読者です 読者をやめる 読者になる 読者になる

おさかなせいざ

プログラミングメモや日記がわりに

謀ったな NVIDIA !!!

やられた

お昼前のことです。Arch linuxX11が起動しても一瞬で止まり、画面が動かず、うんともすんとも言わなくなりました。

続きを読む

セールスマン問題を遺伝的アルゴリズムで解いてみた

セールスマン問題

 セールスマン問題はWikipediaに説明があるのでそちらを見ていただければと思います。
巡回セールスマン問題 - Wikipedia
いくつかの都市を少ないコストで周るにはどの順番でいけばよいか、という問題です。人がやるよりプログラムにやらせたほうが楽そうです。

遺伝的アルゴリズム

 今もよくわかっていません。生き物の進化を参考にして、いい個体といい個体を混ぜて新しい個体を作り、たまに突然変異で中身変えてより良い個体を作ろう、みたいなのが遺伝的アルゴリズムの大まかな認識です。 人が頑張って考えんでもプログラムが勝手に色々試行錯誤してくれるとか最高やん。遺伝的アルゴリズムを使ってなんか解きてぇと考え、セールスマン問題を見つけました。
 こういった内容の記事はたくさんありますが、せっかく解いたので載せてみます。言語はClojureです。

書く

 書いたソースコードを示します。

セールスマン問題をといてみた

 英語がさっぱりなので Google 翻訳を頼りに関数名つけてるけど、めんどくさいです。圧倒的英語力がほしい。
 都市の数は20(要素の数も同様)、1世代100体を1000世代行いました。 都市間の距離は固定するためにそのままリストとして埋めました。 コストが最も少なくなるものを求めます。選択方式はルーレット方式が良さそうだったのでこれに決めました。 突然変異、交叉の確率についてはいくつか試してこれくらいがいい結果を速く得られたので、特に値に理由はありません。(交叉は9割程度がよいと書いてあったところもあったのですが、あまり良い結果を得られませんでした) 実行毎に結果は変わりますが、大体最初は Cost: 50000 くらいから始まっていました。

実行

 最も良かった結果としては

$ lein run
problem: (2138 1198 2667 8293 644 2644 9025 7551 2313 200 1176 501 1364 3016 525 4364 1576 6120 2672 4621 5656 6575 352 5682 6825 6858 1607 2881 3879 3760 424 2627 2055 7930 2642 97 4653 9971 2097 5441 4536 3917 710 195 405 7861 1482 5260 58 4534 5229 696 1711 1696 278 5341 4892 3356 9323 1288 4441 8054 9194 4144 4698 9673 7337 5133 6095 9610 3524 5142 3050 6517 6484 4033 319 1267 2949 751 4784 340 952 1083 1013 387 134 249 1874 368 9259 6963 9 5394 5200 4081 2004 8132 8228 8474 4734 9493 5628 9426 2566 197 9341 479 4821 8767 3667 4413 5249 9557 5846 4856 9110 6405 5826 848 8933 3772 1401 2623 6982 7329 1519 7881 1075 276 3602 7835 470 9977 414 1444 283 1931 8191 4425 6096 4485 589 6870 5281 8295 2284 9578 7887 9042 2033 4587 7949 623 7421 9818 5490 8671 2585 1229 640 1111 5785 8392 3857 3187 5869 1094 464 9391 5375 5128 3439 3601 3306 5301 5746 1784 2485 2367 2325 8722 4754 8540 2342 1308 2295 3124 4279 6214 4874 5791 6 8973 887 96 9121 4863 4767 3908 1518 9347 4525 6652 4397 7324 968 5432 9755 5909)
第 0 世代
DNA:  [14 18 7 4 17 6 12 8 1 16 15 19 9 3 13 5 10 2 0 11] 
Cost:  55250 

第 2 世代
DNA:  (14 18 4 10 9 6 1 12 17 16 2 7 13 3 19 8 5 15 0 11) 
Cost:  49160 

第 10 世代
DNA:  (14 18 4 10 9 6 17 12 1 16 5 8 13 3 19 7 2 15 0 11) 
Cost:  39874 

第 14 世代
DNA:  (14 18 4 10 9 6 7 12 19 16 2 8 13 3 17 1 5 0 15 11) 
Cost:  38202 

第 29 世代
DNA:  (14 18 4 10 9 6 7 12 19 3 2 8 13 16 17 1 5 0 15 11) 
Cost:  33456 

第 35 世代
DNA:  (14 18 4 10 9 6 7 12 13 16 2 8 19 3 17 1 5 0 15 11) 
Cost:  33019 

第 37 世代
DNA:  (14 18 4 1 9 6 7 12 19 3 2 8 13 16 17 10 5 0 15 11) 
Cost:  31189 

第 43 世代
DNA:  (14 18 4 1 9 6 2 12 19 3 7 8 13 16 17 10 5 0 15 11) 
Cost:  28580 

