2009年2月28日土曜日

swig boost_random クリア!

 全部、クリアしました。という訳で、再度、告知します。


 gcc の typeinfo が返すアホな名前ですが、最終的には、std::map<std::string,std::string> によりマッピングを作成しておいて正しい名前に変換するという手法でクリアしました。これなら、どのコンパイラもクリアだと思いたい。

 cmake の TRY_RUN の挙動ですが、コンパイラ・オプションは別途指定しなければならないようです。"-I /usr/local/include/boost_1_38" というような追加情報は、COMPILE_DEFINITIONS に指定しなければなりませんでした。windows 上では環境変数 include に boost も指定していたので windows 上のみ作動していたという訳でした。

追伸:
 ツンデレのお題、俺、体育会系だし、わかんねーよ(Don't think, type. by BRUCE LEE 2nd)。
と思っていたのですが、typeid の返す名前をツンして、
  • gcc : typename コンバータ使ってね
  • msvc : 完璧ね
とデレするパターンを朝に閃きました。でも、こっちに夢中で時間切れとなりますた。

2009年2月27日金曜日

swig boost_random どないせーちゅーねん

 ニュートン法というのをご存知だろうか?解を求めるのに反復しながら近づくというものだ。このニュートン法のように、今日は windows (msvc) と ubuntu (gcc) を何度も往来した。

 まず、cmake の挙動が違う。TRY_RUN が windows 上では、うまく動作するのに、ubuntu 上ではエラーを吐いて止まる。

 次に、gcc_primitive_type_name_hack 中の int の扱いではまる。まさにニュートン法で発散する状況だ。msvc では、long 扱いでないと、boost::random のコンストラクタが動作しないものが出てくる。gcc では、その逆で int 扱いでないと、boost::random のコンストラクタが動作しないものが出てくる。困った事に sizeof(int) == sizeof(long) だ。だ。だ。だ。だ。だだだだだだだだだだだだだ。

 お願いだ、primitive type に関しては、typeinfo は、ちゃんとした名前を返してくれ~

2009年2月26日木曜日

swig boost_random gcc の typeinfo

 えー、ubuntu 上でも動作するようになりました。プリプロセッサだけでなく、gcc の typeid にもやられてました。しょうがないので、こんな関数を作って、お茶を濁すことに…。

const char* gcc_primitive_type_name_hack( size_t primitive_size, bool is_signed, bool is_modulo ) {
// std::cout << typeid( int ).name();
// i
// ... to be haniwa. (O o O)
if( !is_modulo ) {
if( primitive_size == sizeof(double) ) return "double";
else if( primitive_size == sizeof(float) ) return "float";
else if( primitive_size == sizeof(long double) ) return "long double";
} else {
if( is_signed ) {
if( primitive_size == sizeof(char) ) return "char";
else if( primitive_size == sizeof(int) ) return "int";
else if( primitive_size == sizeof(short) ) return "short";
else if( primitive_size == sizeof(long) ) return "long";
else if( primitive_size == sizeof(long long) ) return "long long";
} else {
if( primitive_size == sizeof(char) ) return "unsigned char";
else if( primitive_size == sizeof(int) ) return "unsigned int";
else if( primitive_size == sizeof(short) ) return "unsigned short";
else if( primitive_size == sizeof(long) ) return "unsigned long";
else if( primitive_size == sizeof(long long) ) return "unsigned long long";
}
}
return "unknown";
}

swig boost_random 移植性は難しい

 今度こそ、コンパイルも通るだろ…と思ったら、家の ubuntu 環境では、またもエラーになってしまった。その原因は、型のズレによるもの。よくよく考えたら、random_class_generator.cpp を作成したのは、プラットフォーム間の違いにより生じるソースの違いを動的に吸収しようと思っての事だったので、ubuntu 上でも random_class_generator.cpp からコンパイルして実行する事にした。

 コンパイルしてみると、preprocessor の部分で引っかかった。

BOOST_PP_CAT( "hoge_", BOOST_PP_STRINGIZE(x) ) であるが、x に fuga が渡された時、MSVC では、"hoge_fuga" に展開されるが、gcc では ""hoge_""fuga"" に展開されてしまいエラーになった。MSVC に逆戻りして、チェックしてみないと、なんとも言えないが、正しくは
BOOST_PP_STRINGIZE( BOOST_PP_CAT(hoge_, x) ) とすべきなのだろうか? 'hoge_' は文字通り展開され、'x' は 'fuga' に展開されて ## により結合されるので、心情的に、かなり気持ち悪い。

 今回の教訓。プリプロセッサ、面白かったけど、罠がいっぱい。できるならば使わない方が良い。

 他にも、いろいろと引っかかっている。一筋縄ではいかないもんだ・・・。これは、まだまだ完成しそうにない。

2009年2月25日水曜日

swig boost_random 意味がわからん

 ubuntu 環境でコンパイルしてみたら identifier before ‘&’ token というようなエラーになって、全く意味がわからなかった。
 どうやら、クラスのメンバ関数名に random() という名前を使ったのがお気に召さなかったらしい。include ガードとかも念のために追加して、また、手を加えたらポストします。

swig 欲張りすぎたかも

 とりあえず、active_perl では動作した。しかし、ほとんどテストはしていない。cmake 用の CMakeFiles.txt も適当に書いたので、そのまんまではコンパイルもままならないかもしれない。ここまでやったが、私がこれを使う事は、まず無いだろう(少々のコンバータとかでも、C++で書いちゃいますから~)。そんなわけで、一応、貼っときます。煮るなり、焼くなり、好きにしてください。



  • direct_* は直接呼出し
  • uniform_* は、[0,1) の一様確率
  • exp_* は 指数分布
  • norm_* はガウス分布
  • log_* は対数ガウス分布
となってます。コンパイルには、boost が必要です。

後で、もうちょっと CMakefilesCMakeLists.txt をまじめに書く予定だけど、移り気なので約束が果たされるかどうか…

追記: よく考えたら、余計なメンバを定義していたので無駄にサイズが増えて勿体無いお化けに怒られそう…という事で、ポストしてから、AM3:09には、修正したのをアップし直しました。
更に追記:Ubuntuでコンパイルが通らない。なんで~?

2009年2月24日火曜日

本日は研究会

 本日は、サイバーフィールド研究会。難しい話が多いけど、面白かった。帰りに巡回セールスマン問題の件で相談に行き、GAは捨てて違うアルゴリズムを採用することになった。先行きが楽しみだ。

2009年2月23日月曜日

swig 怪しい経過

 こちらですが、とりあえず、動作させる所までは来ました(手を入れないと動かないです)。しかし、わかった事が2点。これは、かなり怪しい領域に突入してきました。
  1. メンバ配置のバイト・アライメントを考慮に入れなければならない
  2. 仮想継承のサイズを考慮に入れなければならない
 以上をクリアすれば、今の方向性で問題なさそうです。バイト・アライメントなんて、コンパイルする環境によって変わるし、仮想継承のサイズなんて実装依存です。困ったもんだ…。

追記: バイト・アライメントをコード中で取得する方法って、何か無いだろうか? boost::pool でも参考にする?

巡回セールスマン問題を解く(4)

 予測していたように pgRouting の TSP 自明な3点以外でもエラーになる場合があった。しょうがないので、若干負けているが自前のルーチンを使う事にした。それで、厳密に都市間の距離を計算して勝負してみたが、それでも負ける(本当は勝っている、と言っても、こちらだけ厳密な距離を使用しているので、不公平な比較だが…)。
 何故負けるかというと、現在は配送問題も加えており(集荷と出荷の関係を持ち込む)、単純な最短巡回問題では無くなっているからだという結論に達した。出荷条件が整っていない場合に、その都市の順序を先送りするという方式を取っているが、こういう事をする場合には、むしろ不完全な解の方が先送りした結果良い結果を生むという皮肉な事態になっているようだ。
 という事で、都市間距離に加えて、配送問題も取り込む事にする。ブログへのポストは、この辺が潮時か…。

追記:距離の計算において、最終都市から起点都市への距離の追加が漏れていた。これを入れれば、元より勝っていたっぽい。

SPI で insert or update

 よくSQLでは、レコードが存在していれば更新し、存在していなければ挿入したいという事がありますが、それをPostgreSQL SPIで実現するための備忘録。尚、コードはバッファ・オーバーランに関して無考慮なので、そのまま踏襲しないように。


bool record_insert_hoge(
int id,
const char* namae
) {
char buf[ 512 ];
sprintf( buf, "insert into hoge (id, namae) values (%d,'%s');", id, namae );
return (SPI_OK_INSERT == SPI_execute( buf, false, 1 ));
}

bool record_update_hoge(
int id,
const char* namae
) {
char buf[ 512 ];
sprintf( buf, "update hoge set namae='%s' where id=%d returning *;", namae, id );
if( SPI_OK_UPDATE_RETURNING != SPI_execute( buf, false, 1 ) ) {
return false;
}
return (SPI_processed == 1);
}

bool record_insert_or_update_hoge(
int id,
const char* namae
) {
if( !record_update_hoge( id, namae ) ) {
return record_insert_hoge( id, namae );
}
return true;
}

2009年2月22日日曜日

swig 経過

 とりあえず、現在は、こんな感じ…。BOOST_PP_IF( BOOST_PP_EQUAL( ... などとやっていたが、さすがにこれは、やり過ぎでやめた。boost random の引数等が違っていて、さすがにこれは等価には扱いきれなかった。欲を言えば、seed_type とか seed_arg_count とかを定義していて欲しかったかも?

namespace {
char copyright[] =
"";
}

#include <iostream>
#include <typeinfo>
#include <fstream>
#include <boost/preprocessor.hpp>
#include <boost/random.hpp>

#define RANDOM_TYPE_COUNT 16
#define RANDOM_TYPE_ARRAY ( RANDOM_TYPE_COUNT, ( \
minstd_rand, \
rand48, \
ecuyer1988, \
kreutzer1986, \
hellekalek1995, \
mt11213b, \
mt19937, \
lagged_fibonacci607, \
lagged_fibonacci1279, \
lagged_fibonacci2281, \
lagged_fibonacci3217, \
lagged_fibonacci4423, \
lagged_fibonacci9689, \
lagged_fibonacci19937, \
lagged_fibonacci23209, \
lagged_fibonacci44497 \
) )

#define NTH_ecuyer1988 2
#define NTH_lagged_fibonacci607 7

#define INC_OP( r, i ) BOOST_PP_INC(i)
#define PRED( r, i ) BOOST_PP_LESS(i,RANDOM_TYPE_COUNT)

#define NEXT_LINE ofs << "\n";

#define ALGO_CLASS_NAME( x ) BOOST_PP_CAT( "algo_", BOOST_PP_STRINGIZE(x) )

// for random_def.hpp
void print_type( std::ostream& os, const char* class_name, size_t class_size ) {
os << "struct " << class_name << " {" << std::endl;
os << " char pos[" << class_size << "];" << std::endl;
os << "};" << std::endl;
}
#define PRINT_TYPE_X( x ) { \
print_type( ofs, BOOST_PP_STRINGIZE(x), sizeof(x) ); \
NEXT_LINE \
print_type( ofs, BOOST_PP_CAT("valiate_generator_", BOOST_PP_STRINGIZE(x)), sizeof(variate_generator<x,uniform_real<> >) ); \
NEXT_LINE \
}
#define PRINT_TYPE( r, i ) PRINT_TYPE_X( BOOST_PP_ARRAY_ELEM(i,RANDOM_TYPE_ARRAY) )

