Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

JOI夏期セミナー2016

880 views

Published on

この後maroon君にも負けました

(許可はとってあるので肖像権侵害は)ないです

Published in: Art & Photos
  • Be the first to comment

JOI夏期セミナー2016

  1. 1. メタヒューリスティクス @yosupot
  2. 2. 寝てないので粗相は許して
  3. 3. 自己紹介 ● 森田晃平 ● Twitter: @yosupot ● 東京工業大学第5類3年 ● GCJ FHC 2016 Finalist ● 前回のJOI春合宿で講師をしました
  4. 4. 2016年の流行
  5. 5. 2016年の流行 ● 水素水
  6. 6. 2016年の流行 ● 水素水 ● ポケモンGO
  7. 7. 2016年の流行 ● 水素水 ● ポケモンGO ●Chain – もちろん皆さんも遊んでいますよね?
  8. 8. 5日間でやったこと ● 「メタヒューリスティクスの数理」を読む ● chainのSolverの実装
  9. 9. 5日間でやったこと < 課題としてChainのSolverを実装してみては? kagamizチューター
  10. 10. 5日間でやったこと < おっそうだな
  11. 11. Chain(おさらい) ● kagamizチューターの作ったパズルゲーム ● スコアの計算式は ● kagamizチューターの作ったパズルゲーム ● スコアの計算式は (X, Y): 選択したブロックBの座標 S: 消えたブロックの座標の集合 n: 全てのブロックが消えた縦の列の本数
  12. 12. 考察 ● 式を見る限り、列ボーナスが大きそう ● 時系列があるため近傍が定義しづらい
  13. 13. 考察 < 近傍ないって メタヒューリスティクスの余地なくない?
  14. 14. 考察 < 本を読んだ意味とは?
  15. 15. 考察 < どうやってスコア出そう...
  16. 16. 考察 こういう時は
  17. 17. 考察 < ビームサーチで常勝!
  18. 18. ビームサーチ(おさらい) ● 探索手法の1つ ● 適当に各状態にスコアリング ● スコアの悪いものを枝刈りしてオーダーを抑える ● 無茶振りに強い(らしい)
  19. 19. ビームサーチ(おさらい) ● ビームサーチで大事なのは評価関数 ● 評価関数でSolverの戦略を制御する事ができる ● 今回は(実際のスコア) + (評価関数の値)でランク付け ● 例として一番初めに考えた評価関数を紹介します
  20. 20. 考察(再掲) ● 式を見る限り、列ボーナスが大きそう
  21. 21. ビームサーチ(おさらい) ● 結局、列ボーナスを得られるような動きが欲しい – 「列が1色になったら加点」は良くなさそう ● それは実際のスコア内で考慮されると思われる – 「列が1色になる」ために何が起こればいい? ● 列がn色からn-1色になったら嬉しそう
  22. 22. ビームサーチ(おさらい) ● num[i] := 丁度i色のブロックが含まれる列の数として ただしconsは適当な定数(1000, 600, 100, 40, 0とか)
  23. 23. ビームサーチ(おさらい) ● こんなに雑で良いのかなあと思いながら書いた – 隣り合う列の状態なんかは全く考慮されていない ● 果たして上手く動いたのか? – 結果はのちほど
  24. 24. 期間中の改善を紹介します
  25. 25. 1日目 ● テキストにメタヒューリスティクスを選ぶ ● ゼミをやるらしく2章を読み始める – 書き方が分かりづらく非常に苦労した... ● Chainの実装はまだ始めていなかった ● ボードゲームを4時間ぐらいした
  26. 26. 2日目 ● ボードゲームのせいで読めてなかった2章を読む ● 無事に全てを理解することに成功しゼミを行った ● 夕方からChainの実装を始める ● 初めの評価関数を適当に思いつく ● シミュレーション部分は完成した ● ボードゲームを3時間ぐらいした
  27. 27. 3日目 ● ビームサーチも含めて書き上げられた ● よっしゃ提出や! – easy_1 → 26000点ぐらい – 他の人は既に40000点ぐらいを取っていた(かな?) – 低すぎません....?
  28. 28. 3日目 ● 出力する答えを眺めていたらあることに気づく – たまにSolverが目先の利益に飛びついている
  29. 29. 3日目 ● 出力する答えを眺めていたらあることに気づく – たまにSolverが目先の利益に飛びついている – どういうことか?
  30. 30. 3日目 ● 出力する答えを眺めていたらあることに気づく – たまにSolverが目先の利益に飛びついている – どういうことか?
  31. 31. 3日目 ● 出力する答えを眺めていたらあることに気づく – たまにSolverが目先の利益に飛びついている – どういうことか? ● この段階でも青を消す方が赤よりスコアが良い 距離460 + 列1600
  32. 32. 3日目 ● 出力する答えを眺めていたらあることに気づく – たまにSolverが目先の利益に飛びついている – どういうことか? ● この段階でも青を消す方が赤よりスコアが良い ● 先に赤を消したらもっとスコアが伸びたのに... 距離1000 + 列6400
  33. 33. 3日目 ● 盤上の全連結成分のスコアを評価に加えることにした – これで点数の高さに飛びつくことはなくなる ● これで点数跳ね上がるんちゃう?w – easy_1 → 30800点ぐらい – まだまだ40000点に届かないんですが... ● バグを疑い始める
  34. 34. 3日目 ● ここでクイズ – どこがバグの原因でしょうか? struct StateGreater { bool operator()(State* a, State* b) { int ap = a->cur_score + a->evaluated + a->estate; int bp = b->cur_score + a->evaluated + b->estate; return ap > bp; } }; ... set<State*, StateGreater> cur_stage; // ビームサーチ用のheapたち set<State*, StateGreater> next_stage;
  35. 35. 3日目 ● ここでクイズ – どこがバグの原因でしょうか? – シンキングタイム struct StateGreater { bool operator()(State* a, State* b) { int ap = a->cur_score + a->evaluated + a->estate; int bp = b->cur_score + a->evaluated + b->estate; return ap > bp; } }; ... set<State*, StateGreater> cur_stage; // ビームサーチ用のheapたち set<State*, StateGreater> next_stage;
  36. 36. 3日目 ● ここでクイズ – どこがバグの原因でしょうか? – 答え struct StateGreater { bool operator()(State* a, State* b) { int ap = a->cur_score + a->evaluated + a->estate; int bp = b->cur_score + a->evaluated + b->estate; return ap > bp; } }; ... set<State*, StateGreater> cur_stage; // ビームサーチ用のheapたち set<State*, StateGreater> next_stage;
  37. 37. 3日目 ● ここでクイズ – どこがバグの原因でしょうか? – 答え struct StateGreater { bool operator()(State* a, State* b) { int ap = a->cur_score + a->evaluated + a->estate; int bp = b->cur_score + a->evaluated + b->estate; return ap > bp; } }; ... set<State*, StateGreater> cur_stage; // ビームサーチ用のheapたち set<State*, StateGreater> next_stage; コ↑コ↓
  38. 38. _人人人人人人人人人人人人人人人人人人人人人人_ > b->cur_score + a->evaluated + b->estate; <  ̄Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y ̄
  39. 39. 3日目 ● アッ、a->evaluatedが2つ共に足されている... – 当然差し引き0なので評価関数が機能していない – 俺の2時間を返せ
  40. 40. 3日目 < バグも取れたし優勝余裕やろ!
  41. 41. 3日目 ● しかし現実はそんなに甘くない! – easy_1提出 → 40220 – 40000点を超えたものの1位とは数千点差があった – DEGwerチューターなのになんで参加してるの...
  42. 42. 3日目 ● 結果が改善されず辛い気持ちで夕食に臨む – ここで評価関数なしの人々に負けていると知る – 考えてるのにスコアでないの悲しい... – 評価関数に乱数を足している人々がいて感動する ● 貪欲ランダム適応型探索法的効果が得られそう
  43. 43. 3日目 ● 夜はワードバスケットで語彙力を高めた – リービッヒ冷却器、ワーシャルフロイドは典型
  44. 44. 4日目 ● 寝ている間に矛盾点に気づく – 評価関数無視するバグがあった – その間僕も評価関数なしでやってたのでは? – なんで僕のは人々のような点数が出ないんだ?
  45. 45. 4日目 ● 考えられる原因は多様性が減っていること ● 状態数を表示してみると明らかに少ないことに気づく – 常に状態数200な訳無いだろいいかげんにしろ! – どうしてデバッグ出力しなかったんでしょうかねぇ – 実行爆速すぎるしおかしいと思うべきなんだよなあ
  46. 46. 4日目 ● ここでまたまたクイズ – どこがバグの原因でしょうか? struct StateGreater { bool operator()(State* a, State* b) { int ap = a->cur_score + a->evaluated + a->estate; int bp = b->cur_score + b->evaluated + b->estate; return ap > bp; } }; ... set<State*, StateGreater> cur_stage; // ビームサーチ用のheapたち set<State*, StateGreater> next_stage;
  47. 47. 4日目 ● ここでまたまたクイズ – どこがバグの原因でしょうか? – シンキングタイム struct StateGreater { bool operator()(State* a, State* b) { int ap = a->cur_score + a->evaluated + a->estate; int bp = b->cur_score + b->evaluated + b->estate; return ap > bp; } }; ... set<State*, StateGreater> cur_stage; // ビームサーチ用のheapたち set<State*, StateGreater> next_stage;
  48. 48. 4日目 ● ここでまたまたクイズ – どこがバグの原因でしょうか? – 答え struct StateGreater { bool operator()(State* a, State* b) { int ap = a->cur_score + a->evaluated + a->estate; int bp = b->cur_score + b->evaluated + b->estate; return ap > bp; } }; ... set<State*, StateGreater> cur_stage; // ビームサーチ用のheapたち set<State*, StateGreater> next_stage;
  49. 49. 4日目 ● ここでまたまたクイズ – どこがバグの原因でしょうか? – 答え struct StateGreater { bool operator()(State* a, State* b) { int ap = a->cur_score + a->evaluated + a->estate; int bp = b->cur_score + b->evaluated + b->estate; return ap > bp; } }; ... set<State*, StateGreater> cur_stage; // ビームサーチ用のheapたち set<State*, StateGreater> next_stage; これ!(大声)
  50. 50. 4日目 ● setは重複する値を取り除く – 重複は比較関数で判断される – a < b == false && b < a == falseならa == b – 現状の比較関数は点数しか考えていない! ● 点数が同じなら違う盤面も同じとみなされる
  51. 51. 4日目 ● じゃあmultisetにすれば良くない?w – これはこれで問題が発生する – 完全に同じ盤面、同じスコアのものが大量発生 ● そいつらは成分を消す順番が違うだけ ● これもビーム幅を圧迫し多様性を損なう – じゃあどうすれば...
  52. 52. 4日目 < Zobrist Hashで常勝!
  53. 53. 4日目 ● Zobrist Hash – チェスや将棋などの盤面をハッシュ化するのに便利 – スコア、ハッシュ双方が同じなら同一とみなす – これでsetを使っても問題なくなった!
  54. 54. 4日目 ● 提出ゥ! – Easy_1 → 43990!!! – やっと上位勢に追いつくことが出来た...?
  55. 55. 4日目 ● やはり現実は甘くない! – アイスに釣られたtozanが異常なスコアで君臨 – チューターですらないのに何をやってるんですかね
  56. 56. 4日目 ● 適当にパラメータや評価関数を変えるものの効果なし ● 評価関数を再度無視したら何故かスコアが伸びた – 一番ショックだった
  57. 57. 5日目 ● 徹夜してSolverの改良... ● と思いきや皆でyoutubeを見てたら4時になっていた ● joisinoチューターと話した時に浮かんだ改善を試す – スコア更新はあったが効果があるのか分からない ● 全体的にもはや手詰まり...
  58. 58. 結果
  59. 59. 結果(13:30現在)
  60. 60. 結果 完 全 敗 北
  61. 61. 感想 ● ビームサーチ、あまり役に立ってない気がする – 時間制限がないと評価関数考える必要ないかも? ● マラソンとは話が結構違った ● Output Onlyだと方針で改善してるのか見えづらい – テストケースが5個しかないので余裕で上下する ● 計算資源の暴力は強い ● 夜は寝ましょう ● ボードゲームは控えめに
  62. 62. ご静聴ありがとうございました

×