第 66 世代
DNA:  (14 18 4 1 9 6 2 12 19 3 7 8 13 17 16 10 5 0 15 11) 
Cost:  27075 

第 69 世代
DNA:  (14 18 4 1 9 6 2 12 19 3 7 8 13 17 10 16 5 0 15 11) 
Cost:  26202 

第 157 世代
DNA:  (14 18 4 1 9 6 2 12 19 3 7 8 13 17 10 0 5 16 15 11) 
Cost:  25333 

第 196 世代
DNA:  (14 18 4 1 9 6 2 12 19 3 7 8 13 17 10 16 15 0 5 11) 
Cost:  25181 

第 221 世代
DNA:  (14 18 7 8 9 6 2 12 19 3 4 1 13 17 10 0 5 16 15 11) 
Cost:  24208 

第 230 世代
DNA:  (14 18 7 8 9 6 2 12 19 3 4 1 13 17 10 16 15 0 5 11) 
Cost:  24056 

第 252 世代
DNA:  (14 18 7 6 9 8 2 12 19 3 4 1 13 17 10 0 5 16 15 11) 
Cost:  23252 

第 270 世代
DNA:  (14 18 7 6 9 8 2 12 19 3 4 1 13 17 10 16 15 0 5 11) 
Cost:  23100 

第 296 世代
DNA:  (14 18 7 6 9 8 2 12 19 3 4 13 1 17 10 16 15 0 5 11) 
Cost:  22489 

第 330 世代
DNA:  (14 18 7 6 9 8 5 12 19 3 4 13 1 17 10 0 2 16 15 11) 
Cost:  21722 

第 455 世代
DNA:  (14 18 7 6 9 8 5 12 19 3 4 13 17 1 0 10 2 16 15 11) 
Cost:  21714 

第 471 世代
DNA:  (14 18 7 6 9 8 5 12 19 3 4 13 1 17 2 0 10 16 15 11) 
Cost:  21236 

第 525 世代
DNA:  (14 18 7 6 9 8 5 0 19 3 4 13 1 17 12 2 10 16 15 11) 
Cost:  21154 

第 536 世代
DNA:  (14 18 7 6 9 8 5 0 19 3 4 13 1 17 10 2 12 16 15 11) 
Cost:  20924 

第 572 世代
DNA:  (14 18 7 6 9 0 5 8 19 3 4 13 1 17 10 2 12 16 15 11) 
Cost:  20684 

第 587 世代
DNA:  (14 18 7 6 3 0 5 8 19 9 4 13 1 17 10 2 12 16 15 11) 
Cost:  19013 

第 608 世代
DNA:  (14 18 7 6 3 0 5 8 9 19 4 13 1 17 10 2 12 16 15 11) 
Cost:  17819 

第 623 世代
DNA:  (14 18 7 6 3 0 5 8 9 19 4 13 1 17 10 16 12 2 15 11) 
Cost:  17577 

第 642 世代
DNA:  (14 18 7 6 3 0 5 8 9 19 13 4 1 17 10 16 12 2 15 11) 
Cost:  16552 

第 707 世代
DNA:  (14 18 7 6 3 0 5 8 9 19 13 17 1 4 10 16 12 2 15 11) 
Cost:  16548 

第 731 世代
DNA:  (14 18 7 6 3 0 5 8 9 19 4 13 17 1 12 2 10 16 15 11) 
Cost:  14669 

FINISH

となりました。一番最初はランダムですが最終的にその1/4程度になるのはすごい。 ちゃんと値が1対1で対応して交換されていて(交叉したものが残って、あとの世代で突然変異しているものもあります)、交叉、突然変異しているのが目に見て取れます。

すごいけどもしかして…

 たしかにすごいけど、これってランダムで同じくらいの時間まわしたらもっといい結果を得られるんじゃ…?