// for random_retype.hpp
void print_retype( std::ostream& os, const char* base_name ) {
os << "typedef variate_generator< " << base_name << ", uniform_real<> > ";
os << "variate_generator_" << base_name << ";" << std::endl;
}
#define PRINT_RETYPE_X( x ) { \
print_retype( ofs, BOOST_PP_STRINGIZE(x) ); \
NEXT_LINE \
}
#define PRINT_RETYPE( r, i ) PRINT_RETYPE_X( BOOST_PP_ARRAY_ELEM(i,RANDOM_TYPE_ARRAY) )


// for random.hpp
void print_class( std::ostream& os, const char* class_name, const char* result_name, int array_number ) {
os << "class algo_" << class_name << " {" << std::endl;
os << "private:" << std::endl;
os << " " << class_name << " generator_;" << std::endl;
os << " variate_generator_" << class_name << " variator_;" << std::endl;
os << "public:" << std::endl;
os << " algo_" << class_name << "( ";
if( array_number == NTH_ecuyer1988 ) {
os << result_name << " seed1, " << result_name << " seed2);" << std::endl;
} else if( array_number >= NTH_lagged_fibonacci607 ) {
os << ");" << std::endl;
} else {
os << result_name << " seed);" << std::endl;
}
os << " double random();" << std::endl;
os << " " << result_name << " numeric_random();" << std::endl;
os << "};" << std::endl;
}
#define PRINT_CLASS_X( x, i ) { \
print_class( ofs, BOOST_PP_STRINGIZE(x), typeid( x::result_type ).name(), i ); \
NEXT_LINE \
}
#define PRINT_CLASS( r, i ) PRINT_CLASS_X( BOOST_PP_ARRAY_ELEM(i,RANDOM_TYPE_ARRAY), i )

// for random.cpp
void print_implement( std::ostream& os, const char* class_name, const char* result_name, int array_number ) {
os << "///////////////////////////////////////" << std::endl;
os << "// " << class_name << std::endl;
os << "///////////////////////////////////////" << std::endl;
os << class_name << "::" << class_name << "(";
if( array_number == NTH_ecuyer1988 ) {
os << result_name << " seed1, " << result_name << " seed2) :" << std::endl;
os << " generator_(seed1,seed2)," << std::endl;
} else if( array_number >= NTH_lagged_fibonacci607 ) {
os << ") :" << std::endl;
os << " generator_()," << std::endl;
} else {
os << result_name << " seed) :" << std::endl;
os << " generator_(seed)," << std::endl;
}
os << " variator_(generator_,uniform_real<>())" << std::endl;
os << "{}" << std::endl;
os << std::endl;
os << "double " << class_name << "::random() { return variator_(); }" << std::endl;
os << result_name << " " << class_name << "::numeric_random() { return generator_(); }" << std::endl;
os << std::endl;
}
#define PRINT_IMPLEMENT_X( x, i ) { \
print_implement( ofs, ALGO_CLASS_NAME(x), typeid( x::result_type ).name(), i ); \
}
#define PRINT_IMPLEMENT( r, i ) PRINT_IMPLEMENT_X( BOOST_PP_ARRAY_ELEM(i,RANDOM_TYPE_ARRAY), i )

// for random.i
void print_ignore( std::ostream& os, const char* class_name ) {
os << "%ignore " << class_name << "::generator_;" << std::endl;
os << "%ignore " << class_name << "::variator_;" << std::endl;
}
#define PRINT_IGNORE_X( x ) print_ignore( ofs, ALGO_CLASS_NAME(x) );
#define PRINT_IGNORE( r, i ) PRINT_IGNORE_X( BOOST_PP_ARRAY_ELEM(i,RANDOM_TYPE_ARRAY) )

using namespace boost;

void print_random_def() {
std::ofstream ofs( "random_def.hpp" );

ofs << "// random_def.hpp\n";
NEXT_LINE
BOOST_PP_FOR( 0, PRED, INC_OP, PRINT_TYPE )
NEXT_LINE
print_type( ofs, "uniform_base", sizeof(uniform_real<>) );
}

void print_random_retype() {
std::ofstream ofs( "random_retype.hpp" );

ofs << "#include <boost/random.hpp>\n";
ofs << "using namespace boost;\n";
NEXT_LINE
BOOST_PP_FOR( 0, PRED, INC_OP, PRINT_RETYPE )
NEXT_LINE
ofs << "typedef uniform_real<> uniform_base;" << std::endl;

}

void print_random_hpp() {
std::ofstream ofs( "random.hpp" );

ofs << "#ifdef SWIG\n";
ofs << "#include \"random_def.hpp\"\n";
ofs << "#else\n";
ofs << "#include \"random_retype.hpp\"\n";
ofs << "#endif\n";
NEXT_LINE

BOOST_PP_FOR( 0, PRED, INC_OP, PRINT_CLASS )
}

void print_random_cpp() {
std::ofstream ofs( "random.cpp" );

ofs << "#include \"random.hpp\"\n";
NEXT_LINE
BOOST_PP_FOR( 0, PRED, INC_OP, PRINT_IMPLEMENT )
}

void print_random_i() {
std::ofstream ofs( "random.i" );

ofs << "/* File : random.i */\n";
NEXT_LINE
ofs << "%module boost_random\n";
NEXT_LINE
ofs << "%{\n";
ofs << "#include \"random.hpp\"\n";
ofs << "%}\n";
NEXT_LINE
BOOST_PP_FOR( 0, PRED, INC_OP, PRINT_IGNORE )
NEXT_LINE
ofs << "%ignore uniform_base;\n";
NEXT_LINE
ofs << "/* Let's just grab the original header file here */\n";
ofs << "%include \"random.hpp\"\n";
}

