平岡さんがStockfishの公式にpull requestをしている。
https://github.com/official-stockfish/Stockfish/pull/814
StockfishはかつてONE_PLY(1手の深さ)が、2だった。これがいつぞやのpatchで1になった。
「1でも強さ変わらんし、そのほうが速いもーん」(要約)
とのことだった。ところが、やはり、ONE_PLYは自由に変更できるほうが探索パラメーターの調整をうまく出来るという考え方も根強く、「この値をいくらに変更してもうまく動作するようにしよう」というcommitが先月ぐらいにあった。
ちなみに将棋ソフトの開発者の間でもONE_PLYはもっと大きくしたほうが探索パラメーターを調整しやすいという考えかたを支持する人は多い。『技巧』ではONE_PLYは64になっている。でかすぎ!さすがチューニングの鬼と言ったところか。
ONE_PLYを自由な値に変更できるようにするためには、例えばdepth(残り探索深さ)が、5なら、値としては5*ONE_PLYであるから、これを枝刈りのときのマージン値として用いると、ONE_PLYに影響されてしまうことになる。
そこで、margin = value – depth/ONE_PLY …のようにdepthを用いるときはONE_PLYで割ってから使う必要があるわけだ。
こんなムーブメントのなか、Stockfishのソースコードにはいまだrazoring(枝刈りの名前)の配列へのアクセスがONE_PLYの値に依存しているところがあった。
1 2 3 |
if (depth <= ONE_PLY && eval + razor_margin[3*ONE_PLY] <= alpha) return qsearch |
ONE_PLY倍してしまうとONE_PLYが1以外のときに配列の範囲外をアクセスしてしまう。
どう見ても間違ったコードである。平岡さんのpull requestはこの意味である。それに対して「この修正、間違っているのでは」みたいな脊髄反射レスがついているが、ド素人はすっこんでろ!と言ったところか。
平岡さんがこのpull requestを投げるということはAperyの最新版ではONE_PLYを1以外の大きな数字にしていて、それでうまく動作しなかったからなのだろう。やねうら王ではONE_PLYは1のままです、はい。
ちなみにやねうら王では、razor_marginは関数化してもともとONE_PLYに非依存にしてあった。上の箇所が間違っているのは知っていたが、そのうち修正されるだろうと思ってStockfish公式にpull requestをしたりはしていなかった。
しかしこの部分はよく見ると、何だかrazoringとしておかしい。razor_margin[3]ではなく、razor_margin[0]ではないのか?eval+razor_margin[0] <= alphaだから、静止探索を呼ぶのがrazoringだろ?razor_margin[3]ってどこから出てきたのだ…。
ついでに言うと、eval+razor_margin[0] <= alphaは前提条件として満たしているから、この条件自体が不要だと思う。だからこの部分、正しくは、こうだ。
1 2 |
if (depth <= ONE_PLY) return qsearch |
これで元のコードより強くなるかは知らんが…。
やねうら王のほうはこっそり修正した。
って書いてたら、いましがたStockfish公式のほうで、これと全く同じ修正が入った。
Remove useless razoring condition
https://github.com/official-stockfish/Stockfish/commit/eccccba0ce4e2d627cbe2adb1bf4a692d595ca99
razoring(枝刈り)のついての解説記事は…また気が向いたら書きます。
難しいです。
指してを読んでいるときに「何かよさそうな手だからもっと深く読むか」ってときに、もっと深く読むパラメータが1手単位ではなくてってことなのでしょうか?
「(残り探索)深さ」の単位が1手より小さいんです。詳しくは明日の記事で書きます。