集合知プログラミング 5.1 5.2 5.3 最適化
- 作者: Toby Segaran,當山仁健,鴨澤眞夫
- 出版社/メーカー: オライリージャパン
- 発売日: 2008/07/25
- メディア: 大型本
- 購入: 91人 クリック: 2,220回
- この商品を含むブログ (275件) を見る
今回もサンプルコード(python)から、Rubyへの書き換えに挑戦しました。
目標は一応サンプルコードに忠実にです。
5章の5.1から5.3までの、コスト関数の所までを書いてみました。
出版社から配布されているサンプルコードに間違いがいくつかあり苦労しました。
サンプルコードの正誤
PCI_Code\PCI_Code Folder\chapter5\optimization.pyの32,33行目
# サンプルコードのコード out=flights[(origin,destination)][int(r[d])] ret=flights[(destination,origin)][int(r[d+1])] # 正しいコード # *2を忘れている out=flights[(origin,destination)][int(r[d*2])] ret=flights[(destination,origin)][int(r[d*2+1])]
この後も、同じような箇所がいくつかあり、すべて書き換えます。
その他には69行目の演算子が逆でした。
まだまだ、間違っている所はあると思います。
ちなみに、本には正しいコードで書かれています。
ですので、サンプルコードをそのまま実行せず、本の通りに修正すれば問題ないです。
今回作成したプログラム
今回もいつもの通り、"optimization.rb"と名付けました。
フライトデータファイルはここのものを利用します。
#!/usr/bin/ruby require 'date' require 'time' $people = [ ['Seymour', 'BOS'], ['Franny','DAL'], ['Zooey','CAK'], ['Walt','MIA'], ['Buddy','ORD'], ['Les','OMA'] ] # ニューヨークのラガーディア空港 $destination='LGA' $flights=[] # テキストファイルから配列に格納 ifh = open('schedule.txt', 'r') lines = ifh.readlines for line in lines do line_sp=line.strip().split(/\s*,\s*/) $flights << [ line_sp[0], line_sp[1], line_sp[2], line_sp[3], line_sp[4].to_i ] end module Optimization # 時刻を分に直す関数 def self.getminutes(t) # 文字列から日付オブジェクトに変換 x = Time.parse(t) return x.hour * 60 + x.min end def self.printschedule(r) # 人数を割り出す ran_r = r.length / 2 d = 0 ran_r.times {|d| # 名前を取り出す name = $people[d][0] # 出発地を取り出す origin = $people[d][1] # 配列から行きの便を取り出す out_list = $flights.select{ |f| f[0] == origin && f[1] == $destination } out = out_list[r[d*2]] # 配列から帰りの便を取り出す ret_list = $flights.select{ |f| f[0] == $destination && f[1] == origin } ret = ret_list[r[d*2+1]] print name, " ", origin, " ", out[2], "-", out[3], " ", "$", out[4], " ", ret[2], "-", ret[3], " ", "$", ret[4], "\n" } end #コスト関数 def self.schedulecost(sol) totalprice=0 latestarrival=0 earliestdep=24*60 sol_r = sol.length / 2 sol_r.times {|d| # 行きと帰りのフライトを得る origin = $people[d][1] # 配列から行きの便を取り出す outbound_list = $flights.select{ |f| f[0] == origin && f[1] == $destination } outbound = outbound_list[sol[d*2]] # 配列から帰りの便を取り出す returnf_list = $flights.select{ |f| f[0] == $destination && f[1] == origin } returnf = returnf_list[sol[d*2+1]] # 運賃総額Total price は出立便と帰宅便すべての運賃 totalprice+=outbound[4] totalprice+=returnf[4] # 最も遅い便と最も早い便を記録 if latestarrival<getminutes(outbound[3]) latestarrival=getminutes(outbound[3]) end if earliestdep>getminutes(returnf[2]) earliestdep=getminutes(returnf[2]) end } # 最後の人が到着するまで全員で待機 # 帰りも空港にみんなで来て自分の便を待つ totalwait=0 sol_r.times {|d| # 行きと帰りのフライトを得る origin = $people[d][1] # 配列から行きの便を取り出す outbound_list = $flights.select{ |f| f[0] == origin && f[1] == $destination } outbound = outbound_list[sol[d*2]] # 配列から帰りの便を取り出す returnf_list = $flights.select{ |f| f[0] == $destination && f[1] == origin } returnf = returnf_list[sol[d*2+1]] # それぞれ待ち時間を足し合わせて、総待ち時間を算出する totalwait+=latestarrival - getminutes(outbound[3]) totalwait+=getminutes(returnf[2]) - earliestdep } # レンタカーの追加料金が必要なら50ドル追加 if latestarrival<earliestdep totalprice+=50 end return totalprice+totalwait end end
確認
irbで確認
irb(main):001:0> load 'optimization.rb' => true irb(main):002:0> s=[1,4,3,2,7,3,6,3,2,4,5,3] => [1, 4, 3, 2, 7, 3, 6, 3, 2, 4, 5, 3] irb(main):003:0> Optimization.schedulecost(s) => 4585 irb(main):004:0> Optimization.printschedule(s) Seymour BOS 8:04-10:11 $95 12:08-14:05 $142 Franny DAL 10:30-14:57 $290 9:49-13:51 $229 Zooey CAK 17:08-19:08 $262 10:32-13:16 $139 Walt MIA 15:34-18:11 $326 11:08-14:38 $262 Buddy ORD 9:42-11:32 $169 12:08-14:47 $231 Les OMA 13:37-15:08 $250 11:07-13:24 $171 => 6
補足
getminutes関数
ある時刻が一日の中で何分目かを出す関数です。
時間計算をしたいので、引数で入ってきた文字列を日付オブジェクトに変換します。
strptimeがうまく使えず、今回はTime.parseを使いました。
しかし、もっといい方法がないかなと思っています。
メンバー毎のフライトの割り出し
Integerクラスのtimesメソッドを用いました。
これはブロック内を指定回数だけ実行します。
カウンタも使うことができます。
「初めてのRuby」では6.3.6イテレータで紹介されています。
- 作者: Yugui
- 出版社/メーカー: オライリージャパン
- 発売日: 2008/06/26
- メディア: 大型本
- 購入: 27人 クリック: 644回
- この商品を含むブログ (251件) を見る
この処理は同じような所が何回も出てくるので、関数でまとめてもよかったかもしれません。
結果の出力(printメソッド)
サンプルコードでは、文字列整形して出力していたのですが
自分ではうまくいかず不格好な感じになってしまいました。
Yahoo!ブリーフケースの有料化とYahoo!プレミアムの値上げ
Yahoo!ブリーフケース、Yahoo!プレミアム会員/Yahoo! BB会員 専用サービス化のお知らせ
http://info.photos.yahoo.co.jp/briefcase/index.html
12月1日より、Yahoo!プレミアム会員/Yahoo! BB会員専用サービスになるとのこと。
それに伴い、Yahoo!プレミアムの値段は294円から364円になるそうです。
特典も楽しみも大幅アップ Yahoo!プレミアムが12月1日に生まれ変わります! - Yahoo!プレミアム:
http://premium.yahoo.co.jp/info/powerup.html
いくつかサービスもリニューアルされるらしいので、それに期待するとしましょう。
Rubyのコーディングスタイルについて
あとからコードを見直す時、きれいに整形されていた方が、言うまでもなく理解が早いです。
前回の規約に続き、今回はさらにコーディングスタイルに絞って参考になったページを羅列します。
Ruby and Rails Style Guide
http://www.pathf.com/blogs/ruby-and-rails-style-guide/
ここが一番良かったです。
以下内容の抜粋紹介です。
if文の例
だいたいここに書いてある感じでコーディングしていましたが、if文ここまで短くかけるとは思いませんでした。
逆に驚きでした。
# 良い例 if active? x = 3 else x = 5 end # 悪い例 # しかしこういう感じでも書ける x = active? ? 3 : 5 x = if active? then 3 else 5 end
長いコードの場合
ついつい、悪い例のように書いてしまうことが多いです。
他にも長い命令のインデントとかは、結構我流でやってしまっていた所があったので参考になりました。
# 悪い例 x = if a_really_long_boolean_function then a_long_true_value else a_long_false_value end # 良い例 x = if a_really_long_boolean_function a_long_true_value else a_long_false_value end
あとは演算子の間はスペースの事や、Railsのコーディングスタイルについても書いてありました。
あとは日本語で参考になったところ。
Ruby のコーディングスタイル
http://i.loveruby.net/ja/ruby/codingstyle.html
Rubyの記事ではないですが。
コーディングスタイルの常識をぶち壊せ
http://codezine.jp/article/detail/3055
ここらを参考にして、今後は見やすいコードを書いていきたいと思います。
Ruby1.9のインストールとそのgemを動かすまで(Windows)
今回は、ruby1.9のWindowsへのインストールについてです。
約1年前に書いた記事(d:id:ky2009:20071016:1192542741)では、One-Click Installerを使いました。
1.9系では、gemが標準装備になったので、これを使う必要はありません。
また当たり前ですが、1.9系は配布されていません。
ruby本体のダウンロード
1.9はまだ開発版という位置づけらしいので、安定版(1.8系)を求められる方はOne-Click Installerでいいと思います。
この日記を書いた時点では、1.9.1はまだ不安定らしので1.9.0の最新版をダウンロードしました。
http://www.garbagecollect.jp/ruby/mswin32/ja/
http://www.garbagecollect.jp/ruby/mswin32/ja/download/develop.html
今回は「ruby-1.9.0-2-i386-mswin32.zip」をダウンロードしました。
これを解凍し、フォルダ名を「ruby」にします。
そして「C:\ruby」に置きました。
以後はこのフォルダ構造で説明します。
gemを使うまで
次にgemの動作を確認してみます。
gem -v
これが動きませんでした。
「zlib.dll」がないと言われました。
zlibの入手
zlib.dllのダウンロード
http://www.rubylife.jp/railsinstall/rubygems/index3.html
このページによると、http://www.zlib.net/からダウンロードできました。
ダウンロードしたものは、「zlib1.dll」なので「zlib.dll」にリネームし、「C:\ruby\bin」に置きます。
これでコマンドが通りましたが、「gem update」をしてみると以下のようなエラーがでました。
libeay32.dll、ssleay32.dllの入手
これは、足りないと言われたものを順番に入れていくしかないようです。
OpenSSL for Windows
http://www.limber.jp/?Software%2FOpenSSL%20for%20Windows
ここによると、「ssleay32.dll」はwindowsでopensslをするのに必要なようです。
libeay32.dll、ssleay32.dllのダウンロード
http://d.hatena.ne.jp/troopergreen/20071109/1194586892
こちらで簡単な入手方法が説明されていました。
ここに書かれているように、一緒に「libeay32.dll」も入れておきます。
ここの「openssl-0.9.〜」のファイルをダウンロードして、同じようにbinに入れます。
これでやっとupdateもできました。
最初から入れて配布してくれないのでしょうか。
あと、One-Click Installerのgemの動作もなんとなくあやしい。
いつも環境作りは一筋縄ではいきません。
Rubyコーディング規約のまとめ
命名規則や演算子を忘れてしまった時に、よくこれらのページを見ます。
他にもインデントや条件規則の記述のしかたなど、簡潔にまとめられています。
カンニング以外にも、他言語習得者ならこういうのを見た方が便利かもしれません。
まつもとさんも参照しているもの。
一番標準なのでしょうか。
最終更新が2007年です。
那由多屋版Rubyコーディング標準
http://labs.nayutaya.jp/?ruby-coding-standards
Stack Stock Booksなどのサービスを提供しているnayutayaで定義されたもの。
同じく2007年です。
RubyCodingStyle
http://www.loveruby.net/w/RubyCodingStyle.html
少し古めですが2005年に作成されたものです。
Ruby Language Coding Rule
http://lab.lowreal.net/trac/wiki/CodingRule/Ruby
こうしてみると、組織や団体によって微妙にちがうことがわかりました。
多人数で開発する場合は、しっかりとルールを決めておくべきなんですね。
追記11/26
VB,C,Javaなどのコメント規約
コメントでいただいたものです。
いわゆるコメントアウトについての規約です。
他言語でも結構参考になりそうです。
〜 コメント規約(コーディング規約) 〜
ドキュメント自動生成ツール【A HotDocument】
http://www.hotdocument.net/faq/man.html
restful_authenticationの導入
restful_authenticationとは、Rails用のユーザ認証プラグインのことです。
Rails2.0以降は、このプラグインが大勢のようです。
今後、少し使いそうだったので、試してみました。
- 作者: 高橋征義,諸橋恭介
- 出版社/メーカー: ソフトバンククリエイティブ
- 発売日: 2008/05/31
- メディア: 単行本
- 購入: 37人 クリック: 567回
- この商品を含むブログ (95件) を見る
Railsレシピ本では、153項で紹介されています。
でも、正直そこでは中途半端にしか紹介されていなかったので、他に調べてみました。
プラグインのインストール
プラグインはアプリケーションごとに導入します。
導入したいアプリケーションのルートディレクトリで以下を実行
$ruby script/plugin install http://svn.techno-weenie.net/projects/plugins/restful_authentication/
認証用のコントローラやライブラリを生成
$ruby script/generate authenticated user sessions
テーブルの用意
ユーザ情報を格納するテーブルを作ります。
$ruby rake db:migrate
ルーティングの設定
ログイン・ログアウトなどを手軽に使えるよう、config/routes.rbを編集します。
ActionController::Routing::Routes.draw do |map| #以下5行を追加 map.resources :users map.resource :session map.signup '/signup', :controller => 'users', :action => 'new' map.login '/login', :controller => 'sessions', :action => 'new' map.logout '/logout', :controller => 'sessions', :action => 'destroy' end
ここまでは、レシピ本にも載っています。
ちなみに、このルーティングで、それぞれのURLは例えば以下のようになります。
ユーザ登録 | http://localhost:3000/signup |
ログイン | http://localhost:3000/login |
ログアウト | http://localhost:3000/logout |
コントローラの設定
次に、認証機能をコントローラ全体に適用させます。
まず、「app/controllers/session_controller.rb」と「app/controllers/users_controller.rb」にある「include AuthenticatedSystem」の行をカットまたはコメントアウトします。両方とも削らないとうまくいきませんでした。
class UsersController < ApplicationController # Be sure to include AuthenticationSystem in Application Controller instead include AuthenticatedSystem
class SessionsController < ApplicationController # Be sure to include AuthenticationSystem in Application Controller instead include AuthenticatedSystem
そして、そのコードを「app/controllers/application_controller.rb」に追加します。
class ApplicationController < ActionController::Base # include AuthenticatedSystemのコードを追加 include AuthenticatedSystem
これで認証機能を、アプリケーション全体で使うことができます。
詳しくは下の所などで紹介されていました。
restful_authentication
http://rektunpe.sakura.ne.jp/diary/?date=20071222restful_authenticationを触ってみた
http://d.hatena.ne.jp/idesaku/20080430/1209579996restful_authenticationプラグイン
http://d.hatena.ne.jp/tsimo/20080323/1206277929#c
認証のフィルタの設定
最後に認証が必要なコントローラに、アクションにアクセスする前に認証するように設定します。
例として、app/controllers/hoge_controller.rbに設定をします。
class HogeController < ApplicationController # before_filter :login_requiredのコードを追加 before_filter :login_required
これでこのアクションのページを見る前に認証が必要になります。
一応全部のコントローラに加えておくといいと思います。
このように認証機能の核はできましたが、実用にはもう少しカスタマイズする必要がありそうです。
発展的な使い方
自分のためにもここにメモしておきます。
余裕があれば、ここまで実装してみたいです。
railsforumのrestful_authenticationは素晴らしい!それを見てRESTfulの理解も深まる
http://d.hatena.ne.jp/zariganitosh/20080803/1217836912
以下のような機能が紹介されています。
同じくメールによるアクティベーションについて
Restful Authentication with rails 2
http://www.avnetlabs.com/rails/restful-authentication-with-rails-2restful authentication plugin
http://d.hatena.ne.jp/cuspos/20080725
結局RESTfulが何なのかわかりませんでした。聞いたことはあったのですが。
時間があれば、勉強してみたいです。
「はてなブックマーク」新バージョンが11月に公開
はてなブックマーク、新バージョンの公開日決定!
http://hatena.g.hatena.ne.jp/hatenamagazine/20081002
はてブが11月25日にリニューアルするそうです。
前の日記(d:id:ky2009:20080912:1221207741)に書いたように
ぜひインポート機能を実装していただきたいです。