int main() {

print_random_def();
print_random_retype();
print_random_hpp();
print_random_cpp();
print_random_i();

return 0;
}

パスワード変更の是非

 日頃から疑問に思っている事を書いてみようと思う。
  1. 3ヶ月に1回パスワードを変更しなさい
  2. パスワードはN文字以上
  3. 英数記号を混ぜよ
  4. IDとパスワードの組み合わせ
  5. HTTPSでやりとりした情報が守られる
以上が現在定着している事項だと思う。
 この中で、2番目の理由は簡単で、ブルート・フォース・アタックからの耐性が上がるからだ。
 3番目の理由もアルファベットのみでパスワードを構成するよりもパスワードを解とすれば、同じパスワード長でも解空間が大きくなるからで、まあ、わからなくもない。しかし、この3番目に関しては攻撃をする方がパスワードはアルファベットしか使っていないと知っている時やアルファベットのみの組み合わせでしか攻撃しない場合にしか効能が無いようにも思える。辞書攻撃を利用された場合に、どこまで効果があるのか極めて疑問で、容易に推測できない組み合わせの文字を利用する事の方が大切ではないかと思う。
 1番目の理由が意味不明で、わからない。3ヶ月に1回変更しないと、パスワードがばれるから変更するのか?パスワードがばれた時に変更すればいいではないか?では、誰かがブルート・フォース・アタックを試みていて、3ヶ月に1回パスワードを変更すれば、既にアタックを受けて攻撃済みのパスワードに推移するから安全とでも言いたいのだろうか?複数人からブルート・フォース・アタックを受けている場合は、一体誰からの攻撃に対する耐性があるというのか?
 ここで5番目の疑問に移ろう。HTTPS通信の記録を全て保持されている場合に、その通信に使われていた暗号方式が簡単に破られるようになったら、その時点で、その通信内容は筒抜けだ。そうすると、こういう場合を想定して、パスワードを定期的に変更するという話であれば納得がいく。それでも、3ヶ月に1回とか、そんな頻度でパスワードを変更しなければならない意味がわからない。
 最後は4番目の疑問。パスワードの解空間を広げたいならば、2つ以上のパスワードを併用してみてはどうなのだろうか?しかし、これは改行文字を導入すれば良いだけなので、そんなに効果的とも言えないようだ。

3D円グラフ

 3D円グラフは、錯覚を起こすので良くないという話が奥村先生のブログに書かれており、一時スラドでも話題になったが、普及している一因は、Google ではなかろうか?
英語サイトもそのようだ。

2009年2月21日土曜日

swig のはずが boost preprocessor

 swig で boost::random をラッピングしたクラスを作ってみようと、あれこれ構想しているうちに、何故か脱線してしまい。boost preprocessor に夢中になってしまった。そもそも、こういう方向性でいいのかどうか7割ぐらいの確信でもって、どんどん突っ走ってしまっていいのだろうか?という一抹の不安もぬぐえない…。が、能天気な性格なのでよしとする。

 プリプロセッサも面白いね。


#include <iostream>
#include <typeinfo>
#include <fstream>
#include <boost/preprocessor.hpp>
#include <boost/random.hpp>

#define RANDOM_TYPE_COUNT 16
#define RANDOM_TYPE_ARRAY ( RANDOM_TYPE_COUNT, ( \
minstd_rand, \
rand48, \
ecuyer1988, \
kreutzer1986, \
hellekalek1995, \
mt11213b, \
mt19937, \
lagged_fibonacci607, \
lagged_fibonacci1279, \
lagged_fibonacci2281, \
lagged_fibonacci3217, \
lagged_fibonacci4423, \
lagged_fibonacci9689, \
lagged_fibonacci19937, \
lagged_fibonacci23209, \
lagged_fibonacci44497 \
) )

#define INC_OP( r, i ) BOOST_PP_INC(i)
#define PRED( r, i ) BOOST_PP_LESS(i,RANDOM_TYPE_COUNT)


#define PRINT_TYPE( r, i ) { \
ofs << "struct " << BOOST_PP_STRINGIZE(BOOST_PP_ARRAY_ELEM(i,RANDOM_TYPE_ARRAY)) << " {\n"; \
ofs << " char pod[" << sizeof(BOOST_PP_ARRAY_ELEM(i,RANDOM_TYPE_ARRAY)) << "];\n"; \
ofs << "};\n" << std::endl; \
ofs << "struct valiate_generator_" << BOOST_PP_STRINGIZE(BOOST_PP_ARRAY_ELEM(i,RANDOM_TYPE_ARRAY)) << " {\n"; \
ofs << " char pod[" << sizeof(variate_generator<BOOST_PP_ARRAY_ELEM(i,RANDOM_TYPE_ARRAY),uniform_real<> >) << "];\n"; \
ofs << "};\n" << std::endl; \
}

#define PRINT_RETYPE( r, i ) { \
ofs << "typedef variate_generator< " << BOOST_PP_STRINGIZE(BOOST_PP_ARRAY_ELEM(i,RANDOM_TYPE_ARRAY)) << ", uniform_real<> >"; \
ofs << " variate_generator_" << BOOST_PP_STRINGIZE(BOOST_PP_ARRAY_ELEM(i,RANDOM_TYPE_ARRAY)) << ";\n"; \
}


#define PRINT_CLASS( r, i ) { \
ofs << "class algo_" << BOOST_PP_STRINGIZE(BOOST_PP_ARRAY_ELEM(i,RANDOM_TYPE_ARRAY)) << " {\n"; \
ofs << "private:\n"; \
ofs << " " << BOOST_PP_STRINGIZE(BOOST_PP_ARRAY_ELEM(i,RANDOM_TYPE_ARRAY)) << " generator_;\n"; \
ofs << " variate_generator_" << BOOST_PP_STRINGIZE(BOOST_PP_ARRAY_ELEM(i,RANDOM_TYPE_ARRAY)) << " variater_;\n"; \
ofs << "public:\n"; \
ofs << " algo_" << BOOST_PP_STRINGIZE(BOOST_PP_ARRAY_ELEM(i,RANDOM_TYPE_ARRAY)) << "( unsigned int32 seed ); \n"; \
ofs << " double random(); \n"; \
ofs << " " << typeid( BOOST_PP_ARRAY_ELEM(i,RANDOM_TYPE_ARRAY)::result_type ).name() << " numric_random();\n"; \
ofs << "};\n" << std::endl; \
}


using namespace boost;

void print_random_def() {
std::ofstream ofs( "random_def.hpp" );

ofs << "// random_def.hpp\n";

BOOST_PP_FOR( 0, PRED, INC_OP, PRINT_TYPE )

ofs << "struct uniform_base {\n";
ofs << " char pod[" << sizeof(uniform_real<>) << "];\n";
ofs << "};\n";

}

void print_random_retype() {
std::ofstream ofs( "random_retype.hpp" );

ofs << "#include <boost/random.hpp>\n";
ofs << "using namespace boost;\n";

BOOST_PP_FOR( 0, PRED, INC_OP, PRINT_RETYPE )

ofs << "typedef uniform_real<> uniform_base;" << std::endl;

}

void print_random_hpp() {
std::ofstream ofs( "random.hpp" );

ofs << "#ifdef SWIG\n";
ofs << "#include \"random_def.hpp\"\n";
ofs << "#else\n";
ofs << "#include \"random_retype.hpp\"\n";
ofs << "#endif\n";
ofs << "\n";

BOOST_PP_FOR( 0, PRED, INC_OP, PRINT_CLASS )
}

int main() {

print_random_def();

print_random_retype();

print_random_hpp();

return 0;
}

2009年2月20日金曜日

巡回セールスマン問題を解く(3)

 今の解法は、都市のノード間を直線距離で計算して、最適解を導くというものなのですが、実際の道路は直線で結ばれているわけなんてないのです。自前で書いたTSPルーチン、悪くは無いと思うのですが、pgRouting の TSPルーチンと比較すると、ことごとく負けてしまいました。直線距離で最適解を導くという勝負においては負けていないと思うのですが(地図上で経路を見て比較しただけで厳密な検証はまだ)、実道路にあてはめてみると pgRouting の TSPの方が良いです。
 こういう部分で、pgRouting の TSPを開発した方の思い入れをなんとなく感じてしまいます。pgRouting のコードは、実計算部分の方をほとんど見ていませんが、プログラマーならではの、ある種の会話をした気分です。
 とは言え、負けは負けで悔しいので、直線距離での計算から、実距離での計算へ方針を転換する事にしました。都市数Nに対して、N×N通りの距離を計算しなければならないですが、ある都市からの最短経路を計算するという事は、結局、他の全都市への最短経路を計算する事でもあります。よって、実距離の計算はN回+α行えば良く、小規模であれば今のコンピュータだと一瞬で終わります。なるべく曖昧な要因は排除できるなら排除した方がいい。これで負けたら諦めもつくってもんです。