ということで試してみました。気づいた方もおられると思いますが、ソースコードの(cond (< prob 0) ~となってる部分がランダムの確率の部分です(このままではランダムにはならない)。これを(< prob 1)に変更するとすべてランダムに次世代を生成します。 一世代は同じく100体で、遺伝的アルゴリズムと時間が同じくらいになるよう10000世代にしました。 こちらも何度か試し、最もよかった結果は以下のようになりました。

$ lein run
problem: (2138 1198 2667 8293 644 2644 9025 7551 2313 200 1176 501 1364 3016 525 4364 1576 6120 2672 4621 5656 6575 352 5682 6825 6858 1607 2881 3879 3760 424 2627 2055 7930 2642 97 4653 9971 2097 5441 4536 3917 710 195 405 7861 1482 5260 58 4534 5229 696 1711 1696 278 5341 4892 3356 9323 1288 4441 8054 9194 4144 4698 9673 7337 5133 6095 9610 3524 5142 3050 6517 6484 4033 319 1267 2949 751 4784 340 952 1083 1013 387 134 249 1874 368 9259 6963 9 5394 5200 4081 2004 8132 8228 8474 4734 9493 5628 9426 2566 197 9341 479 4821 8767 3667 4413 5249 9557 5846 4856 9110 6405 5826 848 8933 3772 1401 2623 6982 7329 1519 7881 1075 276 3602 7835 470 9977 414 1444 283 1931 8191 4425 6096 4485 589 6870 5281 8295 2284 9578 7887 9042 2033 4587 7949 623 7421 9818 5490 8671 2585 1229 640 1111 5785 8392 3857 3187 5869 1094 464 9391 5375 5128 3439 3601 3306 5301 5746 1784 2485 2367 2325 8722 4754 8540 2342 1308 2295 3124 4279 6214 4874 5791 6 8973 887 96 9121 4863 4767 3908 1518 9347 4525 6652 4397 7324 968 5432 9755 5909)
第 0 世代
DNA:  [19 2 7 18 11 1 8 13 6 3 0 17 4 10 14 15 9 16 5 12] 
Cost:  56356 

第 1 世代
DNA:  [15 1 4 19 3 2 16 9 14 18 13 17 12 0 10 6 7 5 8 11] 
Cost:  49941 

第 5 世代
DNA:  [12 11 15 16 10 2 0 17 9 19 8 1 13 14 4 5 3 18 7 6] 
Cost:  49602 

第 16 世代
DNA:  [14 9 6 2 7 3 4 19 8 11 15 0 5 12 17 1 18 13 16 10] 
Cost:  38679 

第 583 世代
DNA:  [3 11 7 18 9 19 8 5 12 1 0 2 15 16 10 17 4 14 13 6] 
Cost:  35524 

第 6787 世代
DNA:  [10 18 14 4 12 11 15 16 17 13 1 8 5 0 9 19 2 7 6 3] 
Cost:  32775 

FINISH

うそだろ…?時間かかる上に効果も得られない、と言う結果になりました。最初の半分以下のコストにもならないとは思わなかったです。遺伝的アルゴリズムすごい。

終わりに

 突然変異をどうすればよいか調べると、現在の個体から選んで突然変異させたり、交叉でできた個体を突然変異させると書いてたり、よくわかりませんでした。なので、現在の個体から選び、要素を2つ選んで順番を交換させる方法を選びました。
 わからないなりにも、遺伝的アルゴリズムのすごさが分かりよかったです。

Clojure から Java の可変長引数をもつ関数の呼び出し

はてなブログ初めました。うおざです。
最初の記事に何を書こうか書こうかと考えていたら、いい感じに問題にあたったのでそれを書くことにしました。
それは ClojureJavafx を呼びだしてファイルダイアログを表示させる際に、拡張子でフィルタをかけるようにしていたときのことです。
Clojure で以下のようなコードを書いていました。

(let [fileChooser (FileChooser.)]
  (-> fileChooser
    .getExtensionFilters (.add (FileChooser$ExtensionFilter. "Audio Files" "*.wav" "*.mp3" "*.aac"))))

しかし、これを実行すると

java.lang.IllegalArgumentException: No matching ctor found for class javafx.stage.FileChooser$ExtensionFilter, compiling:(scoreditor/application.clj:67:34)
Exception in thread "main" java.lang.IllegalArgumentException: No matching ctor found for class javafx.stage.FileChooser$ExtensionFilter, compiling:(scoreditor/application.clj:67:34)

といったエラーがでます。

No matching ctor found for class javafx.stage.FileChooser$ExtensionFilter

クラスが見つからないようなことを言われています。
しかし、調べても Clojure でのインナークラスのコンストラクタの呼び出しは

(ClassName$InnerClass.)

で可能のはずなので不思議で不思議でした。Java で無理やり解決しましたが、やはりモヤモヤは消えず。
あまりにもわからないのでtwitterでつぶやいたら


リプライがきました。
Clojure で調べたら日本語の情報で度々目にする @_ayato_p さんです。
最初のコード送ると以下の StackOverFlow の URL がおくられてきました。ありがとうございます。
stackoverflow.com
ふんふんとわからない英語を読むと、どうやら Clojure から Java の可変長引数の関数を呼ぶにはどうすればいいかという内容でした。
Clojure から Java の可変長引数を呼ぶ際には可変長引数の部分を vector で囲んでやらんといけんとのことでした。
FileChooser$ExtensionFilter のコンストラクタを確認してみると可変長引数になっていました。
そこで以下のように直すと

(let [fileChooser (FileChooser.)]
  (-> fileChooser
    .getExtensionFilters (.add (FileChooser$ExtensionFilter. "Audio Files" ["*.wav" "*.mp3" "*.aac"]))))

エラーなく実行できました。[] で囲っただけです。とっても単純。
こういった言語のルールをしらないと今日のように半日うんうん悩むことになってしまうので、しっかりと勉強しておきます。

これからもこういった記事を書いていきますので、よければ見ていただければと思います。よろしくお願いします。