2011-12-28

_ USIと状態管理案

右図は、あから2010の通信の一部でも使っていた、USIをベースにしたプロトコルの簡略化した状態遷移図です。(ちなみに秋頃書いていたGPS将棋の紹介記事がコンピュータソフトウェア1月号に掲載予定です。USIにも触れていてこの図はここから取りました。)stopとbestmoveの競合 図中で、>が上流から思考部への通信、<が思考部から上流への通信です。

基本的な状態遷移は図の実線の矢印部分です: プログラムは左のidle状態でスタートし、positionを受け取ったり、図では省略されていますがoptionなどの処理をします。go infiniteを受け取ると、思考に入りsearch状態に遷移します。search状態では、infoという文法で定期的に状態を上流に伝えます。stopを受け取ると searrh finished状態に遷移し、bestmove で最善手を報告してidleに戻ります。

さて、思考部を作っていると、stopが来る前に指し手が一手に定まったらbestmoveを返したくなります(特に既存のプログラムを微調整してUSIに対応する場合)。上流側も、もう指手が変化しないという状態を知ると良い場合があります(たとえば、いわゆる合議のように思考部の最善手を集約して指手を決める時に持ち時間を節約したい)。そこで、あから2010では、search状態から下の点線部分にあるように思考部がstopを待たずにsearch finished 状態に遷移することを許しました。すると、上流のstopと思考部のbestmoveが同時に起こったらどうなるか? という競合の問題を解決する必要があります。あから2010の場合は、図のsearch finishedやidle状態の点線のように、search以外の状態で到着したstopを無視するという解をとりました。(が、少し実装は面倒なので、この文章の末尾で別の案を提案します)