2009年2月19日木曜日

MediaWiki-PostgreSQLのアップグレード(結局失敗)

 まだまだネットワーク管理者モードは続くよ。おれマネジメントもしなきゃいけないんですけど…どうすんの?という事で、MediaWikiのアップグレード奮闘記なのだ。

 MediaWikiの方もバックアップを取ってくれないと困る…という話に…まぁ、PostgreSQL からダンプしとけばいいだけの話なんだけどさ…。こいつは Mediawiki-1.10.1 + PostgreSQL 8.1 の構成で、さっさとPostgreSQL 8.3 に上げたいのだ。で、見つけたのがここ。喜び勇んでやったけど、世の中そんなに甘くない。

 環境は、ubuntu上で、apt-get install mediawiki した。

 wikidb-data.sql をインポートする段階で、不正な UTF-8 のコードエラーになった。試行錯誤の上、セキュリィティ対策でコマンドからは UTF-8 のコードが流せないらしい事がわかり、pgAdmin3 から実行するために、データのダンプは

$ pg_dump --host=hoge --username=fuga --password -a -d -n mediawiki wikidb > wikidb-data.sql

とした。それにプラスして、textsearch_ja も入れておく事に…(作業はUbuntu上です)

$ apt-get install mecab
$ apt-get install mecab-ipadic
$ apt-get install libmecab-devel
$ /usr/lib/mecab/mecab-dict-index -d /usr/share/mecab/dic/ipadic -o /var/lib/mecab/dic/ipadic -f euc-jp -t utf-8 -p

で、textsearch_ja の Makefile を一部コメントアウトしました

#ifdef USE_PGXS
PG_CONFIG = pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs)
include $(PGXS)
#else
#subdir = contrib/textsearch_ja
#top_builddir = ../..
#include $(top_builddir)/src/Makefile.global
#include $(top_srcdir)/contrib/contrib-global.mk
#endif

インストールは、make と make install と textsearch_ja.sql を実行するという事で…。
これにプラスして、以下のsqlを事前に実行

CREATE FUNCTION int4text(int4) RETURNS text AS
'SELECT textin(int4out($1));'
LANGUAGE sql STRICT IMMUTABLE;
CREATE CAST (int4 as text)
WITH FUNCTION int4text(int4) AS IMPLICIT;

CREATE FUNCTION mediawiki.rank(tsvector, tsquery, integer)
RETURNS real AS
'SELECT pg_catalog.ts_rank($1,$2,$3);'
LANGUAGE sql;

CREATE TEXT SEARCH CONFIGURATION mediawiki.default
(COPY = pg_catalog.japanese);

これだけやって、ようやくデータの引越しが終わったが、ここからが脱力Showの始まりだ。

php update.php でエラーになるザンス。hasConstraint が無い。あーそうですか… /usr/share/mediawiki/includes/DatabasePostgres.php にリポジトリからもってきて以下の関数を加えればいいんでしょ。

function hasConstraint( $name ) {
global $wgDBmwschema;
$SQL = "SELECT 1 FROM pg_catalog.pg_constraint c, pg_catalog.pg_namespace n WHERE c.connamespace = n.oid AND conname = '" . pg_escape_string( $name ) . "' AND n.nspname = '" . pg_escape_string($wgDBmwschema) ."'";
return $this->numRows($res = $this->doQuery($SQL));
}

しかしだ…しかし…。upgrade DONE... しても、Mediawiki はセットアップ画面になる。こちらを実行してもアップグレードになるので、セットアップを継続してみたが、tsearch2 がインストールされていないと文句をたれる。

あー、わかりましたとも、PostgreSQL8.3 から tsearch2 は標準になったけど、apt-get できるバージョンは、これを考慮していないんですね?ハイハイ、最新のmediawikiをダウンロードして、アップグレードしましょう。

これで、どうだーーーーーー!!!!!!

どうだーーーーー!!!!



インストールに成功しました!!!!やったーーーー!!!

どれどれ、アクセス・・・ん???

Could not determine the numeric version from !

・・・

そして、こんな情報をみつけた。こりゃ、まだまだ時期尚早のようで…。

2009年2月18日水曜日

CentOS yumの設定

 まだまだネットワーク管理者モードは続くのであった…。うきょー。

はじめに


 自前でソースをダウンロードしてコンパイルして…というのは、時間がいくらあっても足りない。何かセキュリィティホールが発見される度に対処されたソースを取得してコンパイルしなければならないからだ。そのためには、どんなセキュリィティホールが発生したのか絶えず最新の情報を漏れなく追いかけなくてはならない。こんな事、専任のネットワーク管理者がいなければ不可能だ。しかも、ライブラリの依存関係にも気を遣わなければならない。ライブラリが根本から覆ると、それに依存しているものは全てコンパイルし直し…という事態を招くかもしれない。こうして、どんどんと時間を費やすことになるだろう。 ながらネットワーク管理者には、とてもそんな時間は取れないし知識も無いので、できる事ならパッケージを流用する方が賢明というものだ。メンテナーの皆様ありがとう。という事で、なるべくパッケージを流用する方針で行こう。

最初にやる事


 初期の状態で yum update を開始すると、恐ろしく時間がかかります。そこで、yum-fastestmirror の導入は必須でしょう。また、方針により yum-updatesd を外し yum-cron を導入するものとします。yum-cron を利用すると無条件に更新されてしまうため動作していたものが動作しなくなるという危険が伴います。考え方により導入しないで手動でメンテナンスするというのも有りです。手をかけたくない人は yum-corn でしょう(注:centos だから成立するのであって fedora では有り得ない選択肢です)。

$ yum remove yum-udpatesd
$ yum install yum-fastestmirror yum-cron

 もうひとつ、いろんなパッケージを導入すると、依存関係に破綻をきたす事があります。そんな破綻を防いでくれるのが yum-protect-packages です。

$ yum install yum-protect-packages

こいつを導入したら、

$ cd /etc/yum.repos.d
$ ls
$ gedit CentOS-Base.repo&

として

[base]
name=CentOS-$releasever - Base
mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=os
#baseurl=http://mirror.centos.org/centos/$releasever/os/$basearch/
gpgcheck=1
gpgkey=http://mirror.centos.org/centos/RPM-GPG-KEY-CentOS-5
protect=1

[updates]
name=CentOS-$releasever - Updates
mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=updates
#baseurl=http://mirror.centos.org/centos/$releasever/updates/$basearch/
gpgcheck=1
gpgkey=http://mirror.centos.org/centos/RPM-GPG-KEY-CentOS-5
protect=1

[addones]
...
protect=0

base, updates セクションに対して protect=1 を追加で設定し、その他のセクションに対しては、protect=0 を追加で設定します。
同様に、他の *.repo ファイルに対しても protect=0 を追加で設定します。
今後、リポジトリを追加した場合には、protect=0 を追加で設定するようにしましょう。

リポジトリを追加


これから2つのリポジトリを追加します。1つは、PostgreSQL で、もうひとつは DAG と呼ばれるものです。

PostgreSQL


CentOS 5.5 から postgresql84 が導入されました。

http://yum.pgsqlrpms.org/reporpms/ から目的のパッケージをダウンロードしてインストールします。


$ wget http://yum.pgsqlrpms.org/reporpms/8.3/pgdg-centos-8.3-5.noarch.rpm
$ rpm -ivh pgdg-centos-8.3-5.noarch.rpm

postgresql はベースのパッケージにも存在するので、リポジトリに対して exclude 指令を加えます。

$ gedit /etc/yum.repos.d/CentOS-Base.repo &

として、以下のように base, updates セクションに exclude を追加します。

[base]
name=CentOS-$releasever - Base
mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=os
#baseurl=http://mirror.centos.org/centos/$releasever/os/$basearch/
gpgcheck=1
gpgkey=http://mirror.centos.org/centos/RPM-GPG-KEY-CentOS-5
exclude=postgresql*
protect=1

[updates]
name=CentOS-$releasever - Updates
mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=updates
#baseurl=http://mirror.centos.org/centos/$releasever/updates/$basearch/
gpgcheck=1
gpgkey=http://mirror.centos.org/centos/RPM-GPG-KEY-CentOS-5
exclude=postgresql*
protect=1

