前回は制約プログラミングについての簡単な説明と、サンプルプログラムをその通り実行してみたら落ちる...というところまででした。
よく考えたら先走りましたので、少し戻ってインストール方法の説明をしておきます。
Gecode/Rのインストール
私の環境はMac OS X Lion(not 山猫)ですが、おそらくSnow Leopard以降なら同じだと思われます。
ソースコードから自分でビルドするにはGecodeのライブラリを入れて、Gecoder(Gecode/R)を入れるようですが、OSXならGecode/Rのインストールガイドの最初にあるとおりgemで一発です。
gem install gecoder-with-gecode
私はRubyの実行環境のセットアップにrvmを使っているので
$ rvm current ruby-1.9.3-p327 $ gem which gecode /Users/iwazawa/.rvm/gems/ruby-1.9.3-p327/gems/gecoder-with-gecode-1.1.0/lib/gecode.bundle $ gem which gecoder /Users/iwazawa/.rvm/gems/ruby-1.9.3-p327/gems/gecoder-with-gecode-1.1.0/lib/gecoder.rb
こんな感じにインストールされた在処がわかります。
実はGecode,Gecode/Rをソースからビルドっていうのもちょっと試してみたのですが、Gecode 2.2.0のコンパイルがそのままでは失敗するので上記のgemを使った方が良いようです。 最新版に対応できないかなど、またの機会にトライしたいと思います。
ちょっと試してみます。(REPLはpryを使ってます)
$ pry pry(main)> require 'gecoder' => true pry(main)> Gecode.methods(false) => [:load_bindings_lib, :FreeVar, :solve, :maximize, :minimize, :create_model]
インストールされているようです。
なぜ動かなかったか?
前回、サンプルプログラムが動かなかったわけですが、上記のように最新のRubyに入れて試してみたところそうなりました。
せっかちなのでよく見なかったのですが、Featuresの対応バージョンによるとRuby 1.8.6と書かれている orz
残念ながらいささか古いプロダクトで、おそらく更新もされていないという状況と予想されます(´・ω・`)
簡易インストール版、よく入りましたね(汗)
目標は1.9.3で動かす事として、とりあえず1.8.6なら動くのかを確かめて見たテスト。rvmって便利ヽ(´ー`)ノ
サンプルをex00.rbというファイルに保存して実行しています。
$ rvm install 1.8.6 $ rvm use 1.8.6 $ gem install gecoder-with-gecode $ ruby ex00.rb x y z 0 3 3
やはり動きました。ここからが本番。
Ruby 1.9.3でのエラー
Ruby 1.9.3で動かしたときの直接的なエラーはコレでした。
NoMethodError: undefined method `to_i' for :==:Symbol from /Users/iwazawa/.rvm/gems/ruby-1.9.3-p327/gems/gecoder-with-gecode-1.1.0/lib/gecoder/interface/constraints/int_var_constraints.rb:137:in `block in singletonclass'
Symbol:==にto_iメソッドがないと言っています。
問題のコードを見てみると
receiverの特異クラスにメソッドをを定義しようとしてますが、compという変数はGecode::Util::COMPARISON_ALIASESというHashのキーだと分かります。これをto_iしようとしてエラーになってます。このHashは~/.rvm/gems/ruby-1.9.3-p327/gems/gecoder-with-gecode-1.1.0/lib/gecoder/interface/constants.rbに定義されていました。
キーはただのSymbolです。私はRuby歴が比較的短いので推測ですが1.8.6の頃はSymbolのto_iメソッドがID的な整数を返していて、alias_#{comp.to_i}_without_short_circuitはalias_1234_without_short_circuitみたいに定義できていたようです。
$ rvm use 1.8.6 $ ruby -e 'puts :sym.to_i' 10177 $ rvm use 1.9.3-p327 $ ruby -e 'puts :sym.to_i' -e:1:in `': undefined method `to_i' for :sym:Symbol (NoMethodError)
==のような記号をメソッド名として使えないのでそうしているのでしょう。ということはimmutableなオブジェクトに対して不変な値が必要なのだと思われるので、Object#object_idを返すようにSymbolに定義すれば良い気がします。
その通りスクリプトの最初に追記してex01.rbとして保存し実行すると
$ rvm current ruby-1.9.3-p327 $ ruby ex01.rb x y z 0 3 3
実行できた!ヽ(´ー`)ノ
さて、こんな感じでいろいろと直していきたいのでGecode/Rのソースコードリポジトリを探そうと思いますが、今回はここまでとします。
このシリーズ、ここまでで分かるとおり行き当たりばったりにやってますので、寄り道が多くてまどろっこしいでしょうがお時間があれば、今後もお付き合いください(汗)