USIの元提案 (http://www.geocities.jp/shogidokoro/usi.html) や、将棋所バージョン (http://www.geocities.jp/shogidokoro/usi.html) では、go infinite に限ってstopが来るまではbestmoveの出力を禁止することで、競合が起こらないようにしています。しかし、go byoyomi 10000 等時間指定がある時は、依然競合があります。時間制限がある時はstopを使わないなら別ですが、それは不便ですし、仮に時間前のbestmove出力を禁止したとしても、stopが思考部に届くまでに10秒を越える等の例で分かるように、通信に遅延がある環境で頑健なクライアントを作りたい場合は競合に対処しておく必要が依然としてあるわけです。

ところで、囲碁のgtpというプロトコルでは、コマンドと応答に名前をつけることが可能です。具体例を示すと、usiのgoとbestmoveに対応する応答はgtpでは
genmove b
= E7
となりますが、ここでgenmoveの行頭に数値のidをつけると、
0 genmove b
0 = E7
というように、応答の先頭にもそのidを提示する規約になっています。http://www.lysator.liu.se/~gunnar/gtp/gtp2-spec-draft2/gtp2-spec.htmlの2.5節のあたり。

そこで、USIでもposition, go, info, stopにid=xで対応する局面を明示可能にして、
position id=0 startpos
go id=0 infinite
info id=0 pv 7g7f
stop id=0
bestmove id=0 7g7f

等でいかがでしょう。細かくは、goやstopで提示されるidは思考部が最後に受け取ったpositionと同じでなければならない、と決めておいたほうが良いかもしれません。またid=xをどこに挟むかは、理由があれば変更しても良いかもしれません。(コメント歓迎)

_ その他の変更案

細かいところでいくつか

  • go ignoremoves: go searchmoves 7g7f 2g2f とすると、7g7fと2g2fだけ探索するという文法があります。この反転で、go ignoremoves 7g7f 2g2fとすると7g7fと2g2fは候補手に含めない、という文法が必要です。応用先は、予測読みとか、探索の分担があります。上流が合法手を全て生成できれば、searchmovesでも理論上は同等のことができますが、合法手が100を越えることを考えると冗長さが耐えられないので。
  • go book: 定跡が有る時だけ返す。無い時はpassを返す。思考部が定跡を使うかどうかを制御したいケースがあります。原案では、USI_OwnBookというオプションで設定することが提案されています。しかしオプション関係は面倒なので、通常のgoでは定跡は使わない。定跡の手がほしい時は専用のgo bookコマンドを使うと使い分けては? (定跡がなければ探索させるとかは上流で制御)
  • go declarewin: 勝ち宣言できる時だけ返す。できない時はpassを返す。
  • ponder 変更: あまり検討していませんが、idがあるとシンプルにできることの紹介です。 (1) ponderを許可するかどうかは上流から通知される (2) 思考部はponderが許可されている場合、いつでもinfo を上流に送って良いことにする。GUIの場合に、これを表示するかしないかは上流が決める。思考部が現在どの局面を探索しているかはidとpvから読み取る。最後の探索結果がbestmove id=0 7g7fで、その後
    info id=0 7g7f 3c3d 2g2fであれば、34歩の局面を予想している、と解釈可能(ですよね)。
  • legalmoves 局面の合法手を全て生成(コマンド名は要検討)

gtpやgogui から輸入すると良さそうな機能としては、

  • list_commands 思考部がサポートしているコマンドを表示
  • オプションはgui側が保存する (ユーザが保存メニューを選ぶと、今までに思考部に与えたset option関係をファイルに保存する)
  • gogui-analyze_commands goguiから輸入
などがあります。gogui (http://gogui.sourceforge.net/)で囲碁プログラムを開発する場合、開発者はデバッグ用に独自のgtpコマンドを作って、応答を文字列だけでなく、各マスに対応するする数値を白や黒の四角の大きさで可視化することもできます。

_ 追記

コメントいただいたこともあり少し補足します

  • idなくても動くのでは?
    動くけど、idの方がbetterという立場の提案です。開発過程では、bestmoveをうっかり二回返すバグとか、(ponder絡みの混乱で)古い局面のinfo を送ってしまうなどは十分想定されて、id方式の方が怪しい挙動を手早く検知できて便利/普及しやすいかと。
  • ponderも動くのでは?
    ponderに関しては動かないという問題はなくて、相手考慮中に一手だけ予想して探索するという方式に固定されていることが、他の方式のプログラムとは合わないということですね。提案方式なら複数の手を順番に/並行して探索していても、一応情報の表示が可能です。
  • この文章の位置づけについて
    改定案が出されるならこのような点も議論してほしいという希望がありますが、この案で多数派工作をしようという意図はありません。メリットデメリットを共有したり、見落としがないかとか、トレードオフがある場合はどちらが良いかの議論をするための材料になればという趣旨です。コメントありがとうございます。

本日のツッコミ(全9件) [ツッコミを入れる]
_ ツッコミ・コメント (2011-12-29 22:13)

コマンドが1対1の関係になっていればidは一意に定まるわけですからidをつける必要はないと思います^^<br>もし私がUSI2.0を定義するのであればgoとbestmoveとstopが1セットになるように変更したいですね<br><br>・GUIはgoの次には必ずstopを送る<br>・GUIはgo byoyomi 10000 のような場合もstopを送る<br>・GUIはstopを送る前にbestmoveを受け取ったらstopを即座に送る<br><br>stopの直後にbestmoveと、bestmoveの直後にstopの2パターンだけであれば<br>USIエンジン側の待ち時間はほぼ0ですから競合しても問題はないだろうと思います

_ kaneko (2011-12-29 23:07)

はい、実はGPS将棋やあから2010は、そうやってgo, bestmove, stopの回数を数えながら動いていたりします。<br>ただどちらが良いかというと、idを使った方が簡潔で直感的な実装になるのではないかと。

_ ツッコミ・コメント (2011-12-29 23:25)

ponderについてですが単純にponderhitの代わりにstopを送るのでどうでしょうか<br>ponderが外れたら即座にstopを送る/ponderが当たれば時間ぎりぎりまで粘ってstopを送る<br>ようにGUIの側で対処すればgoとbestmoveとstopを1セットに保てるのでわかりやすいかなと

_ ツッコミ・コメント (2011-12-29 23:38)

返信ありがとうございます<br>なんだか金子様の案がすばらしいような気がしてきました<br>あんまり余計な主張しますと自分でGUIを作らなければならなくなりますのでこの辺で失礼いたします…

_ LS3600 (2011-12-30 05:20)

1回のgo XXXX に対してbestmoveを返すのは一回という、goとbestmoveの1対1の対応関係さえあれば、いいだけのように思うのですが。すなわち、「stopに対してbestmoveを返す/応答する」という仕様がおかしくて、stopはbestmoveを返していないときの督促シグナルに過ぎないという扱いにします。<br>これですと何か問題があるのでしょうか?

_ kaneko (2011-12-30 16:37)

はい、動きます。実際のところ、gpsusi.ccではgoとbestmoveの数を数えています。idを推す理由を追記してみました。

_ LS3600 (2011-12-30 17:49)

ああ、意味がわかりました。確かに相手番での先読み(USIのponderを使わずに独自の方法で先読みしていた場合)絡みの読み筋表示のためにはidがあったほうが良いですね。

_ うさぴょんの育ての親 (2012-01-30 16:36)

基本的な状態遷移は図の実戦の矢印部分です:<br><br>「実線」だと思うのですが、「実戦」に化けてます。<br><br>どうでもいいところで遅いコメントですみません。

_ kaneko (2012-01-30 20:18)

ありがとうございます

[]

«前の日記(2011-12-09) 最新 次の日記(2012-01-29)»