DAG


http://packages.sw.be/rpmforge-release/ から目的のパッケージをダウンロードしてインストールします。尚、CentOS <-> RedHat の関係が成立します。

$ wget http://packages.sw.be/rpmforge-release/rpmforge-release-0.5.1-1.el5.rf.i386.rpm
$ rpm -ivh rpmforge-release-0.5.1-1.el5.rf.i386.rpm

とします。同様に protect=0 の設定を追加しますが、既に設定されているかもしれません。

追記:同じようにインストールを行っても、手順の前後で不整合が生じてうまくいかない場合もあります。

pgdg-83-centos.repo に対して



exclude=libevent

rpmforge.repo に対して


exclude=postgresql*
exclude=pgadmin*

を設定しました。

追記2:なんかエラーになる場合は、以下の呪文を唱えると良いらしいです。


yum clean metadata


追記:2010/07/06 修正

2009年2月17日火曜日

subversion バックアップ構成

 まだまだネットワーク管理者モードは続くのであった…。
Subversionでリポジトリをこしらえたら、バックアップも気になるところです。今回は、バックアップ構成について書くことに…。

 まず、
Z:\> copy con pre-revprop-change.bat
exit 0

として、Ctrl+Z キーを押します。次に、make_new.bat を作成します。
@echo off
@echo "make_new repository_name"
@echo "例: make_new delphi-lib"
if "%1"=="" goto end;
if exist %1 goto already_msg;

svnadmin create %1
copy pre-revprop-change.bat %1\hooks
svnsync init file:///%1 http://your.server/repos/%1

@echo svnsync sync file:///%1 >> do_backup_sync.bat
goto end;

:already_msg

@echo %1 は既に存在します

:end

この場合、リポジトリは、http://yousr.server/repos/ 下にプロジェクト名という形で運用されていると仮定しています。これを、ローカルのプロジェクト名というフォルダにバックアップします。
バックアップは、定期的に do_backup_sync.bat を実行すれば良いです。差分のみ転送してくれます。


 バックアップからの復旧には、
Z:\> svnadmin dump プロジェクト名 > プロジェクト名.dump

として、ファイル化し、
$ svnadmin load プロジェクト名 < プロジェクト名.dump

とすれば良いでしょう。


たまに、ロックされて困った場合には
Z:\ svn propdel svn:sync-lock --revprop -r 0 file:///%1

でオッケー。

2009年2月16日月曜日

パソコンの時間

 家にいてパソコンを開けてると、息子がやってきて「お父さん、Wall-E見たい~」と寄ってきて、「あー目が悪くなるからダメダメ」というと、「見たい~」となって、しまいには、マウスやキーボードを触りだす始末…。よって、普通の時間に何か突っ込んで調べるとか、ブログを書くという選択肢がありません。で、家に帰ったらパソコンをいじれるか?というと、嫁さんがパソコンをいじっている場合があり、そうそうホイホイと使える状況にもありません。
 という訳で、swig くんシリーズは、もうちょい後になりそうです。

CentOS bind の設定

 会社のサーバ、ディスクごと完全に逝ってしまった…。予備機もバックアップ構成も何も無いので、当然バックアップは無い。そもそも人間バックアップを小まめに行うほど暇でもない。自業自得というやつだ。そんなこんなで、ここ数日はネットワーク管理の日々になりそうだ。こんなリソースも割けない。という訳で、DNSの設定もアウトリソースすることに…。

 グローバル用とローカル用の両方を用意する形ですすめます。

インストール


$ yum -y install bind caching-nameserver bind-chroot

として、bind, chching-nameserver, bind-chroot をインストールします

設定


named.conf

named.conf ファイルをコピーします
cp /var/named/chroot/etc/named.caching-nameserver.conf /var/named/chroot/etc/named.conf

named.caching-nameserver.conf よりも named.conf が優先されます。これを行わないで、直接 named.caching-nameserver.conf を変更してしまうと、yum update 時に設定が上書きされる恐れがあります。
$ gedit /var/named/chroot/etc/named.conf &

とし、編集します。
// 使用しませんが、グローバル側を定義
acl corpname {
 221.240.166.240/29;
};

// USEN プロバイダを定義します
// DNS の設定は、プロバイダへ転送できなければなりません。特別扱いします。
acl usennet {
 61.122.116.165;
 61.122.127.154;
 61.122.116.132;
};

options {
// listen-on port 53 { 127.0.0.1; };  // コメントアウト
// listen-on-v6 port 53 { ::1; };     // コメントアウト
 version "unknown";                 // バージョンは表示しない(セキュリィティ対策)
 directory  "/var/named";
 dump-file  "/var/named/data/cache_dump.db";
       statistics-file "/var/named/data/named_stats.txt";
       memstatistics-file "/var/named/data/named_mem_stats.txt";
// 2014/04/16 DNS キャッシュポイズニング攻撃を受けるので、query-source は指定しない
// query-source    port 53; 
// query-source-v6 port 53;         
 allow-query     { any; };     // 問い合わせを許可する基本の設定
 allow-recursion { localhost; localnets; };     // キャッシュを許可する基本の設定
 allow-transfer { any; };      // ゾーン転送を許可する基本の設定
 forwarders { 192.168.1.1; };       // このDNSで解決できない名前を投げる場所(ルータがDNS機能を持っている)
};

controls {
 inet 127.0.0.1 allow { localhost; } keys { rndckey; };
};

include "/etc/rndc.key";

logging {
     category lame-servers { null; };    // 問合せ失敗は記録しない
};

// キャッシュサーバの設定
view localhost_resolver {
 match-clients { localhost; localnets; };
 match-destinations { localhost; localnets; };
 recursion yes;
 include "/etc/named.rfc1912.zones";
 include "/etc/named.yourcorp.co.jp.zone.local";
};

// 内部向け DNS の設定
view "internal" {
 match-clients { localhost; localnets; };
 match-destinations { localhost; localnets; };
 recursion yes;

 include "/etc/named.rfc1912.zones";
 include "/etc/named.yourcorp.co.jp.zone.local";
};

// 外部(公開)向け DNS の設定
view "external" {
 match-clients { any; };   // 誰からもOK
 match-destinations { any; };  // 誰からもOK
 recursion no;  // 再帰は許可しない
 include "/etc/named.yourcorp.co.jp.zone.wan";
};

named.yourcorp.co.jp.zone.local

$ gedit /var/named/chroot/etc/named.yourcorp.co.jp.zone.local &

として、ファイルを編集します。
zone "1.168.192.in-addr.arpa" {
 type master;
 file "1.168.192.in-addr.arpa.db";
};

zone "yourcorp.co.jp" {
 type master;
 file "yourcorp.co.jp.local.db";
};

ローカル・アドレスが 192.168.1.0/24 の場合 1.168.192.in-addr.arpa.db に逆引きを定義します。
ローカルの名前解決は、yourcorp.co.jp.local.db に定義します。
named.yourcorp.co.jp.zone.wan

$ gedit /var/named/chroot/etc/named.yourcorp.co.jp.zone.wan &

として、ファイルを編集します。
zone "yourcorp.co.jp" {
 type master;
 file "yourcorp.co.jp.wan.db";
 allow-update { none; };
 allow-transfer { usennet; };
 allow-query { any; };
};
zone "240/29.166.240.221.in-addr.arpa" {
 type master;
 file "240.166.240.221.in-addr.arpa.db";
 allow-update { none; };
 allow-transfer { usennet; };
 allow-query { any; };
};

上記の場合グローバル・アドレスは、221.240.166.240/29 です。

逆引きゾーンの指定方法は、プロバイダから指定された方法を採用して下さい。

同様にドメインも取得したものを指定します。

allow-transfer で、プロバイダに対して、ゾーン転送を許可します。

allow-query で、外部に対して、問合せを許可します。

ゾーン設定


ゾーン設定ファイルは、バージョン管理されます。

シリアル値を比較して新しい場合だけ、設定が他のDNSサーバへ伝播します。

Serial は YYYYMMDDNN としています。

  • YYYY 西暦
  • MM 月(ゼロサプレス)
  • DD 日(ゼロサプレス)
  • NN 番号 (ゼロサプレス)


CNAME レコードは推奨されなくなりました。
ローカル

$ mkdir /var/named/chroot/var
$ mkdir /var/named/chroot/var/named
$ gedit /var/named/chroot/var/named/1.168.192.in-addr.arpa.db

とします。
$TTL    86400
@       IN      SOA     yourcorp.co.jp.  root.yourcorp.co.jp.(
                                      2009021401 ; Serial
                                      28800      ; Refresh
                                      14400      ; Retry
                                      3600000    ; Expire
                                      86400 )    ; Minimum
@       IN NS    sv.yourcorp.co.jp.
2       IN PTR   sv.yourcorp.co.jp.    ; 192.168.1.2 -> sv.yourcorp.co.jp
3       IN PTR   msv.yourcorp.co.jp.   ; 192.168.1.3 -> msv.yourcorp.co.jp
4       IN PTR   gt.yourcorp.co.jp.
5       IN PTR   gs1.yorucorp.co.jp.
6       IN PTR   gs2.yourcorp.co.jp.

$gedit /var/named/chroot/var/named/yourcorp.co.jp.local.db

とします。
$TTL    86400
@       IN      SOA     sv.yourcorp.co.jp.  root.yourcorp.co.jp.(
                                      2009021401 ; Serial
                                      28800      ; Refresh
                                      14400      ; Retry
                                      3600000    ; Expire
                                      86400 )    ; Minimum
@       IN NS    sv.yourcorp.co.jp.
localhost  IN A  127.0.0.1
        IN MX 10 msv.yourcorp.co.jp.  ; メールサーバ用
@       IN A     192.168.1.2
sv      IN A     192.168.1.2
www     IN A     192.168.1.2
msv     IN A     192.168.1.3
mail    IN A     192.168.1.3
gt      IN A     192.168.1.4
gs1     IN A     192.168.1.5
gs2     IN A     192.168.1.6
yourcorp.co.jp. IN TXT "v=spf1 a mx ~all"  ; SPF レコードです

グローバル

グローバル・アドレスが 211.240.166.240だった場合
$gedit /var/named/chroot/var/named/240.166.240.211.in-addr.arpa.db

とします。
$TTL    86400
@       IN      SOA     sv.yourcorp.co.jp.  root.yourcorp.co.jp.(
                                      2009021401 ; Serial
                                      10800      ; Refresh
                                      3600       ; Retry
                                      604800     ; Expire
                                      86400 )    ; Minimum
       IN NS     sv.yourcorp.co.jp.
       IN NS     uns02.usen.ad.jp.  ; セカンダリ DNS サーバ
; hosts
242     IN PTR    sv.yourcorp.co.jp.
243     IN PTR    msv.yourcorp.co.jp.
244     IN PTR    gt.yourcorp.co.jp.
245     IN PTR    gs1.yourcorp.co.jp.
246     IN PTR    gs2.yourcorp.co.jp.

$gedit /var/named/chroot/named/var/named/yourcorp.co.jp.wan.db

とします。
$TTL    86400
@       IN      SOA     sv.yourcorp.co.jp.  root.yourcorp.co.jp.(
                                      2009021401 ; Serial
                                      10800      ; Refresh
                                      3600       ; Retry
                                      604800     ; Expire
                                      86400 )    ; Minimum
       IN   NS    sv.yourcorp.co.jp.
       IN   NS    uns02.usen.ad.jp.  ; セカンダリ DNS サーバ
; hosts
        IN MX 10 msv.yourcorp.co.jp.
@       IN A     221.240.166.242
sv      IN A     221.240.166.242
www     IN A     221.240.166.242
msv     IN A     221.240.166.243
mail    IN A     221.240.166.243
gt      IN A     221.240.166.244
gs1     IN A     221.240.166.245
gs2     IN A     221.240.166.246
yourcorp.co.jp. IN TXT "v=spf1 a mx ~all"   ; SPF レコードです

IP アドレスのタイプミスには、特に気をつけてください。

追記: 2009/02/17 一部修正
/etc/init.d/bind start にて失敗する場合
$ chgrp named /var/named/chroot/etc/named.conf

とすれば良い。尚、SELinux は enforcing のままで動作する。無闇にdisableする風潮は良くない。

2009年2月14日土曜日

swig ってどうよ?

 ちょい突っ込んでみたが、何も全部をそのまま移植しようとしなくても良かろうに…と思うのである。%ignore により、こいつは無視してくだされ…という指定もできるのだが、ラッパーをかまそうと思ってもできない。これについては、後述する。

 だいたい、ruby のサンプルに template はあるのに、perl のサンプルに template はない。無理矢理移植をしてコンパイルしてみたが、なるほど、コンパイルが通らない。C2061 とか出てて、検索してみたら、2ch にも投稿があり、先駆者の屍が累々としていそうである。だいたい、現行 C++ の template をスクリプトにそのまま展開しようというのは狂気の沙汰であるようにも思える。

 %ignore で無視できるメンバを指定できるのに加えて、#include <hoge.hpp> の中身全てを無視するディレクティブ(指令)が欲しいところである。最終的には、sizeof(無視されたメンバ) さえ取得できれば辻褄が合うのではないかと思う(確信は無い)。

 で、ためしに boost::mt19937 のメンバを char dummy[4]; ぐらいで置き換えて、コンパイルしてみたら、実行時に見事にお亡くなりになる。


#include <boost/random.hpp>
#include <iostream>

int main() {
std::cout << sizeof(boost::mt19937) << std::endl;
return 0;
}


を実行してみると、4996 と表示された…。そんなにデカかったのかよorz...(そりゃそうか)。
気を取り直して、char dummy[4996]; で再度実行すると、うまく動いているような気がする(ただし、表示される数値は unsigned のレンジではなく signed のレンジで怪しさ倍増)。うーん…、swig ってどうよ?

2009年2月13日金曜日

地球温暖化・・・札幌で2月の雨

 今年は完全にイカレテイル。冬になるのが一ヶ月遅れ、春になるのが一ヶ月早くなりそうだ。2月中旬の夜中に降る雨!なんじゃそりゃーーーーーーーー!!!!
 北海道内の湖は、どこも凍らずに大変な事になっています。そして、今年度の冬に、まともにした雪掻きは、たったの2回!!!例年ならば、10回以上は雪掻きしてるちゅーねん。屋根に積もる雪も例年の3分の1以下で少ないちゅーねん。降雪雨量は例年よりも多いらしいのだが、もう気が狂っているとしか思えないレベルです。
 この感覚を夏に適応すると、7月と9月が8月並の暑さになる換算です。すると8月の暑さは、どんな暑さになるのでしょうか?下手をすると水不足と洪水が交互に来て、作物は大打撃を被る…なんて事になりかねない。東京都が地下鉄の浸水シミュレーションをして対策したのは、正解でしょう。オーストラリアと同じく、100年に一度の熱波が常識化しますよ。

swigってみた

 なんとなく swig
どの言語を対象にしても良いけれでも、一応メジャーな Perl にしてみた。今回は windows で、ちょい試してみたので、swig は swigwin-1.3.38 をチョイス。
 cygwin は、どうも好きになれないのと、ActivePerl で swig できるらしいので、ActivePerl 5.10 をダウンロードしてインストール。ここから、ややしばらく悩んだ…。
 swigwin-1.3.38\Examples\perl5\simple のIDEを開いて、コンパイルしてみると、PERL5_INCLUDE, PERL5_LIB の環境変数が設定されていないと怒られ、EXTERN.h とかが無いと言われる。そんなもん、どこにあんねん?とディレクトリを見たが、それらしい所が無い、検索しても、どこにあるといった情報が皆無。ディレクトリを検索してみて、ようやく見つけた。

PERL5_INCLUDE=C:\Perl\lib\CORE
PERL5_LIB=C:\Perl\lib\CORE\perl510.lib

を設定し、コンパイル。OK、うまくいった。

C:\downloads\swigwin-1.3.38\Examples\perl5\simple>perl runme.pl
The gcd of 42 and 105 is 21
Foo = 3
Foo = 3.1415926

ちゃんと動いているようだ。

2009年2月12日木曜日

delphi の行方

 ふと、Delphi ML に Delphi のページが減ってきたとあった。そういえば書籍も、すっかり見かけなくなった。コンポーネントとか、BDEとか、アプリケーションを生成する生産性が高く、TDatabase TTable TQuery TDataSource あたりの考え方は、ExtJs あたりにも受け継がれている気がする。Borland が不振で二転三転したのも大きいけど、時代の変遷についていけなかった感もぬぐえない。
 戦場がウェブやネットになっているのに、今のやり方では厳しいだろうと思う。弊社では、Delphiの資産をたくさん抱えていますが、正直、この先は Delphi がメインプレーヤーではないだろうと個人的には考えてます。Delphiユーザのパワーを Delphi.net に持っていければ形勢は変わるでしょうか?
 いまどきの考え方だと、Restful な DataSource との接続かな?

とびやがった

 会社のウェブサーバ、お亡くなりになりやがった。今日、多分、帰れねー。死ね。

2009年2月10日火曜日

JavaScript 祝日計算

ネタに走る…(^^;



/// 休日の判定(振替休日を考慮)

function getHoliday_ja_JP( date ) {

/// 前日の状態を調べる

function checkBeforeDay( date ) {

var yesterday = new Date();

yesterday.setTime( date.getTime() - 24 * 60 * 60 * 1000 );

var week = yesterday.getDay();

// 前日が祝日の場合、振替休日である可能性がある

if( getPureHoliday_ja_JP( yesterday ) != null ) {

// 祝日が日曜日なので

if( week == 0 ) return '振替休日';

return checkBeforeDay( yesterday );

}

return null;

}

var week = date.getDay();

var holiday = getPureHoliday_ja_JP( date );

if( holiday != null ) return holiday;

if( week == 0 ) return null;

var year = date.getFullYear();

if( year >= 1973 ) {

var holiday = checkBeforeDay( date );

if( holiday != null ) return holiday;

if( year >= 2003 && date.getMonth() == 8 ) {

var yesterday = new Date();

yesterday.setTime( date.getTime() - 24 * 60 * 60 * 1000 );

// 注:敬老の日は、月曜日固定

if( getPureHoliday_ja_JP( yesterday ) == '敬老の日' ) {

var tommorow = new Date();

tommorow.setTime( date.getTime() + 24 * 60 * 60 * 1000 );

if( getPureHoliday_ja_JP( tommorow ) == '秋分の日' ) {

return '国民の祝日';

}

}

}

}

return null;

}



/// 祝日の判定(振替休日を考慮しない)

function getPureHoliday_ja_JP( date ) {

var week = date.getDay();

var year = date.getFullYear();

var day = date.getDate();

switch( date.getMonth() ) {

case 0:

// 元旦

if( day == 1 ) return '元旦';

// 成人の日

if( year >= 2000 ) {

if( week == 1 && 7 < day && day < 15 ) return '成人の日';

} else if( day == 15 ) { return '成人の日'; }

break;

case 1:

// 建国記念日

if( year >= 1967 ) {

if( day == 11 ) return '建国記念日';

}

break;

case 2:

// 春分の日 正確には観測による。下記式は 1980年から2099年の間有効

if( day == (

Math.floor( 20.8431+.242194 * (year -1980.0))

- Math.floor( (year - 1980.0) / 4.0 )

) ) return '春分の日';

break;

case 3:

if( day == 29 ) {

if( year <= 1988 ) return '天皇誕生日';

if( year <= 2006 ) return 'みどりの日';

return '昭和の日';

}

break;

case 4:

if( day == 3 ) return '憲法記念日';

if( day == 5 ) return 'こどもの日';

if( day == 4 ) {

if( year < 1988 ) return null;

if( year <= 2006 ) {

if( week == 0 ) return null;

if( week == 1 ) return null; // 振替休日は祝日としない

return '国民の祝日';

}

//if( year >= 2007 )

return 'みどりの日';

}

break;

case 5:

// for (;_;) oh;

break;

case 6:

// 海の日

if( year >= 2003 ) {

if( week == 1 && 14 < day && day < 22 ) return '海の日';

} else if( day == 20 && year >= 1996) { return '海の日'; }

break;

case 7:

// 盆休み(不定)

break;

case 8:

// 敬老の日

if( year >= 2003 ) {

if( week == 1 && 14 < day && day < 22 ) return '敬老の日';

} else if( day == 15 && year >= 1966 ) { return '敬老の日'; }

// 秋分の日 正確には観測による。下記式は 1980年から2099年の間有効

if( day == (

Math.floor( 23.2488+.242194 * (year -1980.0))

- Math.floor( (year - 1980.0) / 4.0 )

) ) return '秋分の日';

break;

case 9:

// 体育の日

if( year >= 2000 ) {

if( week == 1 && 7 < day && day < 15 ) return '体育の日';

} else if( day == 10 && year >= 1966 ) { return '体育の日'; }

break;

case 10:

// 文化の日・勤労感謝の日

if( day == 3 ) return '文化の日';

if( day == 23 ) return '勤労感謝の日';

break;

case 11:

// 天皇誕生日

if( day == 23 && year >= 1989 ) return '天皇誕生日';

break;

default:

}

return null;

}

ContextFree センスないなぁ

 なかなか思い通りにいかないです。




startshape Hoge

rule Hoge {
50 * { x 15 r 12 } Fuga {}
Hoge { y 8 r 23 s 0.8 sat 5 }
}

rule Fuga {
12 * { x 2 r 30 hue 15 } Leaves {}
}

rule Leaves {
Leaf {}
Leaves { x 5 r 18 z 0.9 s 0.85 }
}

rule Leaf {
CIRCLE { x 5 y 5 r 12 s 2 1 b 1 sat 1 hue 80 }
}





startshape Snow

rule Snow {
6 * { r 60 } Spike {}
}

rule Spike {
40 * { x 0.3 } SQUARE { s 0.3 }
15 * { s 0.3 } Leaf { x 3 s 0.7 }
}

rule Leaf {
Spike { r 60 s 0.98 }
Spike { r -60 s 0.98 }
}

2009年2月9日月曜日

苦手な言語

 プログラマだから、いろんな言語は扱うけれど、白状すると、$マークを使う言語が嫌いです。昔のBASICは異様に難しかった。ちょっと凝った事をしようと思うと、DATA文を使った16進アセンブラで、DSKI$やDSKO$使ってディスクアクセス…そしてBASIC自体が難解。自分にはC,C++の方がよほど簡単で、言語に対する相性のようなものを感じてます。そんなトラウマもあり、$マークを使う言語を見ると、拒絶反応を起こしてしまいます。見ただけで、脳内に「やりたくない」汁が蔓延してしまうのだ。
 そういう意味で、実はperlが大嫌いです。php は C に似ているので、いくらか緩和されるのですが、やはり $マークにはゲンナリします。オブジェクト指向のスクリプト言語は、型がわからないので、何をするためのものか推測が利かないのも大きいです。
 JavaScript も難しいです。インスタンスを継承するという感覚が、もうへんてこりんで、クラスの継承関係というよりもインスタンスの継承関係をイメージしないといけないので、どう設計していいのか悩みマクローリン展開っす。JavaScript の this ポインタも何を指しているのか、時々、わけがわからなくて混乱します。特に後付サクサク関数のthisポインタは不気味すぎます。

結局全部書いちゃった

 pgRouting のTSPも挙動が怪しいので、書き直しちゃいました。書き直したというよりも、全部書いた…なんだけど…。plpgsql で tsp を呼び出すとロールバックされるので、関数を2個に分けて2回呼び出しをするという怪しげな処理も不要になった。たぶん、tsp もどこかを破壊しているのだと思う。
 ここまでやってしまうと、pgRouting なのかどうかもわからなくなってしまった…。付加価値探しの旅にでも出るか?

2009年2月8日日曜日

ContextFree 難しい


 KZRさんのところで見て、面白そうだと思い手を出してみたが、異様に難しい。ドキュメントを読んでみたが、思い通りに動いてくれないのだ…。
 どうにもこうにも、ギブアップしようかと思ったが、悔しいので他に情報源を求めてここに辿りついた。解説がわかりやすくて、有難い。これなら凡人にも理解できる。
 で、解説のとおりにやってみたけど腑に落ちない。


startshape Japan

rule Japan {
//SQUARE { b -1 size 1.5 1 }
Hata { b -1 }
// ここの SQUARE を書く命令と
// 次行の Hata は等価だと思うのだが
// SQUARE に書き換えると、背景は黒に
// なってしまう。しかし、前行も
// SQUARE に統一すると、正常になる。
//SQUARE{ b 1 s 1.49 0.99 }
Hata { b 1 s 0.99 }
//CIRCLE { s 0.5 hue 0 sat 1 b 1 }
Akamaru { s 0.5 }
}

rule Hata {
SQUARE { size 1.5 1 }
}

rule Akamaru {
CIRCLE { hue 0 sat 1 b 1 }
}


で、そのまま解説を踏襲する(^^;



startshape Guru

include japan.cfdg

rule Guru {
Japan {}
Guru { x 1.5 size 0.9 rotate 40 hue 15 }
}

rule Guru 0.1 {
Guru {}
Guru { flip 0.3 }
}

ちょっと楽しいかも…
横で嫁さんが「お仕事?」と聞いてきたので、「いんや頭の体操」と答えたら、「そんな頭の体操は、すぐ頭が痛くなるから絶対にできない」と、切って捨てられた。

2009年2月7日土曜日

小樽雪あかりの路

たまには、こんなエントリーも和めてよいでしょうか?札幌では雪祭りですが、並行して小樽では、こんなお祭りをやっています。


2009年2月5日木曜日

active_scaffold action ボタンの追加

 ネタに走ります…(^^;。
アクションボタンの追加は


config.action_links.add ....


で追加できますが、これにより追加されたボタンのHTML要素には、class 'action' 属性がプレゼントされます。
この 'action' クラス属性は、active_scaffold.js により次の副作用を持ちます。

  • 入れ子のパネルへレンダリングされる


という事なので、部分的にAJAXでパーツを置き換えようと思っても、うまく行きません。そこで、テンプレートを書き換えるしかありません。以下は、_list_header.rhtml を書き換えて、フィルタを切り替える例です。


<% if active_scaffold_config.action_links.any? { |link| link.type == :table } -%>
<div class="actions">
<!-- ここに目的のチェックボックスを作成 -->
<a position="top" class="link">
<input type="checkbox" id="view_past" value="全表示" onclick="view_all_foo()"
<%= 'checked' if(session[:pcomp] == 1) -%> />全表示</a>
<!-- ここまで -->
<% new_params = params_for(:action => :table) %>
<% active_scaffold_config.action_links.each :table do |link| -%>
<% next if controller.respond_to? link.security_method and !controller.send(link.security_method) -%>
<%= render_action_link(link, new_params) -%>
<% end -%>

<%= loading_indicator_tag(:action => :table) %>
</div>
<% end %>
<h2><%= active_scaffold_config.list.user.label %></h2>
<!-- ここからは、フィルタを実行するリクエストを送信 -->
<script type='text/javascript'>
function view_all_foo() {
var elem = document.getElementById( 'view_past' );
if( elem.checked ) {
new Ajax.Updater( 'foos-content', '/foos/set_view_all?scaffold_id=foo&page=1', { asynchronous:true, evalScripts:true } );
} else {
new Ajax.Updater( 'foos-content', '/foos/set_view_new?scaffold_id=foo&page=1', { asynchronous:true, evalScripts:true } );
}
}
</script>
<!-- ここまで -->


これに対して foos_controller.rb では


class FoosController < ApplicationController
layout 'application'
before_filter :authorize
record_select :per_page => 7, :search_on => [:name], :full_text_search => true
active_scaffold :foo do |config|
...
end

def set_view_all
session[:pcomp] = 1
rewrite_list
end

def set_view_new
session[:pcomp] = 0
rewrite_list
end

def conditions_for_collection
if session[:pcomp] == 0
'complete_flag = 0'
end
end

protected
...

def rewrite_list
do_list
render :active_scaffold => 'foos', :partial => 'list'
end

end


としています。尚、フィルタの値は、クッキーによる session[:pcomp] に持たせています。

修正:
一部コードがおかしかったので修正しました。

2009年2月4日水曜日

ハチはなぜ大量死したのか?感想

 蜜蜂が大量失踪する事件について書かれたものであるが、現状に警鐘を鳴らすだけでなく、どのようにすればよいかという道標を提示しています。そういう意味では、本書で十分完結しているように思います。蜜蜂の生態について知らない事がたくさん書いてあります。その中で、働き蜂は生殖機能が無いのに分蜂させないというのは、不老長寿を得た状態で、大量に死滅するのも無理はないと感じました(これについては、本書に引き続き404 Blog not found にて「寿命論」の紹介がされており、当然、そう来るよなーという展開)。

 後書きに「プリオン説はほんとうか?」を書いた福岡伸一先生の解説がありますが、世界に6台しかない粒子分類装置を使って、BSDBSEの原因粒子の大きさを推定できないだろうかと、閃きました。もしBSDBSEがウィルスであるならば、たんぱく質をコロイドのように纏った状態である可能性が高いという話があります。この仮定を推し進めて、ウィルスの大きさを x とし、多様なたんぱく質の大きさを T1, T2, T3, T4,...,Tn とします。単純なモデルでは Ti - x - Tj、或いは Tk - x と結合した粒子が考えられますが、感染力を持った粒子 M の大きさを L(M) = L(x) + L(Ti) + L(Tj) として、感染力を持たない「たんぱく質」 L(T1),..., L(Tn) の組み合わせで Genetic Algorithm を使って推定できないだろうか?というものです。

 私は鳥インフルエンザは、抗生物質を投与する畜産方法が産んだ怪物だと推測しています。そんな中、本書には中国産蜂蜜から炭疽菌に対して使用されるシプロが検出された事実が紹介されています。これは、とても深刻な事で、中国は農・畜産・水産業のやり方を改めないと、中国から死が蔓延していくのではないかと思います。

 我が家では、日本の養蜂家から買った蜂蜜を食べていますが、本書を読んで、普通に手に入る蜂蜜を買っていたら何が入っているか安心できたもんじゃないなと半分ゾッとしました。スーパーで茨城産の干し芋と、中国産の干し芋が並んでいて、値段が倍ぐらい違うけれども、その現状を考え込んでしまうぐらいの衝撃です。

 北海道では、今、蝦夷鹿が増えて問題になっています。もの凄い勢いで増えており、幾寅という所では鹿肉のカツをレシピとして取り入れるほどです。これも蝦夷狼が滅んで生態系が変わったり、地球温暖化の影響だったりするのかもしれません。海ではアザラシが増えて問題になっているそうです。一時は漁獲量が激減した(プロフィールの鵡川で取れる魚)シシャモは、町の取り組みで復活しています。

 とりとめがなくなってしまいましたが、不耕起農業など効率的な農業等の道はあるはずで、情報化社会になり新たなステージの農業が始まるのを期待したいです。

2009年2月1日日曜日

いろいろ悩む

 トラックバックをかけようにも Haloscan (JS-kitに買収された)にて、エラーでトラックバックを撃てない。しかもトラックバックを撃つ作業が恐ろしく面倒くさい。どうすんだよ?これ?やっぱ、Blogger 選択は失敗だな・・・。まじな話 Windows Live にでも引っ越した方がいい気がしてきました。それとも生産消費者の道を突き進む?
 ブログも本来の趣旨から少し路線変更で、まぁ、好きなようにやろうと思います。しかし、そうは言っても、何を書くべきなのか悩みます。
 ここんところ、遊びの方の師匠のブログからの流入が多いけど、テーマが激しく異なるので、こちらの方の直帰率も高い(C++のコード見たらやっぱ引くだろう)。とは言え、どちらかと言うと、本業のソフトウェ開発の話をメインに書いた方が発信力も高いような気がするので、そうした方が良い気もします。ところが、ここんところコーディングする機会が続いているので発信できるけど、そうでなければ時間を割いてテーマを決めてやらないと、それもできそうにないです。
 今日の夕食は、増毛産の甘エビ 298 円を家族3人で、甘エビ丼+甘エビの出汁の味噌汁で、おいしかったのだ…。といった発信をした方が面白いのかも?とか、
 変な話題だと、息子のクリスマス・プレゼントに嫁さんが買ったレスキューフォースのバーコード・リーダが全く反応しなくて、不良品だと思ってビックカメラに持っていったら、元々、反応しにくく、こういうおもちゃだから、文句はタカラトミーに言ってくれと、突っ返されたのとか(そんなもん売るなよ)、雑誌テレビくんの紙で作る付録(仮面ライダー・ディケイド)は凄すぎるだろ…とか、
 ネットワーク管理系の話だと、Ubuntu で UPS を設置して、ネットワークでシェアする apcupsd の設定方法とか、日本語スパムも中国や東南アジアのIPからの発信が結構あるねーとか、
 地球温暖化で、今年の夏は多分、日本でも100年に1度の猛暑で、ひどい事になりそうだと直感した事とか、
 札幌にできた「ジュンク堂」に行ったら、紀伊国屋よりも専門書の品揃えが凄くて興奮したとか、「ハチはなぜ大量死したのか?」という本(404 Blog not found で知りました。今回は、書店で入手しました。すみません)を閉店する旭屋書店で買って、読んで、いろいろと思うところがあった事とか、
 GIGAZINE で3次元円グラフを使ってるのは釣りかな?(確かに、割合が違って見える)とか(もうちょっと解説しないと伝わらないか?)、フィッシング情報ならここにあるかもとか、
 ん・・・何に焦点をあてていけばと、悩みながら、ぼやくって事で、いいのか…。次回は、「ハチはなぜ大量死したのか?」について、読んで思ったところを書こうと思います。