やねうら王 更新履歴 2016Q2まで
・公式のトップページに書いていた更新履歴、邪魔なので消す。
※ 括弧のなかの+Rは、自己対局時の勝率から計算されるもので、0.5手延長などは顕著に勝率が上がりますが、自己対局以外では効果に乏しいです。
- [x] 2016/07/02・sfen packer追加。
- [x] 2016/06/27・KPPT evaluate()リファクタリングと高速化。
- [x] 2016/06/26・やねうら王2016Midの探索部、調整。
- [x] 2016/06/26・指し手生成部のバグ修正。
- [x] 2016/06/26・やねうら王2016Mid、historyで駒打ちを区別しないように変更。
- [x] 2016/06/25・やねうら王2016Mid、新SEEに差し替え。
- [x] 2016/06/24・MacOS、Ubuntu16.04でコンパイル出来ました。
- [x] 2016/06/23・利きを用いないmate1ply()、離し飛車・角に対して合駒判定間違えていたの修正。
- [x] 2016/06/23・利きを用いないmate1ply()、歩の移動による詰み、歩の開き王手による詰みを間違えていたの修正。
- [x] 2016/06/23・#includeするときのfolder separatorが"\"になっていたものを"/"に修正。(thx.もりたにさん)
- [x] 2016/06/23・文字コードがcp932になっていたファイルをutf8に修正。(thx.もりたにさん)
- [x] 2016/06/22・やねうら王2016Midの定跡の指し手ささなくなっていたの修正。
- [x] 2016/06/22・やねうら王2016Midの開発終了。(ひとまず)
- [x] 2016/06/22・やねうら王2016Mid、noSSE/SSE2/SSE4/SSE4.1/AVX用バイナリを公開。
- [x] 2016/06/22・noSSE/SSE2/SSE4/SSE4.1/AVX2の命令を分けた。SSEなしの環境でも動くはず。
- [x] 2016/06/22・やねうら王2016Mid、g++でコンパイルしたWindows用実行ファイルも配布。
- [x] 2016/06/21・やねうら王2016Mid、Msys2上のg++でコンパイルが通るようにした。Makefile追加。
- [x] 2016/06/21・教師棋譜を自動生成するtest gensfenコマンド追加。(書きかけ。まだ正しく動作しない)
- [x] 2016/06/21・KPPT用のevaluate hashtableを実装。
- [x] 2016/06/20・やねうら王2016Mid、大改造。
- [x] 2016/06/20・評価関数格納フォルダをUSIのsetoptionで変更できるように。
- [x] 2016/06/18・長い持ち時間での勝率upのためのチューニング各種。
- [x] 2016/06/17・利きを用いないmate1ply()実装。
- [x] 2016/06/16・どの探索部でもすべての評価関数が使えるように抽象化した。
- [x] 2016/06/15・MovePickerのquietの指し手返すところのバグ修正。
- [x] 2016/06/14・Bonanza6風の1手詰めルーチンを追加。
- [x] 2016/06/14・やねうら王2016Mid、singular extensionまわり調整。(長い持ち時間において強いはず)
- [x] 2016/06/13・やねうら王2016Mid用のMovePicker追加。history、counter moveまわり大改造。
- [x] 2016/06/13・MovePicker、探索部ごとに変更できるように。
- [x] 2016/06/13・singular extensionの係数を初期のものに戻す。長い時間ではそちらのほうが勝率が高い。(長い持ち時間において+R70)
- [x] 2016/06/13・入玉判定のときに手駒の金を足してなかったの修正。
- [x] 2016/06/02・Apery(WCSC26)の評価関数の読み込み対応完了。(+R105)
- [x] 2016/06/01・Apery(WCSC26)の評価関数の読み込み対応作業中。
- [x] 2016/05/20・EvalListまわり、SIMD化しやすいように修正。
- [x] 2016/04/19・やねうら王2016(Mid) パラメーター自動フレームワーク関連の作業中。
- [x] 2016/04/15・やねうら王classic-TCE(TimeControlEnabled)版を正式公開する。
- [x] 2016/04/15・やねうら王2016mid、ハイパーパラメーターの動的な読み込み部書いた。
- [x] 2016/04/14・depthの3乗ボーナスやりすぎだったようなので修正。(+R10)(thx.woodyringさん)
- [x] 2016/04/14・浅い探索のときでも、killerがないならkillerぐらい更新したほうが得なのでは。(+R33)(thx.読み太の作者)
- [x] 2016/04/14・skipEarlyPruning時にkillerとhistoryを更新しない。(+R25)(thx.読み太の作者さん)
- [x] 2016/04/14・MAX_PLYとmax_game_plyの判定を一本化
- [x] 2016/04/14・ponder消失問題に対応。
- [x] 2016/04/14・自己対戦フレームワークで定跡データベース中の対局の手数が指定した手数より少ない場合クラッシュするっぽいバグ修正。(thx. tanuki-)
- [x] 2016/04/14・やねうら王2016 MidとLateに分離。
- [x] 2016/04/13・singularのときkiller,historyを更新しない。(+R10)(thx.読み太の作者さん)
- [x] 2016/04/13・ehashの仕組み追加したが速くならなかった。
- [x] 2016/04/12・historyとか、成りの指し手のときは、成り駒のhistoryを見ないといけないのにそういう処理になってなかった。(thx. 読み太の作者さん)
- [x] 2016/04/11・classic-tce、aspiration depth間違っていたの修正&調整。(+R8)
- [x] 2016/04/08・王手がかかっていないときはstaticEvalをVALUE_NONEに。(+R4)
- [x] 2016/04/07・history等に駒打ちの情報を追加。(+R20)
- [x] 2016/04/07・dynamic margin実験。
- [x] 2016/04/07・go infiniteでstopが送られて来ていないのにbestmoveを返すことがあったのを修正。
- [x] 2016/04/07・優等局面のVALUE変更。
- [x] 2016/04/07・counter moveには、先手用の指し手に後手の指し手が混じらないように変更。
- [x] 2016/04/07・自己対戦サーバーでStateStack、1局ごとにクリアするように修正。
- [x] 2016/04/07・MaxMovesToDrawの設定が無視されていた問題を修正。
- [x] 2016/04/06・やねうら王classic-tceにsingular extension追加。(+R40)
- [x] 2016/04/06・やねうら王classic-tce。counter moveに駒種を入れる。
- [x] 2016/04/06・やねうら王classic-tceに。bestmove changed のカウンター、インクリメントしてなかったの修正。(+R20)
- [x] 2016/04/06・やねうら王classic-tceに。alpha更新のタイミングでeasy moveをクリアしていなかったの修正。
- [x] 2016/04/06・やねうら王classic-tceに。qsearch()のfutilityでcaptureを考慮するように変更。
- [x] 2016/04/06・VALUE_WINまわりの処理、色々修正。
- [x] 2016/04/06・byoyomiが指定されていないときの動作修正。
- [x] 2016/04/04・やねうら王classic-tceに、Options["NetworkDelay2"]を追加。
- [x] 2016/04/04・やねうら王twig→やねうら王classic-tceに名前変更。
- [x] 2016/04/04・やねうら王twigに持ち時間制御入れる。(+R50)
- [x] 2016/04/04・やねうら王twigにEasyMoveの判定追加。
- [x] 2016/04/03・やねうら王twig、終局までの手数に対応。
- [x] 2016/04/03・やねうら王twig、フィッシャールールに対応
- [x] 2016/04/03・やねうら王twigにponder対応。(+R50)
- [x] 2016/04/03・思考時間の計算用のクラス追加。
- [x] 2016/04/03・benchコマンド時に2個目以降の局面で正しくnpsが表示されなかった問題を修正。
- [x] 2016/04/03・やねうら王twigからタイマースレッド削除。
- [x] 2016/04/03・やねうら王classicからやねうら王twigにfork。
- [x] 2016/04/03・mate1ply修正。(thx. tさん) (+R3)
- [x] 2016/04/02・やねうら王classicのnonPV時のreduction定数、調整。(+R10)
- [x] 2016/04/02・kppファイル読み込み時の変換するためのメモリを動的に確保するように変更。
- [x] 2016/04/02・やねうら王classic、local-game-server、入玉宣言勝ちに対応。
- [x] 2016/04/02・MovePickerのevasion、capture時のordering調整。(+R13)
- [x] 2016/04/02・やねうら王classicのPV時のreduction定数、調整。(+R20)
- [x] 2016/04/01・MovePickerにfollowup move追加。
- [x] 2016/04/01・やねうら王classicのhistory bonus考えなおす。
- [x] 2016/04/01・やねうら王classicにsingular extension調整してみる。
- [x] 2016/04/01・やねうら王classicのRecaptureのオーダリング調整。
- [x] 2016/03/31・see()高速化。(thx. tさん) (+R5)
- [x] 2016/03/31・mate1ply修正。(thx. woodyringさん) (+R15)
- [x] 2016/03/30・やねうら王2015から評価関数ファイルの変換に失敗していたので読み込み時に修正するコード追加した。(+R40)
- [x] 2016/03/30・classicでevaluate()を毎node呼び出しておかないとevaluate()の差分計算がなされないので修正。(thx. tさん、わるおさん) (+R40)
- [x] 2016/03/30・mini,classicでNULL MOVEの前のcheck_info_update()が抜けていたので修正。
- [x] 2016/03/30・classicでcheckinfoのupdateが抜けている経路があったので修正。
- [x] 2016/03/30・depth 4手浅いものより大きいなら置換表のエントリー書き換えるように変更。
- [x] 2016/03/30・置換表格納のときにkeyのcastが間違っていたの修正。(棋力に影響なし)
- [x] 2016/03/30・Positionクラス、eval_list()関数は、戻り値はEval::EvalList型ではなくEval::EvalList*型を返すように修正。(thx. わるおさん)(+R15)
- [x] 2016/03/25・CounterMoveHistoryStateの更新と取得に失敗していた件、修正。(thx. tさん) (+R55)
- [x] 2016/03/25・置換表にDEPTH_MAX書き出せなくなってた件、修正。(thx. tさん)
- [x] 2016/03/25・mate1ply()でpinnedを使っているので先行してcheck_info_update()が必要なので修正。(thx. tさん)
- [x] 2016/03/25・pseudo-legalのチェックで、counter moveの手は手番に関係ない(ような実装になっている)ので、
違法手のチェックが必要だったのでその修正。(thx. woodyringさん)
- [x] 2016/03/25・mate1ply()でpinnedを使っているので先行してcheck_info_update()が必要。(thx. tさん)
・classic、mini、nano plus修正。
- [x] 2016/03/25・classicで1手詰めを呼び出すときに王手がかかっているかのチェックするの忘れていたの修正。(thx. woodyringさん)
- [x] 2016/03/25・古いほうの置換表実装削除。(置換表が弱くなる原因ではなかったようなので)
- [x] 2016/03/25・nanoで常にfull depth searchになっていたバグを修正。(thx. kazuさん)
- [x] 2016/03/25・seeのバグ修正。(thx. tさん、woodyringさん) (+R15)
- [x] 2016/03/04・打ち歩詰めの判定修正。(thanks to tanuki-さん)
- [x] 2016/03/01・やねうら王classic、悪いhistoryにreduction量を増やす枝刈り追加。
- [x] 2016/03/01・やねうら王classic、引き分け時のスコア、value_from_tt()を通すようにした。
- [x] 2016/03/01・やねうら王mini、引き分け時のスコア、value_from_tt()を通すようにした。
- [x] 2016/02/29・fail lowを引き起こした直前のcounter moveに加点するようにした。
- [x] 2016/02/29・1手詰めを見つけたときのスコアがおかしかったの修正。
- [x] 2016/02/29・やねうら王miniに定跡のnarrow book機能入れた。
- [x] 2016/02/29・やねうら王classicに定跡のnarrow book機能入れた。
- [x] 2016/02/29・思考エンジンごとにUSIのOptionを追加できるようにした。
- [x] 2016/02/29・やねうら王miniの静止探索で駒取りにならないevasionの枝刈り追加。(+R100)
- [x] 2016/02/29・やねうら王classicの静止探索で駒取りにならないevasionの枝刈り追加。(+R100)
- [x] 2016/02/29・やねうら王miniの静止探索にfutilityによる枝刈り追加。(+R70)
- [x] 2016/02/29・やねうら王classicの静止探索にfutilityによる枝刈り追加。(+R70)
- [x] 2016/02/29・やねうら王classicに親nodeでSEE負の指し手を枝刈り追加。(+R40)
- [x] 2016/02/29・やねうら王classicに親nodeでのfutility枝刈り追加。(+R40)
- [x] 2016/02/29・やねうら王miniにhistoryに基づく枝刈り追加。(+R20)
- [x] 2016/02/29・やねうら王miniで通常探索時の1手詰め判定削除。
- [x] 2016/02/29・やねうら王classicにhistoryに基づく枝刈り追加。(+R150)
- [x] 2016/02/29・やねうら王miniのソースコード、整理。効果の薄い枝刈り削除。
- [x] 2016/02/29・やねうら王miniにmoveCountベースのfutility追加。(+R150)
- [x] 2016/02/29・やねうら王classicにmoveCountベースのfutility追加。(+R150)
- [x] 2016/02/28・やねうら王classicに王手延長追加。(+R50)
- [x] 2016/02/28・やねうら王classicに多重反復深化追加。(+R12)
- [x] 2016/02/28・やねうら王classicにProbCut追加。(+R70)
- [x] 2016/02/28・やねうら王miniにProbCut追加。(+R70)
- [x] 2016/02/28・MovePickerにProbCut用の指し手生成を追加。
- [x] 2016/02/28・やねうら王classicの開発開始。
- [x] 2016/02/28・やねうら王miniの思考エンジンの実行ファイルを公開。
- [x] 2016/02/28・やねうら王miniの開発終了。
- [x] 2016/02/28・local game serverでCreateProcessに失敗したときに復帰できるように修正。
- [x] 2016/02/28・やねうら王miniで定跡の指し手が指せていなかったの修正。
- [x] 2016/02/28・やねうら王miniにrazoring追加。(+R20)
- [x] 2016/02/28・やねうら王miniにnull move search追加。(+R60)
- [x] 2016/02/28・Position::do_null_move()/undo_null_move()追加。
- [x] 2016/02/28・MovePickerで置換表の指し手とcounter moveにおいて歩や大駒の不成などを除外するようにした。
- [x] 2016/02/28・Position::moved_piece()で後手の駒打ちのときに後手の駒が返るように変更。
- [x] 2016/02/28・QUITE_CHECKで歩の不成が生成されていた問題を修正。
- [x] 2016/02/27・Position::pseudo_legal()修正。
- [x] 2016/02/26・やねうら王miniでmain threadでfail high/lowが起きたときにGUIに読み筋を出力するようにした。
- [x] 2016/02/26・やねうら王miniのaspirationのdelta調整。(+R20)
- [x] 2016/02/26・やねうら王miniにlazy SMP実装。(4コア時+R220程度)
- [x] 2016/02/26・やねうら王miniにPV line実装。(-R10)
- [x] 2016/02/26・やねうら王miniにss->moveCount追加。これによるhistoryへのbonus追加。(+R30)
- [x] 2016/02/26・やねうら王miniにaspiration windows search実装。(+R10)
- [x] 2016/02/25・やねうら王miniの思考オプションにMultiPV追加。
- [x] 2016/02/25・やねうら王miniの思考オプションにContempt(引き分け時スコアの設定)追加。
- [x] 2016/02/25・nano plusをベースにしてやねうら王miniの探索部書いていく。
- [x] 2016/02/25・nano plus、開発終了。(R2500相当)
- [x] 2016/02/25・nano plus、bad captureをkillerの直後に。(+R25)
- [x] 2016/02/25・nano plusのMovePickerにEVASIONSのオーダリング追加。
- [x] 2016/02/25・nano plusのMovePickerにCAPTURESのオーダリング追加。(+R30)
- [x] 2016/02/25・nano plusにhistory,counter move,counter move historyを追加。(+R120)
- [x] 2016/02/24・nano plusのMovePicker、別ファイルに分離。
- [x] 2016/02/24・劣等局面の判定追加。(+R5)
- [x] 2016/02/24・nano plusの枝刈りにfutility pruning追加。
- [x] 2016/02/24・nano plusのMovePickerで静止探索時に置換表の指し手がpseudo-legalでないときに落ちていたの修正。
- [x] 2016/02/23・nano plusのMovePickerで置換表の指し手がpseudo-legalでないときに落ちていたの修正。
- [x] 2016/02/23・local game serverの子プロセスの起動タイミングをばらつかせる。(乱数seedをばらけさせるため)
- [x] 2016/02/22・nano plus、"go infinite"に対応させる。
- [x] 2016/02/22・PRNGのデフォルトの乱数seedの精度を上げる。
- [x] 2016/02/22・Position::is_draw()→is_repetition()に名前変更。2手遡るの忘れていたの修正。
- [x] 2016/02/22・test autoplayコマンド追加。
- [x] 2016/02/22・nano plusにサイレントモード追加。
- [x] 2016/02/22・打ち歩詰めの指し手生成、生成条件が間違っていたの修正。
- [x] 2016/02/22・やねうら王nano plus、search()に一手詰め判定追加。(+R10)
- [x] 2016/02/22・やねうら王nano plusに千日手判定追加。(+R20)
- [x] 2016/02/22・Position::is_draw()実装
- [x] 2016/02/21・打ち歩詰め関係、ソース整理。
- [x] 2016/02/21・指し手生成で打ち歩詰め除外したときに、pseudo_legal()に打ち歩詰め判定入れるの忘れていたので修正。
- [x] 2016/02/21・Position::capture()の処理間違っていたの修正。
- [x] 2016/02/21・やねうら王nano plus、full depth searchの処理修正と調整。(+R100)
- [x] 2016/02/21・やねうら王nano plus、improvingフラグ用意。(+R5)
- [x] 2016/02/21・やねうら王nano plus、通常探索でevaluate()を呼び出すように変更。(+R50)
- [x] 2016/02/21・local game server、エンジン側から非合法手が送られてきたときにMOVE_RESIGN扱いにするように。
- [x] 2016/02/21・打ち歩詰めの判定、高速化。(+R10)
- [x] 2016/02/21・pos.legal()、玉の影の利きがあるときの処理間違っていたので修正。
- [x] 2016/02/21・local game serverでserver側の負荷が高かったのを修正。
- [x] 2016/02/21・local game serverで思考エンジンがbestmoveを返さないとハングしていたでタイムアウト処理追加。
- [x] 2016/02/21・やねうら王nano plusのMovePickerのRECAPTUREの処理、修正。
- [x] 2016/02/20・やねうら王nano plusの静止探索の指し手生成を色々調整。(+R180)。
- [x] 2016/02/20・やねうら王nano plusの静止探索で置換表絡みの処理追加。
- [x] 2016/02/19・やねうら王nano plusにLMRの導入。(+R140程度)
- [x] 2016/02/11・起動時にファイルからコマンドを受け付ける機能追加。
- [x] 2016/02/11・起動時にargvとして複数行を実行する機能追加。
- [x] 2016/02/10・自己対局サーバー、1スレッド×同時対局(マルチスレッド)に対応させる。
- [x] 2016/02/09・Threadクラス大改修。→ thread絡みの問題が起きなくなった。(ようだ)
- [x] 2016/02/09・_mm_mallocが失敗する件、さらに調査。→ std::thread絡みの問題くさい。
- [x] 2016/02/09・_mm_malloc()自作した。→これでも失敗する。newに失敗しているのか。ランタイム腐ってるのか…。
- [x] 2016/02/09・ローカルサーバー機能、ときどき対戦が開始しないので原因を調査する。→_mm_mallocが高負荷状態で失敗するようだ…。
- [x] 2016/02/09・やねうら王nano plusにkiller moveの導入。
- [x] 2016/02/09・nano plusで1手詰めなのに探索局面が多すぎるのでmate distance pruning追加した。
- [x] 2016/02/09・ベンチマークコマンド書けた。
- [x] 2016/02/08・やねうら王nano plusでMovePickerでの指し手生成を逐次生成に変更。
- [x] 2016/02/08・やねうら王nano plusで1手詰め判定を呼び出すように。
- [x] 2016/02/08・gcc/Clangでコンパイル通るようにする→Clangは無理。gccは行けそうだが、時間かかりそうなので保留。
- [x] 2016/02/08・やねうら王nano plusの開発開始。
- [x] 2016/02/08・やねうら王nano、floodgateでR2000を超えたので、nanoの開発終了。
- [x] 2016/02/08・実行ファイルをプロジェクトの一部として配布する。
- [x] 2016/02/07・やねうら王nanoをnonPV/PVの処理をきちんと書く。(これでR2000ぐらいになっていればnanoの開発は終了)
- [x] 2016/02/07・KPPの評価関数の差分実装完了。
- [x] 2016/02/06・やねうら王nanoで定跡の採択確率を出力するようにした。
- [x] 2016/02/06・やねうら王nanoの定跡を"book.db"から読み込むように変更。
- [x] 2016/02/06・定跡の読み込み等をこのフレームワークの中に入れる
- [x] 2016/02/06・定跡生成コマンド"makebook"
- [x] 2016/02/05・やねうら王nanoの探索部
- [x] 2016/02/05・やねうら王nano秒読みに対応。
- [x] 2016/02/04・やねうら王nanoに定跡追加。
- [x] 2016/02/01・新しい形式に変換した評価関数バイナリを用意する → 用意した → CSAのサイトでライブラリとして公開された。
- [x] 2016/01/31・やねうら王nanoの探索部(WCSC26用)
■ 2016/06/17 V3.10
・qsearch()での宣言勝ち判定やめる。
■ 2016/06/17 V3.09
・mate1ply()に離し飛車・角での詰みを実装する
DIRECTIONS_CROSS
DIRECTIONS_DIAG
追加。
more_than_one_cr()削除。
秒読み1000[ms]
50.4%
#191
やねうら王2016mid V309
利きなしsmate/qmate。離し飛車・角。1スレッド
#190
やねうら王2016mid V308a
利きなしsmate/qmate搭載。1スレッド
114-10-112(42.1% R3.1)
ほぼ変わらない。もう少し長い時間では..?
秒読み3000[ms]
52.8%
#191
やねうら王2016mid V309
利きなしsmate/qmate。離し飛車・角。1スレッド
#190
やねうら王2016mid V308a
利きなしsmate/qmate搭載。1スレッド
113-7-101(18.7% R19.5)
離し角・飛車、判定があるほうがややいいのかも知れない。
■ 2016/06/17 V3.08
・MATE_1PLY→USE_MATE_1PLYに変更したときに、変更忘れてたところがあって、
mate1ply()用のビットボード初期化されてなかった。mate1ply()そのあと意味成してなかった。ワロタ。
・file,rank、負の値が取れるようにenum : int32_tにする。
・利きを使わないmate1plyの作業
→ 何も考えずにやねうら王2014のコードをコピペしまくったら完成した。2000行もあった。吐きそう。
1手詰め呼び出さないとき
===========================
Total time (ms) : 178391
Nodes searched : 116770147
Nodes/second : 654574
1手詰めを通常探索で呼び出すとき
===========================
Total time (ms) : 62710
Nodes searched : 41126951
Nodes/second : 655827
速度ダウンほとんどなしに(探索ノードが違うから厳密な比較はできないが)
通常探索での1手詰めを搭載出来た。儲け儲け?
V3.08a
qmate(静止探索)でのmate1ply()もあり。
2<Error : engine timeout , engine name = engines\YaneuraOu-2016-midV308a.exe
2< □ □ □ □^玉 □^桂 □ □
2< □ 玉 銀 □ □^角 銀 □ □
2< □ □ □ □ □ □ □ □ 龍
2<^香 □ □^角^歩^金 □ □ □
2<^金 □ □ 桂 □^歩^歩 桂^歩
2< □ 歩^歩 □ 歩 □ □ □ □
2< □ □ □^杏 □ 銀 □ □ □
2< □ 香 □ □ □ □ □^歩 □
2< □ □ □ □ □ □ □ 飛 香
2<先手 手駒 : 歩2 銀 , 後手 手駒 : 歩8 桂 金2
2<手番 = 先手
2<sfen 4k1n2/1KS2bS2/8+R/l2bpg3/g2N1ppNp/1Pp1P4/3+l1S3/1L5p1/7RL b 2PS8pn2g 175
落ちた。
more_than_one()がcross_over()前提としてなかった。
more_than_one_cr()追加
また落ちた。
5<手番 = 先手
5<sfen ln1g2g2/1r7/p1p4+Sp/1pkp5/4N1B2/2PPPPP2/PP2KbS1P/1G2L4/LN1r1G2L b 5PSns 77
can_legal_drop()ではなかったのか。修正。
1,3秒でV3.08とV3.08a
静止探索あるほうがやや得か?
秒読み1000[ms]
51.9%
#190
やねうら王2016mid V308a
利きなしsmate/qmate搭載。1スレッド
#189
やねうら王2016mid V308
利きなしsmate搭載。1スレッド
431-20-399(12.6% R13.4)
秒読み3000[ms]
52.0%
#190
やねうら王2016mid V308a
利きなしsmate/qmate搭載。1スレッド
#189
やねうら王2016mid V308
利きなしsmate搭載。1スレッド
194-11-179(20.4% R14.0)
秒読み3000[ms]
50.0%
#190
やねうら王2016mid V308a
利きなしsmate/qmate搭載。1スレッド
#0
silent_majority_V1.1公式
1スレッド
59-1-59(53.7% R0.0)
魔女公式とほぼ互角。assertなしにしてPGOかけると+R30ぐらいなのかな。
■ 2016/06/17 V3.07
・
> && pos.see(make_move(move_to(move), move_from(move))) < VALUE_ZERO)
このSEE値、ちゃんと自分側から見た値が返るのか?
→ 返っていない。手番側ではなく、最初に動かす駒側の手番として考えるべき。
+ stm = is_drop(m) ? sideToMove : color_of(piece_on(move_from(m)));
+ // 相手番(stm側の攻撃駒を列挙していく)
+ stm = ~stm;
さらにこうかな?
→ 修正したのでV3.03aと0.1秒対戦
秒読み100[ms]
48.4%
#188
やねうら王2016mid V307
futility marginテスト。1スレッド
#184
やねうら王2016mid V303a
0.5手延長, mateなし。1スレッド
248-6-264(77.4% R-10.9)
特にバグっていないようだが、強くもなってなさげ…?
・これで魔女と5秒で対戦させておく。
・futility marginのテスト
return Value(d * (90 + param1*27) );
秒読み5000[ms]
34.7% 33.0% 31.3% 29.5% 23.1%
#188
やねうら王2016mid V307
futility marginテスト。1スレッド
#0
silent_majority_V1.1公式
1スレッド
105-8-198(100.0% R-110.2) 97-8-197(100.0% R-123.1) 95-13-209(100.0% R-137.0) 92-10-220(100.0% R-151.5) 63-9-210(100.0% R-209.2)
やはり、そうか…。
評価関数が同じで探索部が近いから、自己対戦成績に近い結果になるはずで、
自己対戦のときも短い時間と長い時間とでfutilityなどは相関があったので、納得の結果。
V3.07a
・futlity pruningの前提depthも5..7で1手10秒で試す
// && depth < PARAM_FUTILITY_RETURN_DEPTH * ONE_PLY
&& depth < (param1 + 5) * ONE_PLY
秒読み5000[ms]
37.7% 34.0% 32.7%
#188
やねうら王2016mid V307a
futility前提depthテスト。1スレッド
#0
silent_majority_V1.1公式
1スレッド
84-11-139(100.0% R-87.5) 72-8-140(100.0% R-115.5) 48-9-99(100.0% R-125.8)
これも1手5秒の持ち時間ではやはりdepth = 5がベストのようだ。長い時間ではわからないが。
0.1秒でやったときと似た結果だと言える。
■ 2016/06/17 V3.06
・MovePickerのkillers、COUNTER_MOVEにしないと下位16bitしか入ってなくて
killer、除外できてなかった。なんだこれ。そら弱くなるわ…。
これで再度futilityのチェックを行う。
・千日手の検出等を、静止探索でやるのはコスト的に無駄なのでは…。これ結構重い気がする。
// 連続王手による千日手、および通常の千日手、優等局面・劣等局面。
// 連続王手による千日手に対してdraw_value()は、詰みのスコアを返すので、rootからの手数を考慮したスコアに変換する必要がある。
// そこで、value_from_tt()で変換してから返すのが正解。
- auto draw_type = pos.is_repetition();
- if (draw_type != REPETITION_NONE)
- return value_from_tt(draw_value(draw_type, pos.side_to_move()),ss->ply);
→ やねうら王 classic-tceにもこの修正を反映させる。
・killer、非適用になったときに、そのあとのquietsの指し手から除外してなかった。
// 今回移動させる駒種が一致するかを確認する。
// このチェックにより先手/後手の指し手であることが担保される。
if (move32 != make_move32(move))
{
+ // このkiller、非適用なのであとでquietsのときに除外されると困るからnullを書き込んでおく。
+ *((Move32*)currentMoves - 1) = 0;
break;
}
上のひどいバグだな…。V3.03aとテスト。
秒読み500[ms]
49.1%
#187
やねうら王2016mid V306
futility marginテスト。1スレッド
#184
やねうら王2016mid V303a
0.5手延長, mateなし。1スレッド
104-7-108(63.4% R-6.6)
こんなに致命的なバグを取ったのに、少し負け越した。まあ、短い時間ではあまり関係ないのだろう…。
■ 2016/06/16 V3.05
・depthボーナスおかしくないか?
(ss - 2)->counterMoves->update(prevPc, prevSq, -bonus - 2 * (depth + 1) / ONE_PLY - 1);
depth + 1って、ONE_PLY = 2のときこれでいいのだろうか..
(ss - 2)->counterMoves->update(prevPc, prevSq, -bonus - 2 * (depth + ONE_PLY) / ONE_PLY - 1);
こうが正しい気もするのだが..
・assertなし、利きなし、mate1plyなし
===========================
Total time (ms) : 113506
Nodes searched : 78131111
Nodes/second : 688343
遅すぎ。仮想環境だからか…。にしても遅いな…。
・futility marginのテスト
return Value(d * (90 + param1*27) );
長い時間でパラメーター再考。
param1 = 0..4
3秒でテスト。
・参考記録
秒読み3000[ms]
36.8% 39.1% 36.8% 28.3% 31.3%
#186
やねうら王2016mid V305
futility marginテスト。1スレッド
#0
silent_majority_V1.1公式
1スレッド
56-4-96(100.0% R-93.6) 59-5-92(99.7% R-77.2) 56-4-96(100.0% R-93.6) 43-4-109(100.0% R-161.6) 47-5-103(100.0% R-136.3)
■ 2016/06/16 V3.04
・静止探索のrecap、5までに変更。
- DEPTH_QS_RECAPTURES = -3*(int)ONE_PLY,
+ DEPTH_QS_RECAPTURES = -5*(int)ONE_PLY,
・evasion、LVA通したほうがいいような…。
if (pos.capture(m))
m.value = (Value)Eval::PieceValueCapture[pos.piece_on(move_to(m))]
- - Value(type_of(pos.moved_piece_before(m))) + HistoryStats::Max;
+ - Value(LVA(type_of(pos.moved_piece_before(m)))) + HistoryStats::Max;
・ここ、prevPcだわ。間違えてた。駒打ちのときに違ってくる。
if ((ss - 2)->counterMoves)
- (ss - 2)->counterMoves->update(pos.piece_on(prevSq), prevSq, -bonus - 2 * (depth + 1) / ONE_PLY - 1);
+ (ss - 2)->counterMoves->update(prevPc, prevSq, -bonus - 2 * (depth + 1) / ONE_PLY - 1);
・どの探索部でもすべての評価関数が使えるように抽象化。
void evaluate_with_no_return(const Position& pos);
を追加。
秒読み1000[ms]
45.7%
#185
やねうら王2016mid V304
オーダリング改善, mateなし。1スレッド
#184
やねうら王2016mid V303a
0.5手延長, mateなし。1スレッド
134-8-159(93.6% R-29.7)
なんか弱くなっとる。よく考える。
■ 2016/06/16 V3.03
・moveCount == 1(置換表)の指し手、必ず延長したほうがいいな。YSSの0.5手延長と同じ。
// 王手となる指し手でSEE >= 0であれば残り探索深さに1手分だけ足す。
if (givesCheck
+ && (moveCount == 1
→ これ、Stockfishでなんでやってなかったんだろう。はてはて。
・popcnt8()とか使わないから削除
・popcnt16()
// popcount16() counts the non-zero bits using SWAR-Popcount algorithm
unsigned popcount16(unsigned u) {
u -= (u >> 1) & 0x5555U;
u = ((u >> 2) & 0x3333U) + (u & 0x3333U);
u = ((u >> 4) + u) & 0x0F0FU;
return (u * 0x0101U) >> 8;
}
これも使わないから要らないや。
・bsf、テーブル使うと速いのか?
// De Bruijn sequences. See chessprogramming.wikispaces.com/BitScan
return BSFTable[(b * 0x3F79D71B4CB0A89ULL) >> 58];
みたいな?遅そう..。bsf使えない環境向けだな。
秒読み5000[ms]
36.8%
#183
やねうら王2016mid V303
0.5手延長, 1スレッド
#0
silent_majority_V1.1公式
1スレッド
25-0-43(99.0% R-94.2)
V3.03a mate1plyなし、利きなし。
秒読み10000[ms]
29.2%
#184
やねうら王2016mid V303a
0.5手延長, mateなし。1スレッド
#0
silent_majority_V1.1公式
1スレッド
33-2-80(100.0% R-153.8)
なんか弱くなった気がする。おかしい。
秒読み1000[ms]
46.2%
#184
やねうら王2016mid V303a
0.5手延長, mateなし。1スレッド
#180
やねうら王2016mid V299c
search、魔女化(), 1スレッド
72-6-84(85.1% R-26.8)
秒読み3000[ms]
47.5%
#184
やねうら王2016mid V303a
0.5手延長, mateなし。1スレッド
#180
やねうら王2016mid V299c
search、魔女化(), 1スレッド
201-12-222(85.8% R-17.3)
なんか弱くなってる感。
■ 2016/06/16 V3.02
・Limits.depthだけ回るとき、Threads.main()->rootDepthと比較すればいいのか..そうか..
・利きあり MATE1PLYあり。静止探索でのmate1plyなし。
秒読み20000[ms]
29.9%
#181
やねうら王2016mid V301
MovePickerバグ修正, 1スレッド
#0
silent_majority_V1.1公式
1スレッド
107-15-251(100.0% R-148.1)
まあ、こんなものなのか…。静止探索でのmate1plyありにして20秒で。
秒読み20000[ms]
26.8%
#182
やねうら王2016mid V301a
MovePickerバグ修正、Qmateあり, 1スレッド
#0
silent_majority_V1.1公式
1スレッド
56-13-153(100.0% R-174.6)
■ 2016/06/16 V3.01
・LazySMPにおいてinsert_pv_in_tt()は意味がないらしい。
// 探索中に置換表のPV lineを破壊した可能性があるので、PVを置換表に
// 書き戻しておいたほうが良い。(PV lineが一番価値があるので)
for (size_t i = 0; i <= PVIdx; ++i)
rootMoves[i].insert_pv_in_tt(rootPos);
→ 削除。(全エンジン共通)
・StockfishのLazySMP、バグってる。
if (!mainThread)
- break;
+ continue;
MultiPVのとき、mainThread以外が2番目以降のMultiPVの指し手を読まずに
次のiterationに行ってしまっていた。
・Stockfishの最新のimprovingFactorに変更する。
・MovePickerで
// ※ これ、指し手の数が多い場合、AVXを使って一気に削除しておいたほうが良いのでは..
if ( move != ttMove
- && move != killers[0]
- && move != killers[1]
- && move != killers[2])
+ && move != (Move)killers[0]
+ && move != (Move)killers[1]
+ && move != (Move)killers[2])
return move;
このとき、killerが32bit化しているときに一致せずに
重複して同じ指し手を調べていた。
・これで1手20秒で魔女公式と対局させておく。
■ 2016/06/14 V3.00
・利きを用いない1手詰め判定ルーチンを用意する。(やねうら王2014からporting)
extra/mate1ply_with_effect.cpp
extra/mate1ply_without_effect.cpp
・MATE_1PLY → USE_MATE_1PLYに名前変更。
extra/mate1ply_without_effect.cpp
→ コンパイルエラー218個。死にそう..
→ 205[16:10]..189[16:21]..181[16:28]..165[16:38]..休憩。
・利きのない一手詰めの移植だけで丸一日かかりそう..こりゃ大変だ。
・Position::pinned_piece(Color,Square avoidSq)みたいなの必要なので追加。
→ 追加した。
■ 2016/06/14 V2.99
・MovePickerのボーナス値、調整。
・FutilityMoveCounts、ONE_PLYで割るの忘れていた。修正。
bool moveCountPruning = depth < 16 * ONE_PLY
- && moveCount >= FutilityMoveCounts[improving][depth];
+ && moveCount >= FutilityMoveCounts[improving][depth/ONE_PLY];
・V2.90(基準用)と対戦させる。
rtime 500[ms]
54.8%
#177
やねうら王2016mid V299
search、魔女化(), 1スレッド
#171
やねうら王2016mid V290基準用
Apery(WCSC26) evaluate(), 1スレッド
161-6-133(4.5% R33.2)
rtime 1000[ms]
46.7%
#177
やねうら王2016mid V299
search、魔女化(), 1スレッド
#171
やねうら王2016mid V290基準用
Apery(WCSC26) evaluate(), 1スレッド
56-3-64(79.4% R-23.2)
弱い…?魔女とはどうか。
秒読み1500[ms]
55.2%
#177
やねうら王2016mid V299
search、魔女化(), 1スレッド
#0
silent_majority_V1.1公式
1スレッド
100-3-81(6.8% R36.6)
1.5秒だと勝ち越す。
秒読み5000[ms]
32.6%
#177
やねうら王2016mid V299
search、魔女化(), 1スレッド
#0
silent_majority_V1.1公式
1スレッド
30-1-62(100.0% R-126.1)
だいぶ負け越した。singular extensionの前提depthを10→8に変更する。
V2.99a
秒読み5000[ms]
40.8%
#178
やねうら王2016mid V299a
search、魔女化(), 1スレッド
#0
silent_majority_V1.1公式
1スレッド
53-1-77(98.6% R-64.9)
だいぶ良くなった。
V2.99b
- PARAM_DEFINE PARAM_QUIET_SEARCH_COUNT = 72;
+ PARAM_DEFINE PARAM_QUIET_SEARCH_COUNT = 64;
こう変えて、また5秒で回しておく。
秒読み5000[ms]
46.6%
#179
やねうら王2016mid V299b
search、魔女化(), 1スレッド
#0
silent_majority_V1.1公式
1スレッド
48-1-55(78.5% R-23.6)
だいぶ近づいてきた。10秒で回してみる。
魔女相手に長い持ち時間で各種パラメーターをチューニングするほうが良いかも知れない。
秒読み10000[ms]
29.6%
#179
やねうら王2016mid V299b
search、魔女化(), 1スレッド
#0
silent_majority_V1.1公式
1スレッド
21-2-50(100.0% R-150.7)
10秒だとひどいことになった。やる気なくした。
この状態で、1手詰めと利きの更新をオフにしてどれくらいの勝率になるのか計測する。
持ち時間を増やしたときに勝率の差が開くのは良くないチューニング。
つまりは通常探索での1手詰めはあったほうがいい可能性が。
V2.99c
秒読み5000[ms]
38.7%
#180
やねうら王2016mid V299c
search、魔女化(), 1スレッド
#0
silent_majority_V1.1公式
1スレッド
128-14-203(100.0% R-80.1)
---
秒読み10000[ms]
33.5%
#180
やねうら王2016mid V299c
search、魔女化(), 1スレッド
#0
silent_majority_V1.1公式
1スレッド
89-13-177(100.0% R-119.4)
---
秒読み20000[ms]
33.3%
#180
やねうら王2016mid V299c
search、魔女化(), 1スレッド
#0
silent_majority_V1.1公式
1スレッド
56-9-112(100.0% R-120.4)
---
秒読み40000[ms]
31.7%
#180
やねうら王2016mid V299c
search、魔女化(), 1スレッド
#0
silent_majority_V1.1公式
1スレッド
73-19-157(100.0% R-133.0)
持ち時間が増えると勝率の差が広がっていく性質がある。
2.99b、40秒での勝率を調べておく。
秒読み40000[ms]
39.6%
#179
やねうら王2016mid V299b
search、魔女化(), 1スレッド
#0
silent_majority_V1.1公式
1スレッド
129-23-197(100.0% R-73.6)
40秒でそんなに弱くはない。静止探索での1手詰めを呼ばないように
すれば(利きの更新コストがないならば)、おそらく-R50ぐらい。
assertを外して、PGOなどをかければほぼ互角かも。
20秒での勝率も調べておく。
秒読み20000[ms]
39.8%
#179
やねうら王2016mid V299b
search、魔女化(), 1スレッド
#0
silent_majority_V1.1公式
1スレッド
47-5-71(99.0% R-71.7)
対戦数は少ないが、そんなに変わらないという印象。
■ 2016/06/13 V2.98
・探索部、見直す。
・FutilityMoveCounts、ONE*PLY掛けると配列が大きくなるので、やめたほうがいいのでは..
・静止探索のMovePicker、Stockfishの最新のようにhistory渡すのやめる。
・MovePicker、探索部ごとに変えられるようにextraに分離する。
extra/move_picker_2015.h
extra/move_picker_2016Q2.h
…
・捕獲から逃れる指し手のreduction軽減。
・counter moveのボーナス等、変更。
意外と大改造になった。
・Stockfish7の新しいhistoryとかcounter move、効率良さそう。
確かに長い時間で効果が出そうな感じ…。
・bench完走したので、とりあえず良し。
・とりあえず、魔女と1手10秒で対局させておく。
34.8%
#176
やねうら王2016mid V298
search、魔女化(), 1スレッド、10秒設定
#0
silent_majority_V1.1公式
1スレッド、10秒設定
188-29-352(100.0% R-109.0)
以前より弱くなった。まだ何かバグっているのだと思われる。
■ 2016/06/13 V2.97
・MovePicker、よく考える。
いま、Pieceの金の位置が角、飛車の後ろにあるからLVA_Table用意したほうがいいのか…。
以下のように変更。
// MVV-LVAに、歩の成りに加点する形にしておく。
m.value = (pawn_promo ? (Value)(Eval::GoldValue - Eval::PawnValue) : VALUE_ZERO)
+ (Value)Eval::PieceValueCapture[pos.piece_on(move_to(m))]
- LVA(pt);
・MovePickerにコメント少し追加。
■ 2016/06/13 V2.96
・search()を魔女とくらべてみる。
・check_timeを呼び出す周期、もう少し細かくする。
思ったよりnps出ないので、20000 nodeに1回だと0.1秒程度の誤差がでかねないようだ。
→ ここで0.1秒も誤差が出ると、NetworkDelayで0.1秒損をする。
ここをシビアにして、代わりにNetworkDelay,NetworkDelay2のデフォルト値を-80[ms]しておく。
・魔女のprobe()のあとのコード、おかしくないかな。
ttScore = (tte != nullptr ? scoreFromTT(tte->score(), ss->ply) : ScoreNone);
この置換表、entryがないときも tte != nullptr なのでは..
ttScore = (ttHit ? scoreFromTT(tte->score(), ss->ply) : ScoreNone);
これが正しい気がする。
・魔女の1手詰めのあと格納している値がおかしい気がする。
ss->staticEval = bestScore = mateIn(ss->ply);
次のnodeで指し手がなくなって詰むのだから、mateIn(ss->ply +1)のような。
ss->plyを0からカウントしているからこれで合ってるとか?
・魔女の1手詰めを見つけたときに置換表に格納するときのdepth、DEPTH_MAXのほうが
良いような。
・魔女のほう、Search::StackにcounterMovesがある。このへん、新しいStockfishなのか…そうか。
・魔女のほう、パラメーターはStockfishのものから未調整に近いので、これでいいのだとしたら、
singularなどもやはりStockfishの値に戻したほうがいいのかも知れない。
Stockfishのsingularは、やり過ぎだと思っていたのだが、そうでもないのだろう。
・魔女がAperyに長い時間でかなり勝ち越すのは、singular extensionを(本家Stockfishのパラメーターそのままにして将棋にしてみると)
激しくやっているせいで、特殊な状態のような気はする。しかしApery亜種が大量にいる状況では、それが奏功する。
かならずしもいいとは言えない調整だが、singular extension、わりと異種ソフトに対してもわりと妥当な延長である可能性はある。
・短い持ち時間でパラメーターを自動調整するとsingularのパラメーターは縮小される方向(singularを使わない方向)に一方的に向かうが、
これは良くない調整だと思う。singular絡みのパラメーター、持ち時間を大きくしないと調整は危険。
46.8%
#175
やねうら王2016mid V296
search、魔女化(), 1スレッド、5秒設定
#0
silent_majority_V1.1公式
1スレッド、5秒設定
96-5-109(83.6% R-22.1)
魔女にだいぶ並んできた。-R22はあまり正確な数値ではないだろうけども、これが仮に正確な数値だとしたら
利きの更新で損をしている15%(R30相当)が利いて来ている可能性がある。やねうら王のほうassertを入れてる分、
速度的に損をしているのかも知れないし。
同じ条件で10秒でもやってみる。
39.0%
#175
やねうら王2016mid V296
search、魔女化(), 1スレッド、10秒設定
#0
silent_majority_V1.1公式
1スレッド、10秒設定
105-18-164(100.0% R-77.5)
10秒だとずいぶん差が出るな…。なるほど…。確かに魔女は長い時間に対して強いな。
■ 2016/06/13 V2.95
・qsearch()を魔女化したものと魔女とを対局させてみる。
38.1%
#172
やねうら王2016mid V294
qsearch、魔女化(), 1スレッド、5秒設定
#0
silent_majority_V1.1公式
1スレッド、5秒設定
88-7-143(100.0% R-84.3)
ひどくなった気がする。
利きの更新が重いので、やねうら王の場合、1手詰めは呼び出したほうが得なのか。
利きの更新で15%ぐらい損してて、1手詰め判定は通常探索からしか
呼び出されないので、全体の3%ぐらいしか消費していないとすると
結局、12%ぐらい損してることになって、これがレーティングで言うとたぶん
R25ぐらい。逆に言うと、それ以上魔女と差があるならそれについては
原因をよく調べるべき。
ただ、全く同じ評価関数、かつ、ほぼ同じ探索部なのでわずかなnpsの差が
直接勝敗を分けることはありうると思う。この速度差が、思ったより大きな差
なのではないかなと。
・TTがおかしいのか?
if (!tte[i].key16)
return found = false, &tte[i];
→ これよく見るとこの瞬間にgeneration設定していないから
新しい探索部では、まずい。このバグひどいな…。
→ 修正。
if (!tte[i].key16 || tte[i].key16 == key16)
{
// 1.に対してはこのタイミングでrefresh
// 2.に対してはこのタイミングでgenerationを設定しておいてやる。
tte[i].set_generation(generation8);
return found = (bool)tte[i].key16, &tte[i];
}
→ あれ?よく考えたらsave()でgeneration書き出すので、key16 == 0のときは、ここでやらなくて良いのか。
→ じゃあ問題ないや。
・静止探索での1手詰めは、やはり入れるようにして、
上の修正だけ反映させて、それで以前のバージョンと対局させてみる。
50.4%
#173
やねうら王2016mid V295
qsearch、魔女化(), 1スレッド、0.1秒設定
#162
やねうら王2016mid V290
Apery(WCSC26) evaluate(), 1スレッド、0.1秒設定
290-12-285(40.1% R3.0)
変わっていないか。そうか…。
・結論的には、静止探索での1手詰めの呼び出しは強くなるのか怪しいけど、いまそこが問題ではなさそう。
長い持ち時間において弱くなる原因は通常探索部にありそう。
■ 2016/06/13 V2.94
・開発環境が整理できたので、
Silent Majority V1.1と1スレッド2秒/5秒/10秒対局において同じぐらいの勝率になるところまでチューニングする。
cf.
コンピュータ将棋ソフトウェアの時間制御
http://woodyring.blog.so-net.ne.jp/2016-06-05
woodyringさんの上の記事の内容を引き継いで、長い持ち時間におい
てSilent Majorityの棋力が伸びる原因について深く調べる。
まず2秒設定にてやねうら王V2.92と対局させる。
エンジン設定)
#0
やねうら王2016mid V290
Apery(WCSC26) evaluate(), 1スレッド、2秒設定
YaneuraOu-2016-midV290.exe
go btime 0 wtime 0 byoyomi 2000
setoption name Hash value 256
setoption name Threads value 1
setoption name NetworkDelay value 0
setoption name NetworkDelay2 value 0
#169
silent_majority_V1.1公式
1スレッド、2秒設定
SILENT_MAJORITY_AVX2_x64_V110.exe
go btime 0 wtime 0 byoyomi 2000
setoption name Hash value 256
setoption name USI_Hash value 256
setoption name Threads value 1
思考コマンド
> go btime 0 wtime 0 byoyomi 2000
49.7%
#169
silent_majority_V1.1公式
1スレッド、2秒設定
#0
やねうら王2016mid V290
Apery(WCSC26) evaluate(), 1スレッド、2秒設定
281-31-284(56.7% R-1.8)
→ ほぼ互角。
> go btime 0 wtime 0 byoyomi 5000
58.9%
#169
silent_majority_V1.1公式
1スレッド、5秒設定
#0
やねうら王2016mid V290
Apery(WCSC26) evaluate(), 1スレッド、5秒設定
312-19-218(0.0% R62.3)
→ だいぶ負け越した
2秒→5秒にして負け越すようになるということは、
singular extension絡みなどでないなら、これは
短い持ち時間においては終盤絡みで逆転して勝っているだけだと考えられる。
1手詰めが怪しいが、魔女のほうもmateMoveIn1Ply()は呼び出している模様。
やねうら王のほうは、利きの更新で損しているのかも知れない。
・短い持ち時間での対局のときに、リソース削減のためにHashを極力小さく設定しているが
これにより、CPU cacheが少しでも汚染されるようなチューニング(例:nodeのquietの指し手バッファ=64を大きな値に変更するなど)
に対して極めてパフォーマンスが低下する傾向があり、間違ったチューニングとなる可能性がある。
・魔女とqsearch()を比較してみる。
・やねうら王側、宣言勝ちの判定をqsearch()でやっているのがどうなのか。
→ まあいいか。
・やねうら王側、null moveのときの見積りにTempoを加算するように変更。
- : -(ss-1)->staticEval;
+ : -(ss-1)->staticEval + 2 * Tempo;
・やねうら王側、qsearch()では1手詰め呼び出さないように変更。
・やねうら王側、evasionPrunableのフラグ、歩の成りは対象外とする。
bool evasionPrunable = InCheck
&& bestValue > VALUE_MATED_IN_MAX_PLY
- && !pos.capture(move);
+ && !pos.capture_or_pawn_promotion(move);
・魔女側、qsearch()で用いているMovePicker、Stockfishの少し古いバージョンのようだ。
これは関係あるのか?ないのか?
0.1秒で前バージョンと対局。
45.3%
#170
やねうら王2016mid V294
qsearch、魔女化(), 1スレッド、0.1秒設定
#0
やねうら王2016mid V290
Apery(WCSC26) evaluate(), 1スレッド、0.1設定
228-12-275(98.4% R-32.6)
50.0%
#171
やねうら王2016mid V294
qsearch、魔女化(), 1スレッド、5秒設定
#0
やねうら王2016mid V290
Apery(WCSC26) evaluate(), 1スレッド、5設定
104-13-104(52.8% R0.0)
→ 長い持ち時間においては静止探索での1手詰め判定の効果が
相対的に薄れるということなのだと思う。
静止探索中に1手詰めを見つけたところでそれによって
(通常探索時に見つけた1手詰めとは異なり)探索すべきnode数が減るという
効果に乏しく、singular extensionのような効果しかないから。
1手詰め判定を通常探索でしか呼び出さないなら、現状のように
利きを評価関数で使わないのに利きの更新を行うと、そのコスト面において
魔女とくらべてかなり損をしてしまう。利きを用いない1手詰め判定関数を
作成して、かつ、利きの更新を用いないのが得策か。
■ 2016/06/10 V2.93
・魔女が宣言勝ちした局面、やねうら王の自己対戦フレームワークで認められなかった。おかしい。
4<Error : illigal move , move = win , engine name = engines\SILENT_MAJORITY_AVX2_x64_V110.exe
4< □ □ □ □ □ □ □ 飛 □
4< 玉 と □ 馬 □ □ 圭 □ □
4< 圭 と と と □ 歩 と □ □
4< □ □ □ □ □ □ □ 全 □
4< □ □^龍 □ □^と □ 金 □
4< □ □ □^圭^圭^馬 □ □ □
4< □ □ □ □ □ □ □^と^杏
4< □ □ □ □ □ □ □^全^玉
4< □ □ □ □ □ □ □ □ □
4<先手 手駒 :
歩2 香3 銀2 金3 , 後手 手駒 : 歩8
4<手番 = 先手
4<sfen 7R1/K+P1+B2+N2/+N+P+P+P1P+P2/7+S1/2+r2+p1G1/3+n+n+b3/7+p+l/7+sk/9 b 2P3L2S3G8p 243
→ 入玉判定のときに手駒の金を足してなかった。修正した。
- + (hand_count(h,BISHOP) + hand_count(h,ROOK)) * 5;
+ + hand_count(h,GOLD) + (hand_count(h,BISHOP) + hand_count(h,ROOK)) * 5;
■ 2016/06/10 V2.92
・null moveのときの評価値、きちんと計算する。
・evaluate_nullmove(pos)追加。
(ss - 1)->currentMove != MOVE_NULL ? evaluate(pos)
- : -(ss - 1)->staticEval;
+ : -(ss - 1)->staticEval + 70;
V2.92
49.1%
#166
やねうら王2016mid V292
null move後のevaluate()修正, 1スレッド、0.1秒設定
#0
やねうら王2016mid V290
Apery(WCSC26) evaluate(), 1スレッド、0.1秒設定
540-15-560(72.7% R-6.3)
+ : evaluate_nullmove(pos);
V2.92a
48.5%
#167
やねうら王2016mid V292a
null move後のevaluate()修正, 1スレッド、0.1秒設定
#0
やねうら王2016mid V290
Apery(WCSC26) evaluate(), 1スレッド、0.1秒設定
610-24-648(85.8% R-10.5)
■ 2016/06/04~2016/06/05 V2.91
・やねうら王2016 Midの探索パラメーターの自動調整。
・解説.txtに他ソフトとの対局時の設定などを追記。
・パラメーター調整後。
47.6%
#162
やねうら王2016mid V290
Apery(WCSC26) evaluate(), 1スレッド、0.1秒設定
#0
やねうら王2016mid V290 master
Apery(WCSC26) evaluate(), 1スレッド、0.1秒設定
1122-46-1236(99.1% R-16.8)
→ 弱くなるのか…そうか…。
■ 2016/06/01~2016/06/02 V2.90
・Apery(WCSC26)の評価関数の読み込み作業。
SILENT MAJORITYの作者の実装を参考にさせていただきました。
https://github.com/Jangja/YaneuraOu/
・EVAL_KPPT (手番つきKPP)実装
evaluate_kppt.cpp
extra/eval_sum.h
eval_stat()実装完了。
64.6%
#162
やねうら王2016mid V290
Apery(WCSC26) evaluate(), 1スレッド、0.1秒設定
#0
やねうら王2016mid V278master
2016mid first version, 1スレッド、0.1秒設定
858-11-471(0.0% R104.2)
===========================
Total time (ms) : 66637
Nodes searched : 42085583
Nodes/second : 631564
・評価関数の載せ替えにより、
+R105ぐらい。R3400弱?
nps 730k→630k , 14%ぐらいダウン。
探索パラメーター未調整。
利きの更新をやっているのがマイナスになっているかも。(3手詰めなどを実装して利きの更新コストを回収すべきか)
魔女より少し弱いのかも。(未検証)
このあと
1) この評価関数のために探索パラメーターを調整する。
2) 魔女と対戦させてみる。
・以前のparameters.h
PARAM_FUTILITY_MARGIN_ALPHA : 87 → 87(50.00%) : ←←(値81,勝率49.25%,1440局,有意68.84%) ,←(値84,勝率49.15%,1440局,有意71.06%) ,→(値90,勝率49.52%,1440局,有意62.78%) ,→→(値93,勝率49.52%,1440局,有意62.82%) ,
PARAM_QUIET_SEARCH_COUNT : 64 → 72(55.05%) : ←←(値56,勝率51.07%,1440局,有意24.62%) ,←(値60,勝率50.27%,1440局,有意42.23%) ,→(値68,勝率50.43%,1440局,有意38.46%) ,→→(値72,勝率55.05%,480局,有意1.30%) ,
PARAM_RAZORING_ALPHA : 16 → 16(50.00%) : ←←(値12,勝率50.27%,1440局,有意42.22%) ,←(値14,勝率49.72%,2880局,有意58.44%) ,→(値18,勝率50.69%,1440局,有意32.37%) ,→→(値20,勝率48.82%,1440局,有意77.39%) ,
PARAM_RAZORING_MARGIN : 448 → 448(50.00%) : ←←(値384,勝率49.73%,1440局,有意57.74%) ,←(値416,勝率49.30%,1440局,有意67.68%) ,→(値480,勝率49.57%,1440局,有意61.59%) ,→→(値512,勝率50.16%,1440局,有意44.80%) ,
PARAM_PRUNING_BY_HISTORY_DEPTH : 4 → 4(50.00%) : ←←(値8,勝率0.00%,0局,有意50.00%) ,←(値8,勝率45.11%,1440局,有意99.88%) ,→(値8,勝率48.94%,1440局,有意75.28%) ,→→(値8,勝率43.19%,480局,有意99.87%) ,
PARAM_REDUCTION_BY_HISTORY : 14724 → 14724(50.00%) : ←←(値14212,勝率46.27%,480局,有意95.18%) ,←(値14468,勝率51.28%,1440局,有意20.74%) ,→(値14980,勝率47.74%,1440局,有意92.08%) ,→→(値15236,勝率50.32%,2880局,有意40.51%) ,
PARAM_SINGULAR_SEARCH_DEPTH : 128 → 64(53.94%) : ←←(値64,勝率53.94%,624局,有意3.96%) ,←(値96,勝率46.20%,480局,有意95.54%) ,→(値160,勝率50.85%,1440局,有意28.96%) ,→→(値192,勝率49.26%,1440局,有意68.75%) ,
PARAM_SINGULAR_MARGIN : 7 → 6(52.27%) : ←←(値5,勝率49.10%,1872局,有意73.59%) ,←(値6,勝率52.27%,1872局,有意5.71%) ,→(値8,勝率49.80%,1872局,有意55.68%) ,→→(値9,勝率51.97%,1872局,有意8.45%) ,
PARAM_SINGULAR_EXTENSION_DEPTH : 10 → 8(53.44%) : ←←(値8,勝率53.44%,624局,有意4.08%) ,←(値9,勝率49.96%,1872局,有意51.14%) ,→(値11,勝率49.06%,1872局,有意74.51%) ,→→(値12,勝率49.63%,1872局,有意60.13%) ,
PARAM_PROBCUT_DEPTH : 5 → 5(50.00%) : ←←(値3,勝率39.35%,624局,有意100.00%) ,←(値4,勝率49.96%,1872局,有意51.14%) ,→(値6,勝率46.54%,1872局,有意99.20%) ,→→(値7,勝率45.23%,624局,有意99.21%) ,
PARAM_NULL_MOVE_DYNAMIC_BETA : 58 → 64(53.36%) : ←←(値52,勝率51.11%,1872局,有意21.99%) ,←(値55,勝率50.41%,1872局,有意38.74%) ,→(値61,勝率52.29%,1872局,有意5.47%) ,→→(値64,勝率53.36%,624局,有意4.46%) ,
PARAM_NULL_MOVE_RETURN_DEPTH : 12 → 11(51.58%) : ←←(値10,勝率49.84%,1872局,有意54.55%) ,←(値10,勝率51.58%,3744局,有意8.77%) ,→(値10,勝率51.11%,1872局,有意21.99%) ,→→(値10,勝率0.00%,0局,有意50.00%) ,
PARAM_NULL_MOVE_DYNAMIC_ALPHA : 871 → 871(50.00%) : ←←(値839,勝率49.22%,1872局,有意70.68%) ,←(値855,勝率49.10%,1872局,有意73.53%) ,→(値887,勝率49.96%,1872局,有意51.14%) ,→→(値903,勝率46.32%,624局,有意96.87%) ,
PARAM_FUTILITY_AT_PARENT_NODE_SEE_DEPTH : 2 → 2(50.00%) : ←←(値2,勝率0.00%,0局,有意50.00%) ,←(値2,勝率0.00%,0局,有意50.00%) ,→(値3,勝率50.00%,1872局,有意50.00%) ,→→(値4,勝率50.55%,3744局,有意31.99%) ,
PARAM_FUTILITY_AT_PARENT_NODE_MARGIN : 173 → 170(52.73%) : ←←(値167,勝率49.10%,3744局,有意77.95%) ,←(値170,勝率52.73%,3744局,有意0.97%) ,→(値176,勝率47.78%,1872局,有意93.91%) ,→→(値179,勝率50.16%,1872局,有意45.46%) ,
PARAM_FUTILITY_AT_PARENT_NODE_DEPTH : 7 → 8(52.15%) : ←←(値5,勝率45.79%,624局,有意98.35%) ,←(値6,勝率50.74%,1872局,有意30.27%) ,→(値8,勝率52.15%,1872局,有意6.76%) ,→→(値9,勝率50.16%,1872局,有意45.43%) ,
PARAM_FUTILITY_MARGIN_QUIET : 129 → 129(50.00%) : ←←(値123,勝率46.64%,624局,有意95.54%) ,←(値126,勝率49.10%,1872局,有意73.59%) ,→(値132,勝率50.25%,1872局,有意43.15%) ,→→(値135,勝率49.80%,1872局,有意55.68%) ,
PARAM_FUTILITY_RETURN_DEPTH : 5 → 5(50.00%) : ←←(値5,勝率0.00%,0局,有意50.00%) ,←(値5,勝率0.00%,0局,有意50.00%) ,→(値6,勝率50.20%,1872局,有意44.32%) ,→→(値7,勝率49.55%,1872局,有意62.39%) ,
PARAM_FUTILITY_MARGIN_ALPHA : 93 → 87(53.42%) : ←←(値87,勝率53.42%,1872局,有意0.86%) ,←(値90,勝率50.00%,1872局,有意50.00%) ,→(値96,勝率50.08%,1872局,有意47.72%) ,→→(値99,勝率47.19%,1872局,有意97.56%) ,
PARAM_RAZORING_ALPHA : 14 → 16(51.97%) : ←←(値10,勝率49.35%,1872局,有意67.61%) ,←(値12,勝率51.89%,1872局,有意9.37%) ,→(値16,勝率51.97%,1872局,有意8.45%) ,→→(値18,勝率46.18%,624局,有意97.36%) ,
PARAM_RAZORING_MARGIN : 448 → 448(50.00%) : ←←(値384,勝率50.77%,3744局,有意25.62%) ,←(値416,勝率51.01%,3744局,有意19.37%) ,→(値480,勝率46.57%,624局,有意95.90%) ,→→(値512,勝率49.02%,1872局,有意75.38%) ,
PARAM_REDUCTION_BY_HISTORY : 14724 → 14724(50.00%) : ←←(値14212,勝率51.11%,1872局,有意21.99%) ,←(値14468,勝率50.82%,1872局,有意28.36%) ,→(値14980,勝率47.55%,3744局,有意98.22%) ,→→(値15236,勝率51.19%,1872局,有意20.29%) ,
PARAM_SINGULAR_MARGIN : 7 → 7(50.00%) : ←←(値5,勝率49.51%,1872局,有意63.43%) ,←(値6,勝率50.94%,1872局,有意25.57%) ,→(値8,勝率48.72%,3744局,有意86.37%) ,→→(値9,勝率50.94%,1872局,有意25.52%) ,
PARAM_NULL_MOVE_DYNAMIC_BETA : 58 → 58(50.00%) : ←←(値52,勝率50.41%,1872局,有意38.71%) ,←(値55,勝率47.02%,1872局,有意98.16%) ,→(値61,勝率50.49%,1872局,有意36.59%) ,→→(値64,勝率50.69%,1872局,有意31.36%) ,
PARAM_NULL_MOVE_DYNAMIC_ALPHA : 855 → 871(51.92%) : ←←(値823,勝率50.49%,1872局,有意36.58%) ,←(値839,勝率47.42%,1872局,有意96.42%) ,→(値871,勝率51.92%,1872局,有意8.98%) ,→→(値887,勝率51.15%,1872局,有意21.12%) ,
PARAM_FUTILITY_AT_PARENT_NODE_MARGIN : 170 → 173(53.72%) : ←←(値164,勝率49.92%,1872局,有意52.28%) ,←(値167,勝率46.72%,624局,有意95.16%) ,→(値173,勝率53.72%,624局,有意3.07%) ,→→(値176,勝率51.99%,1872局,有意8.11%) ,
PARAM_FUTILITY_MARGIN_QUIET : 123 → 129(52.55%) : ←←(値117,勝率50.78%,1872局,有意29.32%) ,←(値120,勝率50.08%,1872局,有意47.72%) ,→(値126,勝率52.19%,1872局,有意6.39%) ,→→(値129,勝率52.55%,3744局,有意1.42%) ,
PARAM_FUTILITY_MARGIN_ALPHA : 93 → 93(50.00%) : ←←(値87,勝率49.92%,1872局,有意52.29%) ,←(値90,勝率46.42%,624局,有意96.54%) ,→(値96,勝率50.29%,1872局,有意42.07%) ,→→(値99,勝率48.82%,1872局,有意79.61%) ,
PARAM_RAZORING_ALPHA : 16 → 14(55.15%) : ←←(値12,勝率48.04%,1872局,有意91.51%) ,←(値14,勝率55.15%,624局,有意0.51%) ,→(値18,勝率51.88%,3744局,有意5.36%) ,→→(値20,勝率51.72%,3744局,有意7.05%) ,
PARAM_RAZORING_MARGIN : 448 → 448(50.00%) : ←←(値384,勝率49.75%,1872局,有意56.82%) ,←(値416,勝率50.37%,1872局,有意39.80%) ,→(値480,勝率50.03%,3744局,有意49.07%) ,→→(値512,勝率50.16%,1872局,有意45.44%) ,
PARAM_REDUCTION_BY_HISTORY : 14724 → 14724(50.00%) : ←←(値14212,勝率48.19%,3744局,有意93.88%) ,←(値14468,勝率50.37%,1872局,有意39.84%) ,→(値14980,勝率49.14%,1872局,有意72.64%) ,→→(値15236,勝率48.04%,1872局,有意91.48%) ,
PARAM_SINGULAR_MARGIN : 8 → 7(51.69%) : ←←(値6,勝率48.94%,1872局,有意77.09%) ,←(値7,勝率51.69%,3744局,有意7.41%) ,→(値9,勝率50.16%,1872局,有意45.45%) ,→→(値10,勝率49.71%,1872局,有意57.95%) ,
PARAM_NULL_MOVE_DYNAMIC_BETA : 61 → 58(53.98%) : ←←(値55,勝率48.01%,1872局,有意91.89%) ,←(値58,勝率53.98%,624局,有意2.18%) ,→(値64,勝率52.49%,1872局,有意4.06%) ,→→(値67,勝率51.18%,1872局,有意20.41%) ,
PARAM_NULL_MOVE_DYNAMIC_ALPHA : 823 → 855(53.43%) : ←←(値791,勝率48.47%,3744局,有意90.50%) ,←(値807,勝率52.52%,1872局,有意3.97%) ,→(値839,勝率48.08%,1872局,有意91.03%) ,→→(値855,勝率53.43%,1872局,有意0.82%) ,
PARAM_FUTILITY_AT_PARENT_NODE_MARGIN : 170 → 170(50.00%) : ←←(値164,勝率49.51%,1872局,有意63.40%) ,←(値167,勝率46.15%,624局,有意97.40%) ,→(値173,勝率50.65%,1872局,有意32.40%) ,→→(値176,勝率49.51%,1872局,有意63.45%) ,
PARAM_FUTILITY_MARGIN_QUIET : 123 → 123(50.00%) : ←←(値117,勝率50.63%,3744局,有意29.57%) ,←(値120,勝率48.75%,3744局,有意85.85%) ,→(値126,勝率50.25%,1872局,有意43.18%) ,→→(値129,勝率50.86%,1872局,有意27.41%) ,
PARAM_FUTILITY_MARGIN_ALPHA : 90 → 93(55.95%) : ←←(値84,勝率47.93%,1872局,有意92.70%) ,←(値87,勝率50.53%,1872局,有意35.55%) ,→(値93,勝率55.95%,624局,有意0.14%) ,→→(値96,勝率47.30%,1872局,有意97.06%) ,
PARAM_PRUNING_BY_MOVE_COUNT_DEPTH : 16 → 16(50.00%) : ←←(値14,勝率47.70%,1872局,有意94.57%) ,←(値15,勝率48.98%,1872局,有意76.27%) ,→(値17,勝率49.09%,3744局,有意78.02%) ,→→(値18,勝率51.03%,1872局,有意23.68%) ,
PARAM_QUIET_SEARCH_COUNT : 64 → 64(50.00%) : ←←(値56,勝率47.11%,1872局,有意97.79%) ,←(値60,勝率50.04%,1872局,有意48.86%) ,→(値68,勝率47.76%,1872局,有意94.20%) ,→→(値72,勝率50.12%,1872局,有意46.58%) ,
PARAM_PRUNING_BY_HISTORY_DEPTH : 4 → 4(50.00%) : ←←(値8,勝率0.00%,0局,有意50.00%) ,←(値8,勝率46.47%,624局,有意96.27%) ,→(値8,勝率50.24%,1872局,有意43.21%) ,→→(値8,勝率47.48%,1872局,有意96.15%) ,
PARAM_SINGULAR_SEARCH_DEPTH : 128 → 128(50.00%) : ←←(値64,勝率51.03%,1872局,有意23.68%) ,←(値96,勝率49.06%,1872局,有意74.48%) ,→(値160,勝率50.29%,1872局,有意42.07%) ,→→(値192,勝率51.06%,1872局,有意22.85%) ,
PARAM_SINGULAR_EXTENSION_DEPTH : 10 → 11(52.83%) : ←←(値8,勝率49.67%,1872局,有意59.04%) ,←(値9,勝率50.16%,1872局,有意45.43%) ,→(値11,勝率52.83%,1872局,有意2.33%) ,→→(値12,勝率50.12%,1872局,有意46.58%) ,
PARAM_PROBCUT_DEPTH : 5 → 5(50.00%) : ←←(値3,勝率39.42%,624局,有意100.00%) ,←(値4,勝率49.13%,1872局,有意72.67%) ,→(値6,勝率47.16%,3744局,有意99.25%) ,→→(値7,勝率46.13%,624局,有意97.44%) ,
PARAM_NULL_MOVE_RETURN_DEPTH : 12 → 12(50.00%) : ←←(値10,勝率50.29%,1872局,有意42.05%) ,←(値10,勝率49.84%,1872局,有意54.55%) ,→(値10,勝率50.41%,3744局,有意36.28%) ,→→(値10,勝率0.00%,0局,有意50.00%) ,
PARAM_FUTILITY_AT_PARENT_NODE_SEE_DEPTH : 4 → 2(57.03%) : ←←(値2,勝率57.03%,624局,有意0.02%) ,←(値3,勝率49.63%,1872局,有意60.16%) ,→(値5,勝率47.83%,3744局,有意96.88%) ,→→(値6,勝率46.15%,624局,有意97.40%) ,
PARAM_FUTILITY_AT_PARENT_NODE_DEPTH : 7 → 7(50.00%) : ←←(値5,勝率50.11%,3744局,有意46.28%) ,←(値6,勝率51.09%,3744局,有意17.54%) ,→(値8,勝率49.18%,3744局,有意75.82%) ,→→(値9,勝率48.90%,1872局,有意77.98%) ,
PARAM_FUTILITY_RETURN_DEPTH : 7 → 5(53.43%) : ←←(値5,勝率53.43%,624局,有意4.10%) ,←(値6,勝率50.04%,1872局,有意48.86%) ,→(値8,勝率51.15%,1872局,有意21.14%) ,→→(値9,勝率49.18%,1872局,有意71.67%) ,
PARAM_RAZORING_ALPHA : 16 → 16(50.00%) : ←←(値12,勝率50.98%,1872局,有意24.65%) ,←(値14,勝率48.93%,1872局,有意77.17%) ,→(値18,勝率50.85%,1872局,有意27.46%) ,→→(値20,勝率47.56%,1872局,有意95.66%) ,
PARAM_RAZORING_MARGIN : 512 → 448(53.51%) : ←←(値448,勝率53.51%,624局,有意3.77%) ,←(値480,勝率52.83%,1872局,有意2.41%) ,→(値544,勝率50.69%,1872局,有意31.37%) ,→→(値576,勝率49.84%,1872局,有意54.55%) ,
PARAM_REDUCTION_BY_HISTORY : 14724 → 14724(50.00%) : ←←(値14212,勝率49.26%,1872局,有意69.70%) ,←(値14468,勝率50.57%,1872局,有意34.44%) ,→(値14980,勝率50.04%,1872局,有意48.86%) ,→→(値15236,勝率50.45%,1872局,有意37.67%) ,
PARAM_SINGULAR_MARGIN : 8 → 8(50.00%) : ←←(値6,勝率50.08%,1872局,有意47.72%) ,←(値7,勝率48.08%,1872局,有意91.03%) ,→(値9,勝率51.44%,3744局,有意10.85%) ,→→(値10,勝率51.00%,3744局,有意19.43%) ,
PARAM_NULL_MOVE_DYNAMIC_BETA : 67 → 61(52.12%) : ←←(値61,勝率52.12%,3744局,有意3.45%) ,←(値64,勝率46.25%,624局,有意97.11%) ,→(値70,勝率52.04%,3744局,有意4.00%) ,→→(値73,勝率50.82%,1872局,有意28.39%) ,
PARAM_NULL_MOVE_DYNAMIC_ALPHA : 823 → 823(50.00%) : ←←(値791,勝率50.90%,1872局,有意26.42%) ,←(値807,勝率47.87%,1872局,有意93.17%) ,→(値839,勝率50.00%,1872局,有意50.00%) ,→→(値855,勝率49.92%,1872局,有意52.28%) ,
PARAM_FUTILITY_AT_PARENT_NODE_MARGIN : 170 → 170(50.00%) : ←←(値164,勝率49.47%,1872局,有意64.53%) ,←(値167,勝率50.04%,1872局,有意48.86%) ,→(値173,勝率49.23%,1872局,有意70.62%) ,→→(値176,勝率49.35%,1872局,有意67.61%) ,
PARAM_FUTILITY_MARGIN_QUIET : 123 → 123(50.00%) : ←←(値117,勝率49.47%,1872局,有意64.50%) ,←(値120,勝率49.02%,1872局,有意75.36%) ,→(値126,勝率49.88%,1872局,有意53.41%) ,→→(値129,勝率47.39%,1872局,有意96.63%) ,
PARAM_FUTILITY_MARGIN_ALPHA : 90 → 90(50.00%) : ←←(値84,勝率50.00%,1872局,有意50.00%) ,←(値87,勝率49.22%,1872局,有意70.70%) ,→(値93,勝率46.33%,624局,有意96.85%) ,→→(値96,勝率46.73%,624局,有意95.13%) ,
■ 2016/05/20 V2.89
・evalList、シーケンシャルにしておかないと、ベクトル系の命令が使いにくいのか…。修正。
■ 2016/05/17
・MaxMovesToDrawが256を指定したときに256手目が指されない?
setoption name MaxMovesToDraw value 4
position startpos moves 7g7f 3c3d 2g2f
go btime 1000 wtime 1000 byoyomi 0
指せている気が?
floodgateでの設定に問題があるのだと思うので、解説.txtに追記。
■ 2016/05/11 V2.88
・tanuki-さんのlocal-game-serverのプロセスの終了まわりのコードをmerge。
■ 2016/05/06 V2.87
・定跡ファイルの読み込みは
void Search::clear()
のほうでやらないと、HDDが遅いPCだとタイムアウトになりかねない。修正。
■ 2016/05/03 V2.86
・ehashで速くなるかも。
cf.
http://yaneuraou.yaneu.com/2016/04/16/%E3%82%84%E3%81%AD%E3%81%86%E3%82%89%E7%8E%8Bclassic-tce%E7%89%88%E3%80%81%E6%AD%A3%E5%BC%8F%E5%85%AC%E9%96%8B%E3%81%97%E3%81%BE%E3%81%97%E3%81%9F/#comment-6053
→ 読み太の作者さんの実験ではならなかったみたいなのでehashは諦める。
・local-game-serverで棋譜出力機能追加。
→ book自体が実戦棋譜なので棋譜の進行がそこそこ偏っている意味がある。
計測するのに、8手目ぐらいまでrandom playerのほうが良かったりして…。
ともかく、計測自体は正常に行えていることが確認できた。
・やねうら王2016-mid、paramters.hを最新のものにして、他の実験をやる。
V2.86a
・null moveのときだけはkillerは必ず更新したほうがいい。
null moveしたノードでのkiller手は理想的なkiller手なので、価値が高い。(読み太の作者さん)
+ if ((ss - 1)->currentMove == MOVE_NULL)
+ {
+ // ただし、null move時のkillerは理想的なkillerなので有効だと考えられる。
+
+ // 普通にkillerのupdateを行なう。
+ if (ss->killers[0] != move32)
+ {
+ ss->killers[1] = ss->killers[0];
+ ss->killers[0] = move32;
+ }
+
+ } else {
弱くなった…。
49.3%
#160
やねうら王2016mid V286a
2016mid first version, 1スレッド、0.1秒設定
#159
やねうら王2016mid V286
2016mid first version, 1スレッド、0.1秒設定
2248-105-2316(84.3% R-5.2)
・ByteBoardで指し手生成を行なう → たこっとの作者さんに話を聞いてから。
→ SEEが正確に出来ないので損得微妙だと思い、これは先送り。
■ 2016/04/27 V2.85
・基準バージョンに対する勝率を見ながらパラメーターを動かすべき(かも)
・local-game-serverで用いるbookから32手目で同一の局面の除外
・そうすればrtimeは1手0.1秒固定で問題ない(かも)
→ クラスター化しているのでそれでも同じ乱数を引いて、同じ定跡になることはあるから
1手0.1秒固定はまずいのか…。
■ 2016/04/24 V2.84
・local-game-server、bookファイルがないときに読み込みエラー表示追加。
■ 2016/04/22 V2.83
・結論的にはパラメーターの自動調整は意図通り動いていたようだ。
凸性がないときに勝率がいいからと言って値を大きく動かすの危険。
・gen0 初期パラメーターに戻す
tce-finalに対して -R17.8程度。(あちらはASSERTなしなので)
2859-91-2580(0.0% R17.8)
・自己対戦フレームワークのfront-end、robocopyを使うように変更。
世代が進むにつれて弱くなっていたの、たぶん、共有フォルダだと
sambaプロトコルになってて、cacheが生きていて、変更したパラメーターファイルの
読み込みのときに古いファイルが読み込まれたりしていたせいもあるのではないかと…。
これで1手0.1秒で24時間ほど回す。
■ 2016/04/21 V2.82
・local-game-serverのspin loopのsleepの位置がおかしい気がするので修正。
・結果が思わしくないので、rtime = 300msで自動調整しなおす。
[HISTORY]
PARAM_REDUCTION_BY_HISTORY : 14724 → 14980(53.44%) : ←←(値14212,勝率50.41%,3744局,有意36.28%) ,←(値14468,勝率47.17%,1872局,有意97.60%) ,→(値14980,勝率53.44%,624局,有意4.08%) ,→→(値15236,勝率49.96%,1872局,有意51.14%) ,
PARAM_SINGULAR_MARGIN : 6 → 6(50.00%) : ←←(値2,勝率49.26%,3744局,有意73.58%) ,←(値4,勝率51.19%,1872局,有意20.31%) ,→(値8,勝率49.51%,1872局,有意63.43%) ,→→(値10,勝率51.03%,1872局,有意23.70%) ,
PARAM_NULL_MOVE_DYNAMIC_BETA : 67 → 67(50.00%) : ←←(値59,勝率50.71%,3744局,有意27.14%) ,←(値63,勝率45.71%,624局,有意98.44%) ,→(値71,勝率48.06%,1872局,有意91.14%) ,→→(値75,勝率48.11%,1872局,有意90.61%) ,
PARAM_NULL_MOVE_DYNAMIC_ALPHA : 823 → 823(50.00%) : ←←(値791,勝率50.08%,1872局,有意47.72%) ,←(値807,勝率45.48%,624局,有意98.84%) ,→(値839,勝率50.95%,1872局,有意25.47%) ,→→(値855,勝率50.54%,1872局,有意35.40%) ,
PARAM_FUTILITY_AT_PARENT_NODE_MARGIN : 160 → 150(54.05%) : ←←(値140,勝率49.51%,1872局,有意63.45%) ,←(値150,勝率54.05%,624局,有意2.10%) ,→(値170,勝率50.25%,1872局,有意43.19%) ,→→(値180,勝率50.29%,1872局,有意42.07%) ,
PARAM_FUTILITY_MARGIN_QUIET : 123 → 133(53.03%) : ←←(値113,勝率50.66%,1872局,有意32.34%) ,←(値118,勝率50.55%,3744局,有意31.98%) ,→(値128,勝率49.59%,3744局,有意63.72%) ,→→(値133,勝率53.03%,1872局,有意1.71%) ,
PARAM_FUTILITY_MARGIN_ALPHA : 95 → 95(50.00%) : ←←(値85,勝率49.35%,1872局,有意67.61%) ,←(値90,勝率50.00%,1872局,有意50.00%) ,→(値100,勝率50.65%,1872局,有意32.36%) ,→→(値105,勝率48.05%,1872局,有意91.44%) ,
→ これで値を動かしたところR70ぐらい下がってる。わけわからん…。
初期パラメーターが悪いようだ。NULL MOVEの枝刈りのdepthを極端に下げたのが
主な原因のようだ。一度、完全に元のパラメーターに戻す。
■ 2016/04/16 V2.81
・評価関数、定跡ファイルなどのファイルが読み込めないときのエラーメッセージに"Error"の文字列を埋め込み、
local-game-serverではこの文字列を拾うようにする。
・自己対戦の勝率なんかおかしいときがあると思ったら
(1024MB(1GB) + 評価関数 + 変換用バッファ)×6並列対局×2プロセスが
どうも24GBに収まらないことがあった模様。
→ あと、6並列なのにCPU 30%ぐらいしか消費してないのおかしくないか?
→ まあいいや。6コアでは8並列、4コアでは6並列をデフォとしよう。
・ネットワークごしに共有フォルダの同じファイルに同時にアクセスしたら、アクセス出来ないことが
あった模様。なにこれ…。
・値をいい加減に動かし過ぎ。試行回数500回以上において信頼区間95%で有意になるまでは、
値を動かさないように変更。(試行回数上限3000回)
・V2.81 gen0
parameters.h初期化。再度調整。
・V2.81 gen1
試行回数3000回において信頼区間90%で有意でないときは値を変えないようにした。
それ以上細かいものは手で調整することにした。
計測おかしい。
PARAM_RAZORING_MARGIN : 512 → 576(57.24%) : ←←(448,53.05%,0tries,有意9.17%) ,←(480,46.80%,0tries,有意91.71%) ,→(544,49.43%,1344tries,有意64.48%) ,→→(576,57.24%,0tries,有意0.10%) ,
PARAM_RAZORING_MARGIN : 512 → 448(52.08%) : ←←(値448,勝率52.08%,576局,有意8.09%) ,←(値480,勝率47.18%,0局,有意91.69%) ,→(値544,勝率50.13%,1728局,有意46.44%) ,→→(値576,勝率49.87%,1728局,有意53.55%) ,
・試行回数の1/2以上で80%信頼区間で有意でないならng。
・試行回数の1/3以上で90%信頼区間で有意ならok
・試行回数の1/5以上で95%信頼区間で有意ならok
・最大試行回数3000回。
こういう条件でどうなの。
・信頼区間90%で有意でないなら、パラメーターに関して
-step*2,-step,+step,+step*2
だけ動かした4点をサンプリングして関数(勝率)に凸性があるかどうかを確かめてから手で動かすようにしたほうが良さげ。
・V2.81 gen2
tce final ASSERTなしに-R10ぐらい。(900局)
前バージョンだと-R30ぐらいだったので強くなってきている?
■ 2016/04/16 V2.80
・PARAM_FUTILITY_MARGIN_DEPTHはPARAM_FUTILITY_MARGIN_ALPHAのほうが名前変更。
パラメーター自動調整中。
・思考時間 1手、80ms-120ms、平均100msにして倍ぐらいの速度で対戦させたほうがいいような気がしてきた。
→ とりあえずrtime 50でいいや。
持ち時間長くで調べたほうがいいパラメーターは長い時間を対局させる機能が必要だな。
前のバージョンと対戦させると-R10ぐらい低い。なんなんこれ。
→ 対局回数780回に増やして、rtimeを1~1.5倍のランダム時間に仕様変更して
1手100~150msで再度調整。
→ 強くならん…。パラメーター読み込めてない疑惑。
■ 2016/04/15 V2.79
・local-serverから起動したときにparamteres.hが読み込めてない問題。
local-serverがpath設定しないのがいけないのか…。うーん、そうか…。
・parameters_masterとslaveに分離。
・engine側、これでうまく動いてるっぽい。自動制御側を書く。
→ 書けた。しばらく自動で回す。
→ このあと自動で強くなってると嬉しい。
・PARAM_FUTILITY_MARGIN_DEPTHはPARAM_FUTILITY_MARGIN_ALPHAのほうが名前が良かった気がするが
いまさら変更できないな…まあいいや。何かの機会に変更すれば。
■ 2016/04/15 V2.78
・parameters.hから実行時の読み込みルーチンを書く。
→ 読み込み部書けた。
・razoring marginもparameters.hに追加する。
・local-serverから起動したときにparamteres.hが読み込めてない。根が深そう。あとで調べる。
■ 2016/04/14 V2.77
・2016-mid-engine追加。
・一括パラメーター調整の仕組み、何か考える。
・parameters.h追加。
//
// Internal iterative deepening
//
// IIDの条件
//if (depth >= (PvNode ? PARAM_IID_DEPTH_PV * ONE_PLY : PARAM_IID_DEPTH_NONPV * ONE_PLY)
// && !ttMove
// && (PvNode || ss->staticEval + PARAM_IID_ALPHA >= beta))
// [PARAM] min:3,max:10,step:1
PARAM_DEFINE(int) PARAM_IID_DEPTH_PV = 5;
// [PARAM] min:5,max:12,step:1
PARAM_DEFINE(int) PARAM_IID_DEPTH_NONPV = 8;
// [PARAM] min:100,max:400,step:16
PARAM_DEFINE(int) PARAM_IID_ALPHA = 256;
こんな感じで書いていく。てかIIDは、メモリが潤沢にあれば関係ないのでこの調整はしない。
・ざっと書けた。他の細かい探索パラメーターは調整が難しいので評価関数を書きなおしてからにする。
とりあえずコンセプトプルーフだけでも。
・3乗ボーナスやりすぎであったか…。(thx.woodyringさん)
- Value bonus = Value(((int)depth * (int)depth * (int)depth) / ((int)ONE_PLY*(int)ONE_PLY*(int)ONE_PLY) - 1);
+ Value bonus = Value((depth / ONE_PLY) * (depth / ONE_PLY) + depth / ONE_PLY - 1);
51.4%
#153
やねうら王classic-tce V277
3乗ボーナスを2乗に, 1スレッド、0.1秒設定
#0
やねうら王classic-tce V276
skip-early-pruningでもkillerがないなら更新, 1スレッド、0.1秒設定
357-79-337(21.3% R10.0)
■ 2016/04/14 V2.76
・浅い探索のときでもkillerぐらい更新したほうが得なのでは。(thx.読み太の作者)
if (ss->skipEarlyPruning)
+ {
+ // しかしkillerがないときはkillerぐらいは登録したほうが少しだけ得かも。
+ if (ss->killers[0] == MOVE_NONE)
+ ss->killers[0] = move32;
+ else if (ss->killers[1] == MOVE_NONE)
+ ss->killers[1] = move32;
return;
+ }
54.7%
#152
やねうら王classic-tce V276
skip-early-pruningでもkillerがないなら更新, 1スレッド、0.1秒設定
#0
やねうら王classic-tce V273
skip-early-pruningにおいてhistory,killerを更新しない, 1スレッド、0.1秒設定
519-81-429(0.2% R33.1)
■ 2016/04/14 V2.75
・tce vs Apery(WCSC25) 1スレッド5秒固定。62-3-50。
1スレッドもしくは短い持ち時間ではあまり差がつかない。
・MAX_PLYでの引き分け判定、1本化する。
if (Signals.stop.load(std::memory_order_relaxed) || ss->ply >= MAX_PLY || pos.game_ply() > Limits.max_game_ply)
→
Limits.max_game_ply = std::min(Limits.max_game_ply, rootPos.game_ply() + MAX_PLY -1);
こないして、ss->ply >= MAX_PLYの判定を消す。
- if (ss->ply >= MAX_PLY || pos.game_ply() > Limits.max_game_ply)
+ if (pos.game_ply() > Limits.max_game_ply)
- if (Signals.stop.load(std::memory_order_relaxed) || ss->ply >= MAX_PLY || pos.game_ply() > Limits.max_game_ply)
+ if (Signals.stop.load(std::memory_order_relaxed) || pos.game_ply() > Limits.max_game_ply)
・singular extensionを行うかどうかのsearch()の他に、do_moveせずに呼び出すsearch()が2カ所あって(nullmoveの後ろと、iid)
その内部でも同様にkillerとhistoryを更新しないように抑制する。(その部分で更新されるkiller手はもともと登録されてあったkiller手よりは価値が低いので。)
(thx. 読み太の作者)
// IID、null move、singular extensionの判定のときは浅い探索なのでこのときに
// killer等を更新するのは有害である。
if (ss->skipEarlyPruning)
return;
こう変更してみる。
54.7%
#151
やねうら王classic-tce V273
skip-early-pruningにおいてhistory,killerを更新しない, 1スレッド、0.1秒設定
#0
やねうら王classic-tce V271a
revertした, 1スレッド、0.1秒設定
271-34-224(1.5% R33.1)
効果あがあるっぽい。採用。
Stockfish7でも(本家がこれを採用すれば)たぶん効果があるばす。
・これにてtceの開発終了。
exeフォルダに最新のビルドを入れる。
次はやねうら王2016(Mid)の開発に着手。
■ 2016/04/14 V2.74
・ponder消失問題に対処。
fail low時など、置換表にも2手目がないのイクナイ。
→ 追加した。
・ponder、extract_ponder_from_tt()で置換表あさって返すとき、1手目の合法手集合からcontainsで調べてるの、
Stockfishのコードは、バグだな。なんなのこれ。修正した。
しばらくランニングさせておく。
・HalfDensity、おかしい気がする。
// game_ply()は加算すべきではない気がする。あとで実験する。
const Row& row = HalfDensity[(idx - 1) % HalfDensitySize];
if (row[(rootDepth + rootPos.game_ply()) % row.size()])
→ よくわからないが少なくとも足す必要はないように思えるのだが…。
■ 2016/04/14 V2.73
・YaneuraOu 2016は、Mid(5月時点のバージョン/公開)とLate(11月時点のバージョン/非公開)とに分離。前者は公開する。
・自己対戦フレームワークで定跡データベース中の対局の手数が指定した手数より少ない場合クラッシュするっぽいバグ修正。(thx. tanuki-)
■ 2016/04/13 V2.72
・singular extension等では現在のkillerを更新すべきではない説の検証。(thx.読み太の作者)
exclusion nodeでkiller更新とか、やったらあかんのちゃう仮説。
inline void update_stats(const Position& pos, Stack* ss, Move move,
Depth depth, Move* quiets, int quietsCnt)
{
+ // 特定の指し手を除外して探索したなら、今回の指し手がこのnodeでのベストな指し手ではないから
+ // このときにkiller等を更新するのは有害である。
+ if (ss->excludedMove != MOVE_NONE)
+ return;
→ 何らか現実的な効果があるくさい。singularとの兼ね合いかも知れないが。
これ、効果があるならこのアイデアは本家Stockfishにも取り込まれるべき。
51.4%
#148
やねうら王classic-tce V272
exclusion moveがあるときupdate_statしない, 1スレッド、0.1秒設定
#0
やねうら王classic-tce V271a
revertした, 1スレッド、0.1秒設定
241-49-228(25.9% R9.6)
V2.72a
if (ss->excludedMove != MOVE_NONE)
{
// ただしkillerがないなら、ないよりはマシだろうから今回の指し手を登録する。
+ if (ss->killers[0] == MOVE_NONE)
+ ss->killers[0] = make_move32(move);
return;
}
50.9%
#149
やねうら王classic-tce V272a
exclusion moveあってもupdate_stat,killerは更新する, 1スレッド、0.1秒設定
#0
やねうら王classic-tce V271a
revertした, 1スレッド、0.1秒設定
226-56-218(33.5% R6.3)
V2.72b
// このnodeでは、singular extensionをしているので、置換表の指し手がbestのはずで、
// 二番目の指し手が今回の指し手のはずだから、兄弟nodeのためには、以下のように
// killerを設定してやるのが適切。
if (ss->killers[0] == MOVE_NONE)
{
+ ss->killers[0] = make_move32(ss->excludedMove);
+ ss->killers[1] = make_move32(move);
}
49.0%
#150
やねうら王classic-tce V272b
exclusion moveあってもupdate_stat,killerは更新する, 1スレッド、0.1秒設定
#0
やねうら王classic-tce V271a
revertした, 1スレッド、0.1秒設定
216-50-225(68.3% R-7.1)
よくわからないが勝率下がったので取り入れない。
対局、3000局ぐらいやらないとわからない。
■ 2016/04/13 V2.71
・ehash実装するの忘れてた。(thx.平岡さん)
→ 何も速くならんかった…。
・置換表にstaticEval保存しなくてもnpsほとんど変わらない。
staticEval、置換表が壊れてておかしい値拾ってくるリスクを考えると
保存しないほうがいいような気すらする。勝率変わるかテストする。
49.3%
#146
やねうら王classic-tce V271
置換表にstaticEval保存しない, 1スレッド、0.1秒設定
#0
やねうら王classic-tce V265
駒打ちを Statsに含めてみる実験, 1スレッド、0.1秒設定
138-31-142(61.7% R-5.0)
V2.65とやってほぼ互角。
V2.71a
・revertしてV2.65と対戦。
52.8%
#147
やねうら王classic-tce V271a
revertした, 1スレッド、0.1秒設定
#0
やねうら王classic-tce V265
駒打ちを Statsに含めてみる実験, 1スレッド、0.1秒設定
142-32-127(16.5% R19.4)
ということでrevertする。
■ 2016/04/11 V2.70
・ProbCutのパラメーター調整
- Value rbeta = std::min(beta + 200, VALUE_INFINITE);
+ Value rbeta = std::min(beta + 100 + param1 * 50, VALUE_INFINITE);
param1 = 0..4ぐらいで。
48.6% 52.3% 52.6% 50.5% 50.8%
#145
やねうら王classic-tce V270
probcut調整, 1スレッド、0.1秒設定
#0
やねうら王classic-tce V265
駒打ちを Statsに含めてみる実験, 1スレッド、0.1秒設定
275-58-291(76.3% R-9.8) 298-54-272(12.9% R15.9) 288-76-260(10.8% R17.8) 276-73-270(38.2% R3.8) 185-52-179(35.7% R5.7)
よくわからない。いじらんとこ。
・一括パラメーター調整の仕組み、何か考える。
■ 2016/04/11 V2.69
・historyとか、成りの指し手のときは、成り駒のhistoryを見ないといけないのに
そういう処理になってなかった。(thx. 読み太の作者さん)
Position::moved_piece(),moved_piece_ex()修正。
make_move32()、config.hに移動。
50.5%
#144
やねうら王classic-tce V269a
historyに成り区別, 1スレッド、0.1秒設定
#0
やねうら王classic-tce V265
駒打ちを Statsに含めてみる実験, 1スレッド、0.1秒設定
1277-324-1251(30.3% R3.6)
もっと良くなりそうなものだが、何かまだ書き換え忘れている?
→ わからん...誰かデバッグきぼんぬ。
■ 2016/04/11 V2.68
・電王戦から戻ってきたー。
・aspiration searchにするdepth
- if (rootDepth >= 5 * ONE_PLY)
+ if (rootDepth >= 5 )
これStockfishのソースコード自体が間違ってるんだな。
こうやってparam1 = 0..5ぐらいで回しておく。
if (rootDepth >= 3 + param1)
48.6% 50.5% 50.3% 48.7% 51.1% 50.5%
#142
やねうら王classic-tce V268
aspiration depth調整, 1スレッド、0.1秒設定
#0
やねうら王classic-tce V265
駒打ちを Statsに含めてみる実験, 1スレッド、0.1秒設定
1364-373-1445(93.7% R-10.0) 1424-319-1398(31.2% R3.2) 1374-329-1358(38.0% R2.0) 1350-383-1422(91.4% R-9.0) 1418-337-1355(11.6% R7.9) 1384-384-1357(30.3% R3.4)
param1 = 4で最大。(+R7.9)
if (rootDepth >= 9 + param1)
この条件でparam1 = 0..2でもテストしておく。
50.7% 49.0% 43.3%
#142
やねうら王classic-tce V268
aspiration depth調整, 1スレッド、0.1秒設定
#0
やねうら王classic-tce V265
駒打ちを Statsに含めてみる実験, 1スレッド、0.1秒設定
183-55-178(37.6% R4.8) 178-53-185(66.3% R-6.7) 120-37-157(98.9% R-46.7)
+ if (rootDepth >= 7)
■ 2016/04/08 V2.67
・修正忘れてた…。
if (pos.state()->sumKKP == INT_MAX)
- ss->staticEval = evaluate(pos);
+ evaluate(pos);
これで少しでも強くなってるのか一晩回してみる。
50.7%
#141
やねうら王classic-tce V267
evaluate()のときにstaticEvalに代入やめる, 1スレッド、0.1秒設定
#0
やねうら王classic-tce V265
駒打ちを Statsに含めてみる実験, 1スレッド、0.1秒設定
1067-281-1039(27.1% R4.6)
■ 2016/04/08 V2.66
・評価関数、差分計算するときに
sumKKP == VALUE_NONE
を判定条件にしていると偶然一致することがあるのか。なんてこったい…。
INT_MAXを代わりに使うようにする。(thx. tさん)
■ 2016/04/07 V2.65
・駒打ちを Statsに含めてみる実験。
USE_DROPBIT_IN_STATSを追加。
→ 結構、勝ってるような?
これ、効果あるということならいまからソースコード整理しよう..
moved_piece() 1手前の指し手に対して呼び出すと駒打ちにおいて手番が異なるから
呼び出してはいけないのか。
→ そんなことしてる箇所はなかった。
51.8%
#140
やねうら王classic-tce V265
置換表にeval保存しない, 1スレッド、0.1秒設定
#0
やねうら王classic-tce V261
VALUE_WINの値変更, 1スレッド、0.1秒設定
216-37-201(21.7% R12.5)
ほぼ強くなってないな…。
+ auto& prevCmh = CounterMoveHistory[prevPrevSq][prevPrevPc];
+ prevCmh.update(prevPc , prevSq, bonus);
ここも修正要るのか。忘れてた。
53.0%
#140
やねうら王classic-tce V265
置換表にeval保存しない, 1スレッド、0.1秒設定
#0
やねうら王classic-tce V261
VALUE_WINの値変更, 1スレッド、0.1秒設定
157-25-139(13.5% R21.2)
・とりあえず強くなったのでexeフォルダのtce版、差し替えておく。
■ 2016/04/07 V2.64
・evaluateの値、置換表に放り込む価値はないのでは...
bench
Total time (ms) : 60870
Nodes searched : 44842076
Nodes/second : 736685
毎回evaluate()呼び出してみる。
Total time (ms) : 54219
Nodes searched : 39945800
Nodes/second : 736749
nps変わらないし、置換表効率が良くなったし、こっちのほうがいいような…。
強さは変わらないのか?しばらくランニングさせておいて問題なさそうならこれにする。
置換表効率は4/3倍になっているので33%の改善…。
処理的には等価なはずなのだが、探索node数が変わっている..
置換表衝突で破損していた分なのか..
→
48.2%
#139
やねうら王classic-tce V264
置換表にeval保存しない, 1スレッド、0.1秒設定
#0
やねうら王classic-tce V261
VALUE_WINの値変更, 1スレッド、0.1秒設定
355-83-381(84.0% R-12.3)
弱くなったので戻す。うーん..。
■ 2016/04/07 V2.63
・singular実験やりなおし。
Value rBeta = ttValue - (param1+1) * 4 * depth / ONE_PLY;
param1 = 0..3ぐらいで。
singularのmargin値、少しぐらい変えても強くも弱くもならないということなのか?
・VALUE_SUPERIORとかの関係か、以前と同じ値のはずなのにR10ぐらい強くなってる気が..
1000局ほど対局させとくか。
singular 0.1秒だといまひとつはっきりしないな…。
52.4% 51.2% 52.3% 52.8%
#138
やねうら王classic-tce V263
singular調べ直し, 1スレッド、0.1秒設定
#0
やねうら王classic-tce V261
VALUE_WINの値変更, 1スレッド、0.1秒設定
196-42-178(16.3% R16.7) 193-39-184(30.3% R8.3) 190-53-173(17.2% R16.3) 182-41-163(14.1% R19.2)
Value rBeta = ttValue - (param1+1) * 2 * depth / ONE_PLY;
param1 = 0..10ぐらいで2,3日まわしとくか..
一応、param1=0(2*depth*ONE_PLY)での勝率を確認しておく。
Stockfishがこの設定のはず。
51.1%
#138
やねうら王classic-tce V263
singular調べ直し, 1スレッド、0.1秒設定
#0
やねうら王classic-tce V261
VALUE_WINの値変更, 1スレッド、0.1秒設定
255-65-244(29.6% R7.7)
変わらないのか…。
Value rBeta = ttValue - 40 * depth / ONE_PLY;
これはどうなの。
47.0%
#138
やねうら王classic-tce V263
singular調べ直し, 1スレッド、0.1秒設定
#0
やねうら王classic-tce V261
VALUE_WINの値変更, 1スレッド、0.1秒設定
171-51-193(88.6% R-21.0)
・結論的にはよくわからない。
■ 2016/04/07 V2.62
・DYNAMIC_FUTILITY_MARGINの実験やりなおし。
return (16+param1*4) * futility_margin_sum * (int)d / ONE_PLY / (64 * 8);
これくらいに設定して、param1 = 0..4ぐらいで比較。
+ // 評価関数の返す値の最大値
+ VALUE_MAX_EVAL = int(VALUE_KNOWN_WIN) -1,
49.5% 54.3% 42.2% 47.7% 48.1%
#136
やねうら王classic-tce V262
dynamic futility調べ直し, 1スレッド、0.1秒設定
#0
やねうら王classic-tce V261
VALUE_WINの値変更, 1スレッド、0.1秒設定
180-52-184(60.3% R-3.8) 102-20-86(10.7% R29.6) 79-21-108(98.6% R-54.3) 94-11-103(76.2% R-15.9) 91-19-98(72.0% R-12.9)
param1 = 1で最大
return (20 + (param1-1)*2) * futility_margin_sum * (int)d / ONE_PLY / (64 * 8);
param1 = 0..2ぐらいで
49.2% 49.5% 50.8%
#137
やねうら王classic-tce V262a
dynamic futility調べ直し, 1スレッド、0.1秒設定
#0
やねうら王classic-tce V261
VALUE_WINの値変更, 1スレッド、0.1秒設定
92-21-95(61.5% R-5.6) 96-14-98(58.5% R-3.6) 94-21-91(38.4% R5.6)
強くなってないな…。この実験はまた今度。
・めっさ落ちる。なにこれ。
sfen l+R2lbnnl/3skp1s1/pppp3p1/4pPG1p/3N5/2P1G3P/PP1PP2P1/6S2/+s2G1K1RL b PGpnb 75
> VALUE_KNOWN_WIN = int(VALUE_MATE_IN_MAX_PLY) - 1,
こんな近いと置換表に書き込んで、相手番から見ると
- VALUE_KNOWN_WIN
になって、ここにsingularの判定などでmarginを引くと
VALUE_MATE_IN_MAX_PLY
より下回るのでまずいのか…。そうなのか…。
dynamic marginでおかしくなってたの、これが一因にあるのか。
・dynamic margin、なんか以前のものより勝率よさげ?
・色々考えた結果、優等局面のスコア変更することにする。
{ VALUE_SUPERIOR , VALUE_SUPERIOR }, // REPETITION_SUPERIOR
{ -VALUE_SUPERIOR , -VALUE_SUPERIOR }, // REPETITION_INFERIOR
そしてこう変更する。
VALUE_SUPERIOR = 28000,
VALUE_MAX_EVAL = 25000,
■ 2016/04/07 V2.61
{ VALUE_KNOWN_WIN , VALUE_KNOWN_WIN }, // REPETITION_SUPERIOR
{ -VALUE_KNOWN_WIN , -VALUE_KNOWN_WIN }, // REPETITION_INFERIOR
これ、-1にしたほうが良いのでは..
VALUE_KNOWN_WIN自体はEVALの最大値としてつこてるから…。
{ VALUE_KNOWN_WIN-1 , VALUE_KNOWN_WIN-1 }, // REPETITION_SUPERIOR
{ -VALUE_KNOWN_WIN+1 , -VALUE_KNOWN_WIN+1 }, // REPETITION_INFERIOR
こう変更して比較。
少し強くなってる…気がする。500戦ほどさせておく。
51.2%
#135
やねうら王classic-tce V261
revert, 1スレッド、0.1秒設定
#0
やねうら王classic-tce V260b
revert, 1スレッド、0.1秒設定
306-66-292(27.0% R8.1)
・自己対戦で落ちた模様
sfen ln1l1+R2+P/1k3p3/1pps5/p2p2p1P/2g1p3p/KPsP1rg2/P3P+s3/1B7/LNSG4L b 2PB2p2ng 153
・詰まされる形、投げるタイミング早すぎ。
- && (bestValue - (-VALUE_MATE)) * 3 > rootDepth)
+ && (bestValue - (-VALUE_MATE)) * 2 < rootDepth)
・go infiniteに対して、stopが来ていないのにbestmoveを返してしまう。
- while (!Signals.stop && Search::Limits.ponder)
+ // "go infinite"に対してはstopが送られてくるまで待つ。
+ while (!Signals.stop && (Limits.ponder || Limits.infinite))
→ 一応、意図通りになった模様。
・とりあえず結論的には自己対戦の回数もっとやらないとバグを仕込んで弱くなったときの原因究明に時間がかかる
ということ。
・6c6tと6c12t比較
14-8-22 // 8分切れ負け
28-9-31 // 5分切れ負け
時間が長いと大差?
スレッド数増やしても弱くはならないみたい。R30か40ぐらい上がるのかな?
弱くならないということがわかったからそれでいいや。細かい比較はいまできないし。
■ 2016/04/07 V2.60
・若干弱くなっているのが気になる。
46.8%
#132
やねうら王classic-tce V259
counter move修正, 1スレッド、0.1秒設定
#0
やねうら王classic-tce V253s
singular再テスト, 1スレッド、0.1秒設定
265-42-301(94.0% R-22.1)
・counter move、82,83を使うことない気がしてきた。ちょっと修正。
if (!is_ok(move)) \
{ \
+ sq = (Square)color; \
pc = NO_PIECE; \
} else { \
→ 修正完了。
・これで弱くなってるんではない気がする。
futility margin、やはり変なことするといかんのだな…。
// futility margin with game_ply
// 序盤で小さめの数値。
// 40手以降はd * 90固定でいいや。
// rを進行度とみなして、これで70と90を内分する。
game_ply = min(40, game_ply);
float r = game_ply / 40.0f;
return Value(d * int(((1 - r) * 70 + 90 * r)));
→ これやめて、再度練り直す。
V2.60a
・dynamic futility marginのsampling次のような条件でどうか。
if (newDepth == ONE_PLY
&& eval != VALUE_NONE // evalutate()を呼び出していて
&& !captureOrPromotion // futilityはcaptureとpromotionのときは行わないのでこの値は参考にならない
&& !InCheck // 王手がかかっていなくて
&& abs(value) < VALUE_MAX_EVAL // evalのスコア
&& alpha < value && value < beta // fail low/highしていると参考にならない
)
{
// 移動平均みたいなものを求める
futility_margin_sum = futility_margin_sum * 63 / 64;
futility_margin_sum += abs(value - eval);
static int count = 0;
if ((++count & 0x100) == 0)
sync_cout << "futility_margin = " << futility_margin_sum / 64 << sync_endl;
}
// 14/8ぐらいかけとかないといけない(気がする)
// game ply(≒進行度)とdepth(残り探索深さ)に応じたfutility margin。
Value futility_margin(Depth d, int game_ply) {
// 平均値に 14/8 を掛け算しとく。
return 14 * futility_margin_sum * (int)d / ONE_PLY / (64 * 8);
}
・DYNAMIC_FUTILITY_MARGINはifdefで書くように変更
もうちょっと実験の余地がありそう。
・V2.53sと対戦。なんかちょっと負けてる予感。
ソースコード、差分取って調べるべき。
→ 比較してみたがほぼ変わらない。
staticEval = evaluate()するのでimprovingには影響があるかも。
45.6%
#133
やねうら王classic-tce V260a
counter move修正, 1スレッド、0.1秒設定
#0
やねうら王classic-tce V253s
singular再テスト, 1スレッド、0.1秒設定
182-43-217(96.4% R-30.6)
・VALUE_WIN絡み、MATEスコアとして表示してしまうバグ。
もしかして、VALUE_MATE_IN_MAX_PLY超えてるのか?
- VALUE_KNOWN_WIN = int(VALUE_MATE_IN_MAX_PLY) - 1,
+ VALUE_KNOWN_WIN = int(VALUE_MATE_IN_MAX_PLY) - 100,
こう修正しとく。
・
// 評価値が2手前の局面から上がって行っているのかのフラグ
// 上がって行っているなら枝刈りを甘くする。
// ※ VALUE_NONEの場合は、王手がかかっていてevaluate()していないわけだから、
// 枝刈りを甘くして調べないといけないのでimproving扱いとする。
bool improving = (ss )->staticEval >= (ss - 2)->staticEval
|| (ss )->staticEval == VALUE_NONE
|| (ss - 2)->staticEval == VALUE_NONE;
これ、evaluateを毎回呼び出すようにして、staticEvalに格納するようにしたから
王手がかかっているときにこの条件満たさなくなってしまったのか…。
こんなことで弱くなるのか…。
staticEvalに代入するのやめるか。
これでしばらく回す。
→ 勝率めっさ落ちた。どうなってんの…。
2.53sともう少し厳密に違いを調べていくべき。
44.8%
#133
やねうら王classic-tce V260a
counter move修正, 1スレッド、0.1秒設定
#0
やねうら王classic-tce V253s
singular再テスト, 1スレッド、0.1秒設定
296-75-365(99.7% R-36.4)
・
V2.60b
VALUE_WIN、やっぱり戻す。
レアケースだし、要らん変換が入るし、
置換表に書き出せなくなるし…。
VALUE_KNOWN_WIN_IN_MAX_PLY = int(VALUE_KNOWN_WIN) - MAX_PLY,
VALUE_KNOWN_LOSE_IN_MAX_PLY = -int(VALUE_KNOWN_WIN_IN_MAX_PLY),
// 評価関数が返すであろう最大値
VALUE_MAX_EVAL = int(VALUE_KNOWN_WIN_IN_MAX_PLY) - 1,
→ 削除
- return value_from_tt(draw_value(REPETITION_DRAW, pos.side_to_move()),ss->ply);
+ return draw_value(REPETITION_DRAW, pos.side_to_move());
- // 詰みのスコアに対して、rootからの手数を考慮したスコアに変換する必要があるので、
- // value_from_tt()で変換してから返すのが正解。
→ そうか。連続王手の千日手は詰みのスコアなのでこの処理、正しい。
・これで500対戦ほどさせて勝率がまだ落ちているようなら、色々元に戻していく。
・
endMoves = currentMoves + 2 + (counterMove != killers[0] && counterMove != killers[1]);
ここ、counterMoveがu32なのにkillers[0]はu32として比較していないのでは..
#ifdef KEEP_PIECE_IN_COUNTER_MOVE
counterMove = (Move)counterMove; // 駒種が上位に格納されているのならマスクする。
#endif
これが要るような?
・NULL_MOVEに対してcounterどうせ登録されてないから、このときMOVE_NONEにしておくほうが
オーダリング改善されるのでは…
#define sq_pc_from_move(sq,pc,move,color) \
if (!is_ok(move)) \
{ \
sq = (Square)(color); \
pc = NO_PIECE; \
} else { \
sq = move_to(move); \
pc = pos.piece_on(sq); \
}
// toの升に駒pcを動かしたことに対する応手
auto cm =
is_ok((ss - 1)->currentMove)
? thisThread->counterMoves[prevSq][prevPc]
: MOVE_NONE
;
こうしたほうがマシなのでは..。
これでしばらく放置しておく。
NULL MOVEのあと、糞みたいな指し手がcounter moveに挙がってくると
オーダリングを阻害する(気がする)
43.4%
#134
やねうら王classic-tce V260b
revert, 1スレッド、0.1秒設定
#0
やねうら王classic-tce V253s
singular再テスト, 1スレッド、0.1秒設定
192-36-250(99.8% R-45.9)
それでも負けとる…。
・KEEP_PIECE_IN_COUNTER_MOVEをundefにして比較する。
→ 同様に負けとる..
・もしかしてsingularが悪さしてるのか?
singularオフにしたらもっと大差になった。なんなんこれ…。
原因わかった。
- auto& cmh = CounterMoveHistory[prevSq][prevSq];
- auto& fmh = CounterMoveHistory[prevPrevSq][prevPrevSq];
+ auto& cmh = CounterMoveHistory[prevSq][prevPc];
+ auto& fmh = CounterMoveHistory[prevPrevSq][prevPrevPc];
うわわわわあああ。
→ 直った気がする。
やっと互角に戻った。もっかい実験やりなおし…。
■ 2016/04/07 V2.59
・Position::pseudo_legal_s()に、countermove関連のassert追加。
・ASSERT_LV 4 にして、
> test autoplay
で回しておく。
・ああ、落ちる原因わかった。
dropのときも駒種を入れておいて、それが手番側の駒であるかを確認しないといけないのか…。そうか。
てか、countermove、移動元の駒だけでなく移動元の駒種もあるほうが良いのでは…。
いやー、そもそも後手の駒を動かす指し手に対するcounter moveに対して何故後手の指し手が登録されているのか?
・counter moveに関して次のassert追加。
ASSERT_LV3(color_of(prevPc) == ~pos.side_to_move());
・Limitsのコンストラクタに
enteringKingRule = EKR_NONE;
追加。(test autoplayなどで困るため)
・counter move
auto prevSq = move_to((ss - 1)->currentMove);
auto prevPc = pos.piece_on(prevSq);
こうなっているが、null moveのこと考えてないな、このコード。Stockfishのコード自体がおかしい。
チェスでは駒が上下対称に動くから顕在化しないのだと思うが…。
// 直前のnoddの指し手で動かした駒とその移動先の升を返す。
// ただしNULL_MOVEのときは、SQ_NB_PLUS1 + 0か + 1の地点に動かしたことにする。
#define sq_pc_from_move(sq,pc,move,color) \
if (move == MOVE_NULL) \
{ \
sq = (Square)(SQ_NB_PLUS1 + ((color == BLACK) ? 0 : 1)); \
pc = NO_PIECE; \
} else { \
sq = move_to(move); \
pc = pos.piece_on(sq); \
}
こういうマクロを作って、先手用のcounter moveとして後手の指し手が混じらないようにした。
→ root nodeだと(ss - 1)->currentMove == MOVE_NONEなのであった…。
上の処理、!is_ok(move)と書かないと駄目なのか..
これでしばらく回しておいて問題なさげなら、自己対戦してテスト。
・exe/フォルダのtce版、差し替え。
■ 2016/04/07 V2.58
・自己対戦サーバー、256手到達でその次がタイムアウトになっとる..なんでなの..
4<draw,ln1k1g1nl/2gsp3r/pppp1pbs1/4P1ppp/3P1P3/P5PPP/1PP1S1NG1/1BG4K1/LNS1R3L w - 256
4<Error : engine timeout , engine name = engines\YaneuraOu-classic-tceV257.exe
・MaxMovesToDraw、きちんと機能してない
→ 修正した。
sfen ln1k1g1nl/2gsp3r/pppp1pbs1/4P1ppp/3P1P3/P5PPP/1PP1S1NG1/1BG4K1/LNS1R3L w - 255
・自己対戦サーバーでStateStack、1局ごとにクリアするように修正。
・4台のPC、一晩で自己対戦させたときに2局落ちてる。
CounterMoveのpseudo-legalまわりか?
・KEEP_PIECE_IN_COUNTER_MOVEをデフォルトでdefineしたままになっていたの修正。
・他、原因よくわからん…。
・lazySMP有効時に物理6コアに対して何スレッドが最大強さになるのかテストする。
■ 2016/04/06 V2.57
・futility margin、わからん。こっちのほうが良いのでは..
// futilityは深さに比例するより、少し減衰したほうがいいと思う。
// 実戦では連続して大きな損をしないから。
// f(a,depth) = Σ pow(a ,depth) ≒ integral pow( a , depth ) = a ** depth / log(a) + c
// depth == 1において1になって欲しいから、
// a / log(a) + c = 1
// 積分定数c = 1 - a / log(a)
{
const float a = 0.98f - param1 * 0.2f;
for (int i = 0; i < MAX_PLY; ++i)
futility_rate[i] = pow(a, i) / log(a) + (1 - a / log(a));
}
param1 = 0..4で一晩放置。
49.6% 46.8% 44.8% 39.5% 39.0%
#131
やねうら王classic-tce V257
dynamic-futility margin, 1スレッド、0.1秒設定
#0
やねうら王classic-tce V253s
singular再テスト, 1スレッド、0.1秒設定
737-197-750(63.2% R-3.0) 675-159-766(99.2% R-22.0) 646-157-795(100.0% R-36.1) 560-182-858(100.0% R-74.1) 564-148-881(100.0% R-77.5)
全く強くならんかった。要らんことしたようであった…。そうなのか…。
dynamic marginで、もっかい調整しよ。
■ 2016/04/06 V2.56
・dynamic futility marginの計算、直近の値を重視したいから線形加重移動平均にしたほうがいいな。
もう少し当たりをつけてから変更してみる。
→ 実装が少し面倒なわりに効果あまりない気がしてきたので、もう少し簡単な方法でいいや。
再度調整してみる。
// このときにdynamic futility marginの値をサンプリングする
if (newDepth >= ONE_PLY
&& eval!=VALUE_NONE && abs(value) < VALUE_KNOWN_WIN_IN_MAX_PLY
&& value < beta // fail highしている値は信用ならないので除外
&& value < eval // 静的評価値が探索したスコアより大きく出ている局面(楽観視)を対象とする
)
{
int d = newDepth / ONE_PLY;
futility_margin_sum[d] += (eval >= beta) ? (eval - value) * d : eval - value;
if (futility_margin_count[d]++ == futility_margin_update_interval)
{
// futility_sampling_intervalのfutility_margin_update_count倍の要素の合計がfutility_margin_sum[d]
futility_margin_table[d] = ((param1 + 4) * futility_margin_sum[d] / 4)
/ (futility_margin_update_count * futility_margin_update_interval);
// 1/4が入れ替わったという考え。(本当は古い部分を入れ替えたほうがいいかも知れないが…)
futility_margin_sum[d] = futility_margin_sum[d] * (futility_margin_update_count - 1)/ futility_margin_update_count;
futility_margin_count[d] = 0;
cout << "futility_margin[" << d << "] = " << futility_margin_table[d] << endl;
}
}
param1 = 0..2とかで。
→ ぜんぜんあかん..
// このときにdynamic futility marginの値をサンプリングする
if (newDepth == 1 * ONE_PLY
&& eval!=VALUE_NONE && abs(value) <= VALUE_MAX_EVAL
&& value < beta // fail highしている値は信用ならないので除外
&& alpha < value // fail lowしている値は参考にならないので除外
こうして、depth = ONE_PLYをサンプリングして、これにdepth掛け算するだとか..。
47.6% 46.4% 55.5% 50.7%
#130
やねうら王classic-tce V256
dynamic-futility margin, 1スレッド、0.1秒設定
#0
やねうら王classic-tce V253s
singular再テスト, 1スレッド、0.1秒設定
140-24-154(80.9% R-16.6) 65-20-75(82.4% R-24.9) 76-23-61(8.6% R38.2) 70-22-68(39.9% R5.0)
・統計的にはfutilityのmargin、depthに比例しない感じだな..
3手あれば何らか被害を小さくできたりするが、1手だと取られるものはとられるわけで…。
■ 2016/04/06 V2.55
・dynamic futility margin(案) , inspired by 読み太
最初、
sample_count[depth] = 100; // 100個のサンプルがすでにあるという体裁
sample_sum[depth] = 90 * sample_count[depth]; // 初期futility margin
とかにしといて、
search<PV>(..)
で探索したときに残りdepthとeval-valueをここに突っ込む。
sample_count[depth] ++;
sample_sum[depth] += abs(eval - value);
んで、
futility_margin(depth) { return sample_sum[depth] / sample_count[depth]; }
みたいなことで。
sample_countがある程度大きくなったら、次のようにgarbageすると良さそう
if (sample_count[depth] > 1000)
{
sample_count[depth] >>= 1;
sample_sum[depth] >>= 1;
}
↓書けた。
// このときにdynamic futility marginの値をサンプリングする
if (newDepth >= ONE_PLY)
{
futility_margin_sum[newDepth] += abs(eval - value);
if (futility_margin_count[newDepth]++ == 4096)
{
// 4096 / 2個ごとにmargin値を計算しなおす。
futility_margin_table[newDepth] = futility_margin_sum[newDepth] / 4096;
futility_margin_sum[newDepth] /= 2;
futility_margin_count[newDepth] = 4096/2;
}
}
// game ply(≒進行度)とdepth(残り探索深さ)に応じたfutility margin。
Value futility_margin(Depth d, int game_ply) {
// dynamic futility margin
return futility_margin_table[d];
}
・dynamic futility margin、変動幅の平均で本当に良いのかどうかはよくわからない。
値を変えながら勝率を見るべき..
futility_margin_table[d] = (param1 + 3) * futility_margin_sum[d] / 4 / sampling_interval;
param1 = 0..7ぐらいで対戦させてみる。
param1 == 2あたりがmax。平均より25%増しぐらいがベスト。感覚に合致する。
もうちょっと細かく分割して調整してみる。
38.0% 42.4% 53.1% 44.3% 46.5% 53.8% 42.7% 45.3%
#129
やねうら王classic-tce V255
dynamic-futility margin, 1スレッド、0.1秒設定
#0
やねうら王classic-tce V253s
singular再テスト, 1スレッド、0.1秒設定
73-20-119(100.0% R-84.9) 59-21-80(96.9% R-52.9) 77-15-68(20.3% R21.6) 62-20-78(92.5% R-39.9) 66-18-76(82.2% R-24.5) 77-17-66(15.8% R26.8) 61-17-82(96.7% R-51.4) 67-12-81(89.1% R-33.0)
→ あまりよくない。条件自体を検討すべき。
・評価値計算した以上、ss->staticEvalに保存したほうが得なような気がする。
if (pos.state()->sumKKP == VALUE_NONE)
- evaluate(pos);
+ ss->staticEval = eval = evaluate(pos);
■ 2016/04/06 V2.54
・定跡12手までに制限してfloodgateに投入しておく。
・reduction、int(r)にしてしまうとONE_PLY==2にしている意味がないのでは…。
> reduction_table[pv][imp][d][mc] = int(r) * ONE_PLY;
比較してみる。
+ reduction_table[pv][imp][d][mc] = Depth((int)(r * (double)ONE_PLY));
44.9%
#126
やねうら王classic-tce V254
reductionテスト, 1スレッド、0.1秒設定
#0
やねうら王classic-tce V253s
singular再テスト, 1スレッド、0.1秒設定
343-111-421(99.8% R-35.6)
こんなんぐらいでこんなに勝率落ちるのか…。うわわぁぁぁ。
・dynamic futility marginの実験
// game ply(≒進行度)とdepth(残り探索深さ)に応じたfutility margin。
Value futility_margin(Depth d, int game_ply) {
// 序盤で小さめの数値。
// 40手以降はd * 90固定でいいや。
// rを進行度とみなして、これで30と90を内分する。
game_ply = min(40, game_ply);
float r = game_ply / 40.0f;
return Value(d * int((1 - r) * (30 + param1 * 10) + 90 * r));
}
param1 = 0..5ぐらいでひたすら回しておく。
47.7% 47.0% 47.2% 48.1% 54.8% 46.9%
#127
やねうら王classic-tce V254a
dynamic-futility margin, 1スレッド、0.1秒設定
#0
やねうら王classic-tce V253s
singular再テスト, 1スレッド、0.1秒設定
142-45-156(80.8% R-16.3) 139-24-157(86.5% R-21.2) 141-21-158(85.1% R-19.8) 137-35-148(76.1% R-13.4) 154-39-127(4.7% R33.5) 134-34-152(86.9% R-21.9)
param1 = 4がベストっぽい
V2.54b
return Value(d * int((1 - r) * (30 + 4 * 10) + 90 * r));
これでしばらく回してみる。
// 進行度に応じたmargin
#if 0
// 序盤で小さめの数値。
// 40手以降はd * 90固定でいいや。
// rを進行度とみなして、これで30と90を内分する。
game_ply = min(40, game_ply);
float r = game_ply / 40.0f;
return Value(d * int((1 - r) * (30 + 4 * 10) + 90 * r));
#endif
↓何も良くなかった。とほほほほ。
49.3%
#128
やねうら王classic-tce V254b
dynamic-futility margin, 1スレッド、0.1秒設定
#0
やねうら王classic-tce V253s
singular再テスト, 1スレッド、0.1秒設定
174-38-179(62.5% R-4.9)
■ 2016/04/06 V2.53
・counterの指し手、移動させる駒種入れるとどうか。
+ // MovePickerのなかで使っているCounterMoveにおいて、移動させる駒種も含めるか。
+ // (これを含めると同じ移動をする別の駒をCounterMoveとしてみなさなくなり、ちょっと枝刈り性能が上がるはず)
+ #define KEEP_PIECE_IN_COUNTER_MOVE
・これに伴い、config.hに
KEEP_PIECE_IN_COUNTER_MOVE
追加。
いやー、これをやるならkillerもやらないといけないのか..
効果があるようなら考えるか..
・MovePickerでkillerの指し手もチェックするように。
#ifdef KEEP_PIECE_IN_COUNTER_MOVE
Move32 m = (Move32)*currentMoves;
move = (Move)m;
// 移動させる駒種が一致するかを確認する。
if (!is_drop(move)
&& pos.piece_on(move_from(move)) != (Piece)(m >> 16))
break;
#else
move = *currentMoves++;
#endif
・これに伴い、Position::pseudo_legalのほう、簡略化。
→ R150も下がった。何かバグっている…。
- && make_move32(move) != (Move)ss->killers[0]
+ && make_move32(move) != ss->killers[0]
これかな?
→ 勝率、まともになった気がする。
互角ぐらいのようなのでしばらく放置。
49.7%
#124
やねうら王classic-tce V253a
counter moveにpiece入れる, 1スレッド、0.1秒設定
#0
やねうら王classic-tce V252
piece_on()→moved_piece(), 1スレッド、0.1秒設定
214-38-217(57.6% R-2.4)
ほぼ互角。
・V2.53s
↑の変更をしたのちにsingularを有効にしたらちょっと勝ち越している気がする。
なぜだかよくわからない。しばらく対局させておく。
57.4%
#125
やねうら王classic-tce V253s
singular再テスト, 1スレッド、0.1秒設定
#0
やねうら王classic-tce V253a
counter moveにpiece入れる, 1スレッド、0.1秒設定
159-33-118(0.6% R51.8)
↓
238-48-188(0.7% R41.0)
よくわからないがちょっと強くなってる。
singularに関しては、あとでもっと調整すべき。
このまわり、何かおかしい。
・定跡未使用のときにINT_MAXにしてるの間違いだった。修正した。
■ 2016/04/06 V2.52
・historyなどの指し手で、以前の指し手以外はpiece_on()ではなく、moved_piece()で判定しないといけない。(駒打ちのときにおかしくなっている) 修正。
→ 合ってた?
→ 下手に変更すると実行時間が余計にかかるようになって弱くなる。
・定跡を採用する手数制限が出来るようにする。
BookMoves のオプション追加。
・tceエンジン、フォルダ変更してなかった。
・何か弱くなっている気がするのでrollbackする。
3乗bonus、ONE_PLYで割りながらにしているのとか、どうも怪しい気がする。
→ なんかこのへん怪しい。bonus、慎重に調整すべき。
52.1%
#122
やねうら王classic-tce V252
piece_on()→moved_piece(), 1スレッド、0.1秒設定
#0
やねうら王classic-tce V251
bestMoveChanged修正, 1スレッド、0.1秒設定
596-93-548(7.8% R14.6)
今度は弱くなってなかった。よしよし。
■ 2016/04/06 V2.51
・reduction自体は 残りdepthに応じて行なうが、そのときにONE_PLYで割っているので、結局、
bonusもONE_PLYで割ったあとの形で2乗ボーナスとかにしないと辻褄があわない。
- Value bonus = Value((int)depth*(int)depth / ((int)ONE_PLY*(int)ONE_PLY) + (int)depth / (int)ONE_PLY + 1);
- if (ss->ply >= MAX_PLY || pos.game_ply() >= Limits.max_game_ply)
+ if (ss->ply >= MAX_PLY || pos.game_ply() > Limits.max_game_ply)
game_ply()、初期局面が1だから、初期局面からN手指したあとはN+1。
・null moveのとき、評価値反転させるの、差分計算する必要、ないのでは…。
→ do_null_move()でStateInfo丸ごとコピーしているから、合ってる。
・Stockfishのrazor marginのコード
&& depth < 4 * ONE_PLY
&& eval + razor_margin[depth] <= alpha
&& ttMove == MOVE_NONE)
{
if ( depth <= ONE_PLY
&& eval + razor_margin[3 * ONE_PLY] <= alpha)
ひとつ目のところもONE_PLY掛けるべきでは..うーん..
・VALUE_KNOWN_WINを使っているところVALUE_KNOWN_WIN_IN_MAX_PLYに変更しておく。
・bestmove changed のカウンター、インクリメントしてなかったの修正。
+ if (moveCount > 1 && thisThread == Threads.main())
+ ++static_cast<MainThread*>(thisThread)->bestMoveChanges;
・alpha更新のタイミングでeasy moveをクリアしていなかったの修正。
・色々いじったが、この時点で弱くなっていなければまずは良し。
53.4%
#121
やねうら王classic-tce V251
bestMoveChanged修正, 1スレッド、0.1秒設定
#0
やねうら王classic-tce V248a
tce版, 1スレッド、0.1秒設定
238-38-208(7.1% R23.4)
→ 弱くはなってなさげ。よしよし。
■ 2016/04/06 V2.50
・最大手数に到達して引き分けになるとき、qsearchで引き分けのスコアを返すように。
if (ss->ply >= MAX_PLY || pos.game_ply() >= Limits.max_game_ply)
・qsearchでVALUE_WINもrootからの深さに応じた値を返すべきなのか…。そうか…。
+ VALUE_KNOWN_WIN = int(VALUE_MATE_IN_MAX_PLY) - 1,
+ VALUE_KNOWN_WIN_IN_MAX_PLY = int(VALUE_KNOWN_WIN) - MAX_PLY,
+ VALUE_KNOWN_LOSE_IN_MAX_PLY = -int(VALUE_KNOWN_WIN_IN_MAX_PLY),
inline Value value_to_tt(Value v, int ply) {
ASSERT_LV3(-VALUE_INFINITE < v && v < VALUE_INFINITE);
+ return v >= VALUE_KNOWN_WIN_IN_MAX_PLY ? v + ply
+ : v <= VALUE_KNOWN_LOSE_IN_MAX_PLY ? v - ply : v;
}
value_from_tt()も同様の修正。
・qsearch()のfutility、成りも考慮する
+ + (is_promote(move) ? (Value)ProDiffPieceValue[pos.moved_piece(move)] : VALUE_ZERO) ;
50.1%
#120
やねうら王classic-tce V250
ValueWin修正, 1スレッド、0.1秒設定
#0
やねうら王classic-tce V248a
tce版, 1スレッド、0.1秒設定
573-101-571(47.6% R0.6)
→ 強さ変わらん
■ 2016/04/06 V2.49
・singular、持ち時間を変更しつつ試す。
V2.49
singular判定の係数を非常に大きくしてみる。(thx. tさん)
- Value rBeta = ttValue - 8 * depth / ONE_PLY;
+ Value rBeta = ttValue - 50 * depth / ONE_PLY;
→ 0.1秒対局で確かに5%ぐらい勝ち越している感じ..
marginが、こんなに大きいと終盤でのone replyっぽいところだけが延長されるような気が..
でも効果があるということなのか…。
rtime = 0.5秒で試してみる。
48.8%
#118
やねうら王classic-tce V249
singular調整, 1スレッド、0.1秒設定
#0
やねうら王classic-tce V248a
tce版, 1スレッド、0.1秒設定
335-61-351(74.2% R-8.1)
負けとる。やはりsingular、判定か何かがおかしいのか?
V2.49a
singular、8に戻してやってみる。
+ Value rBeta = ttValue - 8 * depth / ONE_PLY;
rtime = 500
52.8%
#119
やねうら王classic-tce V249a
singular調整, 1スレッド、0.1秒設定
#0
やねうら王classic-tce V248a
tce版, 1スレッド、0.1秒設定
180-49-161(13.9% R19.4)
確かに少し長い時間においてはR20ぐらい上がりそうではあるが、もう少し条件を変えてテストしてから考えよう。
■ 2016/04/06 V2.48
・rtime指定しているのにtce版のほうがR50ほど高い。タイマーの判定の問題?
V2.48a
・秒読み、ゼロ初期化忘れていた。これが送られてこないときにおかしくなっていた。
LimitsType() {
- nodes = time[WHITE] = time[BLACK] = inc[WHITE] = inc[BLACK] = npmsec
+ nodes = time[WHITE] = time[BLACK] = inc[WHITE] = inc[BLACK] = byoyomi[WHITE] = byoyomi[BLACK] = npmsec
= depth = movetime = mate = infinite = ponder = rtime = 0;
timeman.cpp
+ // remain_timeにもこれを代入しておかないとround_up()が正常に出来なくて困る。
- minimumTime = optimumTime = maximumTime = limits.rtime + (int)prng.rand(limits.rtime * 2);
+ remain_time = minimumTime = optimumTime = maximumTime = limits.rtime + (int)prng.rand(limits.rtime * 2);
・それでもまだ強そう..わけわからん…。タイマーの判定の問題とかありそうだが…。
56.6%
#117
やねうら王classic-tce V248a
tce版, 1スレッド、0.1秒設定
#0
やねうら王classic V238
mate1ply()修正, 1スレッド、0.1秒設定
703-100-540(0.0% R45.8)
■ 2016/04/04 V2.47
・singular率、表示させてみる。
・check_time()に統計情報を表示するためのdbg_print()追加する。
// singular extentionが生じた回数の統計を取ってみる。
dbg_hit_on(extension == ONE_PLY);
とか書くと1秒ごとに統計情報が表示されるようになった。これは便利。
Value rBeta = ttValue - 8 * depth / ONE_PLY;
においてsingular率は10%程度のようだ。
なんでこれで意味ないんやろか…。わけわからん…。
・定跡抜けたところでいきなり悪くなってる局面ありすぎ。なんなの、この定跡。
定跡の指し手、16手ぐらいまでにすべき。
・最小思考時間設定1秒において、Time.minimum()の値がマイナスになっている?修正。
・ minimumを間違えて minimalって書いてたの修正。
・MinimumThinkingTimeの最小値を1000に変更。
・合ってた。Options[".."] = "1000"; って書くとboolの代入になるのか…なにこれ。
Options[".."] = std::string(1000);
って書かないといけない。マジか。なんなのこれ。
怖いからコピーコンストラクタ追加しておく。
Option& operator=(const char* ptr) { return *this = std::string(ptr); };
・singular extensionもっと原因を調べる
・singular率 以下のようにした場合20%程度。
- Value rBeta = ttValue - 8 * depth / ONE_PLY;
+ Value rBeta = ttValue - 2 * depth / ONE_PLY;
正しく動いているようだが…。
・floodgate、NetworkDelay2 = 1000ぐらいにしないと切れ負けする。なにこれ。
■ 2016/04/04 V2.46
・go ponderなのにbestmove返してる…。修正。
position startpos moves 7g7f 1c1d 2g2f 7a6b 3g3f 8c8d 2f2e 4a3b 3i4h 8d8e 8h7g 3c3d 7i8h 6c6d 2e2d 2c2d 2h2d 6b6c 6i7h 6c5d 2d3d P*2h 3d2d 2h2i+ 2d2i 2b7g 8h7g 3a2b 5i6h 9c9d P*2d 4c4d B*2c 3b3c 2c5f+ 4d4e 5f6f B*5e 6f5f 6d6e 5f5e 5d5e 2d2c+ 3c2c B*4c 2a1c 4c6e+ 5e4d 6e6f 2c3c P*2c 2b3a 4g4f B*5d 4i3h 4e4f 3h3g 8b6b 3g4f 8e8f 8g8f 6b6f 7g6f B*3h 2i3i 3h2g+ 2c2b+ 3a2b 4f5e 4d5e 6f5e 5d3f S*4g P*3h 4g3f 2g3f 3i2i P*2h 2i2h P*2f 2h3h P*3g 4h3g 3f4g 3h3i N*6e 5e6f 1c2e 3g2f S*3h B*9f 7c7d 3i5i 8a7c 6h7i 4g4h 9f7d G*3a R*8a 4h5i 7d6c+ 5a4b 2f2e 4b3b P*3d R*2i 8a8b+ 3b2a 3d3c+ 5i1e 7i8h 1e3c P*3d 3c6f 6g6f P*3b N*4c 2i2e+ 4c3a+ 2b3a 3d3c+ S*5b 6c5b 6a5b 8b5b S*2b B*4c 2b3c 4c2e+ P*8g 8h8g N*9e 8g9h B*4e R*6a 4e3d 2e3d 3c3d
go ponder btime 0 wtime 38000 byoyomi 10000
if (!Limits.mate
&& bestValue >= VALUE_MATE_IN_MAX_PLY
&& (VALUE_MATE - bestValue) * 2 < rootDepth)
- Signals.stop = true;
+ break;
■ 2016/04/04 V2.45
・floodgateに投入している版、time upで負けた。
勝ちを読みきっているが、将棋所の表示が追いつかずに、将棋所がフリーズしていて、その間の時間ロスで
負けてる感じ。これはひどい。
mateを読みきったとき、そのmateの倍以上、iterationを回しても仕方ないのでは…。
position startpos moves 2g2f 4a3b 7g7f 8c8d 2f2e 8d8e 6i7h 8e8f 8g8f 8b8f 2e2d 2c2d 2h2d P*2c 2d2f 8f8b P*8g 7a7b 3i3h 3c3d 1g1f 7c7d 3g3f 7b7c 3h3g 7c6d 4i3h 8a7c 5i5h 6a7b P*2d 2c2d 2f2d 5a5b 3g4f 8b8a 1f1e P*2c 2d3d 2b8h+ 7i8h 4c4d 8h7g 2a3c 3d4d 3a4b P*2d 4b4c B*1f P*3d 4d3d 4c3d 1f3d 5b6b 2d2c+ 3b2c 3d2c+ R*2e P*2g 2e2c S*3d 2c2a 3d3c+ P*2f 2g2f 2a2f G*2g 2f2d P*2f 6d6e 2i3g P*8h 7h8h 7c8e 3g4e 8e7g+ 8i7g 6e5d N*6e 5d4e 4f4e 6c6d 3c3d 2d2b 3d4c 6d6e N*6d 6e6f 6g6f S*6g 5h4h N*7c 6d7b+ 6b7b 4c5c N*7a 1e1d B*6d 1d1c+ 2b2a 1c1b 2a4a 1b1a 4a4e L*8f 8a8f 8g8f 6d5c S*5d S*5i 4h3i S*4h 3i2i L*3g 2g3g 4h3g+ 3h3g 5c2f R*2b N*6b 2b2f+ G*2e L*8d P*8b B*3d 7b8a 5d6c+ 7a6c 3d6a+ S*7a
go btime 0 wtime 0 byoyomi 10000
・秒読み10秒として、
9.4秒で指すけど、切れ負けの瞬間でないなら、X.8秒ぐらいまで思考するのは有りなのでは…。
NetworkDelayMinとNetworkDelayMaxみたいな感じで前者として200、後者として600を指定する、みたいな?
NetworkDelay : 通信時の平均遅延時間[ms]
これを例えば200に設定しておくと、4.2秒で指さずに、4.8秒(200ms早め)まで考えるようになります。
NetworkDelay2 : 通信時の最大置換時間[ms]
これを例えば600に設定しておくと秒読み10秒で、切れたら負けという瞬間に限り、9.4秒(600ms早め)に指し手を返します。
こう変更する。
・exeフォルダにclassic-tce関連のファイル追加。
・goでrtimeが指定されているときにbyoyomiを設定するのまずいのか..修正。
・
> test timeman
そこそこうまく動いているように見える。
もっかいfloodgateに投入しておく。
・詰まされている形でiteration回し過ぎ。
if (!Limits.mate
&& bestValue <= VALUE_MATED_IN_MAX_PLY
&& (bestValue - (-VALUE_MATE)) * 3 > rootDepth)
Signals.stop = true;
■ 2016/04/04 V2.44
・あるところから思考時間が倍になったときのレーティング上昇がゆるやかになっていくだろうから、
持ち時間が長い場合、ponderとか時間制御とかが勝率に及ぼす影響は軽微になっていくはず。
・時間制御うまく動いてるなら、classic-TCE版として別途公開するか。
・TCEでR100上がったとしてR3170ぐらいなのか…。評価関数に手番がない分だけ低そう。R70ぐらい損しているのかな。
そして、TCEでR100も上がってなさげ…。
8-3-14
9-1-12
5-1-13
4-1-3
1-0-11
3-0-5
------
58-6-88 0.65%
AperyTwigでR3250ぐらいなので計算合うな。手番入れるとR50-70ぐらい上がるということで…。
・持ち時間制御のハイパーパラメーター、実験で改善するのはちょっときついような。
短い持ち時間だと正確ではないし、定跡の質にも左右されるし…。
定跡部もう少し作ってからにする。
・将棋所でhangしていたログ
<1:readyok
>1:usinewgame
>2:usinewgame
>1:position startpos
>1:go btime 480000 wtime 480000 byoyomi 0
<1:info pv 4g4f 4c4d (0.00%) score cp 0 depth 32
<1:info pv 4i5h 8c8d (0.00%) score cp 0 depth 32
// omit
<1:bestmove 3g3f
>2:position startpos moves 3g3f
>2:go btime 479000 wtime 480000 byoyomi 0
<2:info depth 22 seldepth 23 score cp -2162 nodes 4302298 nps 15875638 time 271 pv G*3c 2c3c 3b3c 1d2e 3c8h 4e4f P*4d 4f4g+ 4d4c+ 2f2g 8h3c 1g2f 4c4d 3e4d 3c4d 2f4f 5c5d G*4e 4d5c 4f5f 5c8f 5f8f
<2:info depth 23 seldepth 26 score cp -2069 lowerbound nodes 7153667 nps 1405988 hashfull 30 time 5088 pv 1b2c+
前の探索が終わってない感じ?
>2:position startpos moves 7g7f 8b5b 3i4h 5c5d 5i6h 5a6b 6h7h 3c3d 8h2b+ 3a2b 9g9f 6b7b 7h8h 2b3c 7i7h 7b8b 9f9e 9a9b 4h5i 8b9a 5i6h 7a8b 6g6f 4a5a 2g2f 3c4d 2f2e 4d3e B*4e 5b3b 4e5d 5a5b 5d4e 4c4d 4e5f 2a3c 2e2d 3e2d 5f3d 3b2b 4i5h 6a7a 4g4f 5b5c 3d6g 5c4c 6h7g 2d2e 8g8f 2c2d 2h4h B*2g 4f4e 2g4e+ 6g4e 3c4e P*4f 4e3g+ 2i3g 2e2f B*6e B*5d 6e5d 4c5d B*3c 2b3b 3c1a+ 3b3g+ 1a2a 5d5c N*9d 9c9d 9e9d P*9f L*9c 8a9c 9i9f N*8d 9f9e P*5f 9d9c+ 9b9c 9e9c 8b9c L*9e P*9d N*8e L*9b 2a6e 9c8b 6e5f N*6d P*9c 9b9c 5f8c 8d7f 8h9h L*9b 8e9c+ 9b9c P*9b 9a8a L*8e 9d9e 8c9c L*9f L*9g 8a7b 8e8b+ 7a8b 9c8b 7b8b 9b9a+ 9f9g+ 8i9g L*9f L*8e 8b7b S*8g N*7e P*7d 7e8g+ 7h8g 3g4h 8e8c+ 7b8c N*7e 8c7b 5h4h 9f9g+ 9h9g R*9i L*9h 9i6i+ R*9b L*8b 7d7c+ 7b7c P*7d 7c7d G*6e 7d7c P*7d 7c6b 9b8b+ 6b5a 8b8a 5a4b 8a9b 4b3c 9b9e B*5i 7d7c+ 5i7g+ 9g9f 7g8g 9f8e 6i1i 7e6c+ 5c6c 7c6c S*8c 8e7e P*6b 6c7c P*9d 9e8e S*8d 8e8d 8c8d 7e8d R*6h 6e5d 6h4h+ S*4c 3c2c G*1f 4h4f S*3b 2c1d 4c3d G*2b 1f2f 4f2f L*1f 2f1f 1g1f 1i1f R*4b B*6g 3b4c S*3c 4b6b+ 3c3d 6b2b G*2c 2b5b 8g8f 8d9c 3d3e 6f6e P*3f 6e6d 3f3g+ 6d6c+ 1d2e 9c9b 7f8h+ 4c3b G*3c P*8d 8f7f 8d8c+ 3c3b N*2i S*2h P*1g 2h1g+ S*5f 6g5f+ 5g5f 3b3c 2i1g 1f1g P*4c S*4e 5d5c 8h9h 4c4b+ S*3d B*4a L*2f 4b3b L*5a 5b5a 3c3b L*7h 7f6e 6c6d 6e6d 4a3b+ 9h8h G*5e 6d8f 7h7d 2f2h+ 9b8a 2e2f 5e4e 4d4e S*1b G*3c 1b2c 3c2c S*1b S*1d
>2:go ponder btime 105000 wtime 149000 byoyomi 0
<1:bestmove S*1d
>1:gameover draw
>2:gameover draw
<2:info depth 20 seldepth 20 score cp -2196 nodes 1310050 nps 600389 hashfull 13 time 2182 pv 1b2c+ 1d2c 3b5d 2f2g G*3c 2g3h G*4d S*2e 4d4e 3d4e 5d4e G*3d 4e5e 3e4d 3c3d 4d5e 3d2c 5e4d 2c2d 8h8g 2d2e
ponder中に引き分けが確定したときにgameover drawが送られてくるが、これに対して探索が終了していないのか。
USIではgameoverの前にstop送らなくて良いことになっているのか…。
修正。
+ if (token == "quit" || token == "stop" || token == "gameover")
・AperyTwigの評価関数portingしてくるのは、あとにしよう。5月の選手権終わったら新しいバイナリが公開されるかも知れないし。
・twig-engine名前変えよう。classic-tce-engineに変更。
■ 2016/04/04 V2.43
・USI拡張コマンド.txtの説明間違っていたの色々修正。
・やねうら王classic、floodgate、6コアPCにてR3072。もう少し放流しておく。あとで正式に公開する。
・ponderが解除された瞬間、elapsed > Time.maximum()の条件を満たすのか…。修正。
・USI_Ponder、設定項目じゃないから要らないのか。そうか…。
- // ponder設定。
- o["USI_Ponder"] << Option(false);
・思考エンジン側からponderモードなのかどうかの判定が出来ないのか…。UCIなら問題ないのに…。
仕方ないのでLimitsにponder_modeを追加。
・時間の使い方のうまい下手を調整するには自己対戦フレームワークで消費時間の処理が出来ないといけないのか…。そうか…。
その部分の改造を考える。
・詰みの局面、ponderhitしたときに指し手返さないのおかしい。
position startpos moves 5i6h 8c8d 6h7h 8d8e 7i6h 8e8f 8g8f 8b8f P*8g 8f8b 7g7f 7a6b 3i3h 7c7d 3g3f 6b7c 3h3g 7c6d 6h7g 3c3d 3g4f 7d7e 7f7e 5a4b 7g6f 3a3b 3f3e 3d3e 2h3h 3e3f 3h3f 6a5b P*3d P*8f 8g8f 8b8f P*8g 8f7f 7h6h P*8f 6i7h 7f7h+ 6h7h 6d7e R*7a 8f8g+ 7h8g G*7f 8g7h P*8f 7h6h 8f8g+ 6h5h 8g8h 6f7e 8h8i 7a8a+ B*1d 3d3c+ 3b3c N*3d 3c3d 3f3d P*3a 3d7d 2b9i+ S*6a N*5d 6a5b+ 4a5b 4f4e 7f6g 5h6g 1d4g+ 7d7a+ S*6f 6g7f 6f7e 7a7e P*7d S*3c 9i3c G*4a 4b3b 4a3a 3b2b 3a2a 2b1b G*2b 3c2b 2a2b 1b2b B*3c 2b3c 8a3a P*3b 4e4d 4c4d 7e3e B*3d S*2b 3c4c N*5e
go ponder btime 127000 wtime 49000 byoyomi 0
ponderhit
+ // 詰みの局面が"ponderhit"で返ってくることがあるので、ここでのpv[0] == MOVE_RESIGNであることがありうる。
+ if (!is_ok(pv[0]))
+ return false;
→ 修正した。
・ponder有効にしてランニングさせておく。
・切れ負けルールのときに長考するのまずいな。
float max_ratio = 5.0f;
// 切れ負けルールにおいては、5分を切っていたら、このratioを抑制する。
if (limits.inc[us] == 0 && limits.byoyomi[us] == 0)
{
// 3分 : ratio = 3.0
// 2分 : ratio = 2.0
// 1分以下 : ratio = 1.0固定
max_ratio = std::min(max_ratio, std::max(float(limits.time[us])/(60*1000),1.0f));
}
int t2 = minimumTime + remain_estimate * max_ratio / MTG;
・Timer回すから、Limits.startTimeって要らないのでは…。Stockfishの設計もこの部分おかしい。
→ 削除した。
・ponderhitしたときの思考時間がおかしい。
position startpos moves 2g2f 5a4b 2f2e 4b3b 7g7f 3c3d 2e2d 2c2d 2h2d 2b8h+ 7i8h 3a2b 2d3d 2b3c 3d3f P*2c 5i6h B*2g 3i3h 2g3f+ 3g3f 7a6b 2i3g R*2f 4i3i 2f3f 8h7g 3c4d 3i2h 3f3e B*4f 3e8e 8g8f 8e9e 3h2g 8c8d 9g9f 9e6e B*5f 6e6d 4f6d 6c6d 2g3f B*7d 4g4f 7d5f 5g5f 4d3c P*3d 3c2b 3g2e 6a5b 2h3h 8d8e 8f8e 7c7d 3h4g 5b4b B*6f B*4d 6i7h 4d6f 6g6f B*3h 8e8d 8b8d 6h7i 8d8b P*8c 8b8c P*8g 3h2i+ B*5e 2i1i 5e6d L*8d 7i8h P*3e 3f3e 1i2i 6d9a+ 2i4g L*3c 4b3c 3d3c+ 2b3c 2e3c+ 2a3c P*3d G*6g 3d3c+ 3b3c 9a5e 3c4b N*8f 6g7h 8h7h
go ponder btime 199000 wtime 113000 byoyomi 0
ponderhit
- const int MoveHorizon = 70;
+ const int MoveHorizon = 80;
// goコマンド、デバッグ時に使うが、そのときに"go btime XXX wtime XXX byoyomi XXX"と毎回入力するのが面倒なので
// デフォルトで1秒読み状態で呼び出されて欲しい。
+ if (limits.byoyomi[BLACK] == 0 && limits.inc[BLACK] == 0 && limits.time[BLACK] == 0)
limits.byoyomi[BLACK] = limits.byoyomi[WHITE] = 1000;
条件間違ってた。切れ負けを、秒読み1秒と解釈してた。
・以上の修正をして5分切れ負け、ponder有りでclassicと対戦させておく。
・floodgateにclassicのTCE(Time-Control Enabled)版として放流しておく。
6スレッド、narrow book、ponder有り。hash = 4096MB。
■ 2016/04/03 V2.42
・将棋ではstopOnPonderhit自体がおかしい。ponderhitしても2秒は思考したほうが良いのだから…。
- // 思考は終了しているからponderhitが送られてきたらSignals.stopをtrueにして欲しいときに使う。
- std::atomic_bool stopOnPonderhit;
- // 一応、思考はいつ止めても良いのだが、キリの良い時間(最小思考時間を超えた瞬間だとか、
- // ちょうど一秒として計測される手前とか)になったら停止させたいの意味。
- std::atomic_bool weak_stop;
/*
// もしponder中であるなら、ponderhitが来れば停止。
if (Limits.ponder)
Signals.stopOnPonderhit = true;
else
Signals.stop = true;
*/
・check_time()で統計情報みたいなのを出力する機能、要るかなぁ…。
#if 0
static TimePoint lastInfoTime = now();
int elapsed = Time.elapsed();
TimePoint tick = Limits.startTime + elapsed;
// 1秒ごとにdbg_print()を呼び出して統計情報などを出力する用。
if (tick - lastInfoTime >= 1000)
{
lastInfoTime = tick;
dbg_print();
}
#endif
・ponderhitまわり、きちんと書けた(気がする)
それにしてもStockfishのコード、相変わらずバグっていて、ponderhit待ちになった瞬間にponderhitすると(極めてレアケースだが)
ハングするような…。このコード、2年も経つのにまだなおってないのか…。
・ponder、独自にやっても将棋所がponderの局面を送ってこない…。そうか…。
■ 2016/04/03 V2.41
・やねうら王twig、タイマースレッドの廃止。
・Timerクラス、reset()とinit()と分ける。
従来のinit()→reset()
init()→理想的な思考時間を得るためのTimeManger。
・config.hにUSE_TIME_MANAGEMENT追加
・benchコマンド時に2個目以降の局面で正しくnpsが表示されなかった問題を修正。
・解説.txtに書いてなかったファイルの説明追加。
・TimeManagerのテスト用のコマンドを追加
> test timeman
→ そこそこうまく使っているように見える。
■ 2016/04/03 V2.40
・やねうら王classicは開発終了。6コア時、floodgateでR3000を超えているようだったので。
・やねうら王classic、exe/フォルダに放り込む。
・やねうら王classic、exe/フォルダにreadme追加。
・やねうら王twigにfork。
・やねうら王twigにponder機能入れるための準備。
・singular延長で強くなるのは、あるnodeで1手だけが特別に良い場合、相手のプレイヤーもそのnodeでは
その指し手を選択する可能性が高く、それゆえ、相手のPVもそこである可能性が高いから、そこを相手よりわずかにでも
読んでいて詰みを回避などできるなら、その相手に対する勝率は上がるという理屈。
いわば、0.5手延長が自己対戦で(のみ)強くなるのの拡張。
そう考えるとベストな指し手のスコアと2番目にベストな指し手のスコアとの差に応じて1手延長するのが正しいのだが、
2番目にベストな指し手のスコアを小さなコストで求めることは出来ないので…。
・Positionのkey()まわりの名前が気持ち悪い。
board_key()とかのほうが良いのでは…。
→ せっかくなので全部変更する。
■ 2016/04/03 V2.38 classic版final
・mate1ply修正。(thx.tさん)
const uint8_t long_effect8_table[PIECE_NB] = {
0,0,DIRECTIONS_U/*香*/,0,0,BISHOP_DIR/*角*/,ROOK_DIR/*飛*/,0,0,0,0,0,0,BISHOP_DIR/*馬*/,ROOK_DIR/*龍*/,0, // 先手
0,0,DIRECTIONS_D/*香*/,0,0,BISHOP_DIR,ROOK_DIR,0,0,0,0,0,0,BISHOP_DIR,ROOK_DIR,0, // 後手
};
inline Directions long_effect_of(Piece pc) { return (Directions)long_effect8_table[pc]; }
追加。mate1ply()では、long_effect16_of()ではなく、こちらを呼び出すように修正。
修正前
> test rp
Random Player test , loop_max = 100000000
mate found = 10000 , mate miss = 747 , mate found rate = 93.0492%
mate found = 20000 , mate miss = 1471 , mate found rate = 93.1489%
mate found = 30000 , mate miss = 2201 , mate found rate = 93.1648%
mate found = 40000 , mate miss = 2969 , mate found rate = 93.0904%
mate found = 50000 , mate miss = 3792 , mate found rate = 92.9506%
mate found = 60000 , mate miss = 4659 , mate found rate = 92.7945%
mate found = 70000 , mate miss = 5444 , mate found rate = 92.7841%
mate found = 80000 , mate miss = 6270 , mate found rate = 92.7321%
mate found = 90000 , mate miss = 6959 , mate found rate = 92.8227%
mate found = 100000 , mate miss = 7754 , mate found rate = 92.804%
修正後
> test rp
Random Player test , loop_max = 100000000
mate found = 10000 , mate miss = 745 , mate found rate = 93.0665%
mate found = 20000 , mate miss = 1460 , mate found rate = 93.1966%
mate found = 30000 , mate miss = 2180 , mate found rate = 93.2256%
mate found = 40000 , mate miss = 2937 , mate found rate = 93.1597%
mate found = 50000 , mate miss = 3755 , mate found rate = 93.0146%
mate found = 60000 , mate miss = 4612 , mate found rate = 92.862%
mate found = 70000 , mate miss = 5379 , mate found rate = 92.8641%
mate found = 80000 , mate miss = 6197 , mate found rate = 92.8107%
mate found = 90000 , mate miss = 6876 , mate found rate = 92.9023%
mate found = 100000 , mate miss = 7665 , mate found rate = 92.8807%
詰み発見率が0.1%弱増加
50.5%
#115
やねうら王classic V238
mate1ply()修正, 1スレッド、0.1秒設定
#0
やねうら王classic V237
nonPVのreduction調整, 1スレッド、0.1秒設定
767-141-753(36.0% R3.2)
■ 2016/04/02 V2.37
・singularのテスト
bool singularExtensionNode = !RootNode
+ && depth >= (param1 + 2)*2 * ONE_PLY // 8 * ONE_PLY
singularの条件を調べる。param1 = 0..3で。
35.8% 44.6% 43.9% 51.4%
#114
やねうら王classic V237b
singularの調整, 1スレッド、0.1秒設定
#0
やねうら王classic V237
nonPVのreduction調整, 1スレッド、0.1秒設定
343-83-614(100.0% R-101.1) 346-96-430(99.9% R-37.8) 325-92-415(100.0% R-42.5) 392-69-371(21.3% R9.6)
depth >= 10 * ONE_PLY
のときにはわずかに効果がありそうだが、効果が乏しすぎるので怪しい。
何か他の条件がおかしいのかも。
singularについては、もう少し他の部分を作りこんでからさらにテストすべき。
■ 2016/04/02 V2.36
・non PV時のreduction調整。
0.1ずつ 動かしてみる。
double K[][2] = { { 0.799 + (param2-1)*0.1 , 2.281 + (param1 - 1)*0.1 },{ 0.484 + 0.1 , 3.023 + 0.05 } };
param1,2 = 0..2の範囲で。
・position sfen 3S+R+P3/3R1K+P+LP/1gp1+B+P2+P/p2+b2gS1/g8/1P1kp4/P2+p2n+p1/7+s1/+p1+l1+s4 b 5P2L3NG 245
49.7% 48.9% 51.4%
50.8% 49.5% 51.2%
49.2% 50.7% 50.1%
#112
やねうら王classic V236
nonPVのreduction調整, 1スレッド、0.1秒設定
#0
やねうら王classic V235
宣言勝ち, 1スレッド、0.1秒設定
647-155-654(57.7% R-1.9) 639-149-668(78.9% R-7.7) 686-121-649(15.6% R9.6)
671-134-651(29.1% R5.3) 655-119-669(65.0% R-3.7) 583-110-555(20.3% R8.6)
546-138-564(70.5% R-5.6) 577-109-562(32.8% R4.6) 575-101-572(46.5% R0.9)
param1 = 2 , param2 = 0が最適。
double K[][2] = { { 0.799 - 0.1 , 2.281 + 0.1 },{ 0.484 + 0.1 , 3.023 + 0.05 } };
・local server、よく考えたらbestmove winのwinをparseできてない可能性が…。
+ if (str == "win")
+ return MOVE_WIN;
あらら。ということは、入玉宣言で強くなったと思っていたのは間違っていた…。
■ 2016/04/02 V2.35
・入玉宣言勝ちまわりの処理
・MOVE_WIN追加
・extra/entring_king_win.cpp追加。
・local-server、入玉判定に対応。
・mate1ply()で宣言勝ちを1手詰めの指し手として返すように。
#ifdef USE_ENTERING_KING_WIN
// 宣言勝ちであるならそれを1手詰めの指し手として返す。
return DeclarationWin();
#else
→ mate1ply毎nodeで呼ばないから、これは良くない。
classicで、宣言勝ち、毎node調べるように変更。
・入玉宣言勝ちのテスト
position sfen Kn1g1gsnl/+Pl7/2ppppppp/9/9/9/P+p+p+p+p+p+p+p+p/3g1+bs+rk/+l+nsg2+s+n+l w rbp 1
宣言勝ちを含むmate 3
position sfen K+N+S3+S+N+L/+P+R5+B1/1+P+P+Pppppp/9/9/2P6/PPBPPPPPP/9/LNSG1GSNk b RL2gl 1
position sfen +L2+B+B+R+L1+P/6+P2/p2K+P1S+L1/5p2g/5g3/2S3+rk1/PP1P2+p2/3+p1P1g+n/LN2+p1+p2 b 3P2NS2psg 247
・classicでrootで1手詰め判定を呼び出すように変更。
・3駒のテーブル、コンバート間違えてた件で、読み込み時に変換するために
確保している配列、動的に確保するように変更。(メモリがもったいないため)
・宣言勝ちによって勝率が変わっているかどうか調べる。
いままで宣言勝ちを逃していた局面において効果が出るはず…。
V2.35 vs V2.34b
52.3%
#111
やねうら王classic V235
宣言勝ち, 1スレッド、0.1秒設定
#0
やねうら王classic V234b
captureのオーダリング修正, 1スレッド、0.1秒設定
482-83-440(7.8% R15.8)
■ 2016/04/02 V2.34
V2.34a
・evasionのorderingで、駒を打つのをSEE<0なのにゼロ扱いしているのはさすがにおかしいな。
ただで取られるところへの合駒をしている指し手とかがあるわけで…。
- // 駒を打つ指し手であるならゼロ扱い
- if (is_drop(m))
- m.value = VALUE_ZERO;
V2.34a vs V2.34
199-44-192(+R6.2)
ほぼ変わらず。レアケースなので影響はほぼ無いのか?
V2.34b
・captureのorderingも、歩のとき、成り + 捕獲する駒の値になっているほうが良いな…。
m.value = (pawn_promo ? (Value)(Eval::GoldValue - Eval::PawnValue) : VALUE_ZERO)
+ (Value)Eval::PieceValueCapture[pos.piece_on(move_to(m))];
これもレアケースなので勝率に影響はなさげ。
51.8%
#110
やねうら王classic V234b
captureのオーダリング修正, 1スレッド、0.1秒設定
#0
やねうら王classic V234
reduction定数調整後, 1スレッド、0.1秒設定
780-154-725(7.8% R12.7)
そこそこ上がってた。
■ 2016/04/01 V2.33
・MovePickerにfollowupのhistory追加。
const CounterMoveStats* followupMoveHistory;
→ nano plusのほうは、まあ、コンパイル通るだけでいいや。
・followupのhistoryに基いてquietの指し手のオーダリングを行なう。
score_quiet()
m.value = history[move_to(m)][pos.moved_piece(m)]
- + (*counterMoveHistory)[move_to(m)][pos.moved_piece(m)];
+ m.value = history[move_to(m)][pos.moved_piece(m)]
+ + (*counterMoveHistory) [move_to(m)][pos.moved_piece(m)]
+ (*followupMoveHistory)[move_to(m)][pos.moved_piece(m)];
・これに伴い、update_stats()も修正。
V2.33 vs V2.30
231-30-236
→ ほぼ互角
V2.33a
・LMRのreduction tableの定数をStockfishに倣う。
double r = log(d) * log(mc) / 2;
if (r < 0.80)
continue;
reduction_table[NonPV][imp][d][mc] = int(std::round(r)) * ONE_PLY;
reduction_table[PV][imp][d][mc] = std::max(reduction_table[NonPV][imp][d][mc] - ONE_PLY, DEPTH_ZERO);
V2.33a vs V2.30
186-22-236
-R41
他のパラメーターが以前のreduction tableの値に依存しているのでここだけ変えても逆効果のようだ。
もうちょっと調整頑張る。
・Stockfishのreductionのテーブル、おかしいな。
> template <bool PvNode> Depth reduction(bool i, Depth d, int mn) {
> return Reductions[PvNode][i][std::min(d, 63 * ONE_PLY)][std::min(mn, 63)];
> }
return Reductions[PvNode][i][std::min(d / ONE_PLY, 63 )][std::min(mn, 63)];
こうが正しい。
V2.33b
・reduction定数、grid searchしてみる。
double r = log(d) * log(mc) / (1.25 + param1 * 0.25);
として、param1 = 0..6ぐらいで。
いやー、grid search、こうやるか。
double r = (param2 * 0.25) + log(d) * log(mc) / (1.25 + param1 * 0.25);
param2 = 0..4
38.2% 35.5% 46.4% 35.2% 38.3% 41.8% 49.2%
31.6% 46.4% 36.8% 40.2% 38.1% 43.0% 37.6%
28.7% 34.4% 39.7% 44.1% 35.9% 37.8% 41.6%
26.2% 44.0% 39.5% 42.4% 41.0% 38.1% 36.9%
29.4% 31.7% 37.9% 42.7% 43.4% 37.6% 42.5%
#104
やねうら王classic V233b
reduction定数調査用, 1スレッド、0.1秒設定
#0
やねうら王classic V230
新標準, 1スレッド、0.1秒設定
73-17-118(100.0% R-83.4) 70-11-127(100.0% R-103.5) 89-16-103(86.1% R-25.4) 68-15-125(100.0% R-105.8) 75-12-121(100.0% R-83.1) 76-26-106(98.9% R-57.8) 96-13-99(61.3% R-5.3)
62-12-134(100.0% R-133.9) 90-14-104(85.9% R-25.1) 70-18-120(100.0% R-93.6) 76-19-113(99.7% R-68.9) 75-11-122(100.0% R-84.5) 83-15-110(97.8% R-48.9) 74-11-123(100.0% R-88.3)
56-13-139(100.0% R-157.9) 65-19-124(100.0% R-112.2) 79-9-120(99.9% R-72.6) 86-13-109(95.7% R-41.2) 70-13-125(100.0% R-100.7) 73-15-120(100.0% R-86.3) 79-18-111(99.2% R-59.1)
50-17-141(100.0% R-180.1) 85-15-108(95.8% R-41.6) 77-13-118(99.9% R-74.2) 81-17-110(98.5% R-53.2) 82-8-118(99.6% R-63.2) 72-19-117(100.0% R-84.3) 73-10-125(100.0% R-93.4)
57-14-137(100.0% R-152.3) 63-9-136(100.0% R-133.7) 75-10-123(100.0% R-85.9) 82-16-110(98.2% R-51.0) 82-19-107(97.1% R-46.2) 71-19-118(100.0% R-88.2) 71-18-96(97.8% R-52.4)
param1が6だと1.25+6*0.25 = 2.75。以前のがPVのときに3で割っていたので、もうちょっと大きくないといけなかったのか。
V2.33c
double r = (param2 * 0.1) + log(d) * log(mc) / (2.70 + param1 * 0.1);
とりあえずparam1 = 0..4ぐらいであたりをつけるか。
42.8% 44.7% 38.8% 34.4%
#105
やねうら王classic V233c
reduction定数調査用, 1スレッド、0.1秒設定
#0
やねうら王classic V230
新標準, 1スレッド、0.1秒設定
83-14-111(98.1% R-50.5) 88-11-109(94.2% R-37.2) 78-7-123(99.9% R-79.1) 62-12-118(100.0% R-111.8)
param==1が最適みたいだけど、PV時とnonPV時と分かれてないのでパラメーターの調整が困難。
これに変えるぐらいなら以前のコードでパラメーターの調整をしたほうがよさ気。
V2.33d
元のコードに対してPV時に0.1ずつ動かして調整してみる。
double K[][2] = { { 0.799, 2.281 },{ 0.484 + (param2-1)*0.1 , 3.023 + (param1-1)*0.1 } };
param1,2 = 0..2で。
48.4% 45.4% 45.6%
51.1% 48.3% 45.2%
44.5% 51.5% 52.1%
#106
やねうら王classic V233d
reduction定数調査用, 1スレッド、0.1秒設定
#0
やねうら王classic V230
新標準, 1スレッド、0.1秒設定
184-39-196(74.8% R-11.0) 171-39-206(96.8% R-32.3) 175-32-209(96.3% R-30.8)
201-23-192(30.7% R8.0) 189-25-202(76.1% R-11.6) 175-29-212(97.3% R-33.3)
171-32-213(98.6% R-38.2) 201-26-189(25.5% R10.7) 201-30-185(19.3% R14.4)
param1 = param2 = 2がベストっぽい。
V2.33e
・もう少し細かくしてみる。
double K[][2] = { { 0.799, 2.281 },{ 0.484 + 0.1 + (param2-1)*0.05 , 3.023 + 0.1 + (param1-1)*0.05 } };
param1,2 = 0..2で。
勝率が低いのは、0.1秒だとこのテーブルの初期化に要する時間が無視できないからかも。
47.5% 49.9% 45.9%
52.6% 50.7% 49.1%
48.7% 47.9% 51.6%
#107
やねうら王classic V233e
reduction定数調査用, 1スレッド、0.1秒設定
#0
やねうら王classic V230
新標準, 1スレッド、0.1秒設定
364-65-403(92.6% R-17.7) 385-61-386(52.9% R-0.5) 360-48-424(99.0% R-28.4)
409-55-368(6.6% R18.4) 387-68-377(34.5% R4.5) 379-60-393(70.5% R-6.3)
380-51-401(78.4% R-9.3) 372-55-405(88.9% R-14.8) 380-57-357(18.8% R10.8)
Param1 = 0,Param2 = 1で最大。
double K[][2] = { { 0.799, 2.281 },{ 0.484 + 0.1 + (1-1)*0.05 , 3.023 + 0.1 + (0-1)*0.05 } };
double K[][2] = { { 0.799, 2.281 },{ 0.484 + 0.1 , 3.023 + 0.05 } };
ゆえに、こう変更しておくる
■ 2016/04/01 V2.32
・やねうら王classicの探索部、もう少し調整する。
singluar extensionのパラメーター調整する。
else if (singularExtensionNode
&& move == ttMove
+ && !extension // 延長が確定しているところはこれ以上調べても仕方がない。
&& pos.legal(move))
↑この条件忘れてた。
Value rBeta = ttValue - (param1 + 1) * depth / ONE_PLY; // margin = 2 * depth / ONE_PLY
今日は、param1 = 0..9でひたすら回しておく。
44.9% 44.0% 43.5% 45.5% 46.9% 49.5% 48.0% 49.7% 48.1% 50.3%
#100
やねうら王classic V232
singularのテスト, 1スレッド、0.1秒設定
#0
やねうら王classic V230
新標準, 1スレッド、0.1秒設定
263-38-323(99.4% R-35.7) 253-49-322(99.8% R-41.9) 253-42-329(99.9% R-45.6) 189-40-226(96.9% R-31.1) 179-34-203(90.0% R-21.9) 190-32-194(60.1% R-3.6) 184-33-199(79.3% R-13.6) 188-38-190(56.1% R-1.8) 188-25-203(79.1% R-13.3) 190-38-188(43.9% R1.8)
どうやっても良くならない。評価関数の質が悪いのか、singularに関連する処理の何かがバグっているのか…。
singularのときにdo_move()せずにsearch()を再帰的に呼び出すと
ss->moveCountが破壊されてしまうのでmoveCountベースの枝刈りがきちんと機能しない?
→ そうでもないような…。ローカル変数にあるしな..
V2.32a
ss->skipEarlyPruning = false;
+ ss->moveCount = moveCount; // 破壊したと思うので修復しておく。
ss->excludedMove = MOVE_NONE;
これを追加して、param1 == 7固定で
Value rBeta = ttValue - (7 + 1) * depth / ONE_PLY; // margin = 2 * depth / ONE_PLY
として対戦させてみる。これであかんかったらsingularはしばらくおあずけ。
これでうまくいくなら他の値もgrid searchする。
376-68-383
-R3.2
やらないほうがマシか…。仕方ない。コメントアウトしておく。
■ 2016/04/01 V2.31
・update_stats()でのボーナス、ONE_PLYで正規化すべき。
// depthの二乗に比例したbonusをhistory tableに加算する。
- Value bonus = Value(depth*(int)depth + (int)depth + 1);
+ Value bonus = Value((int)depth*(int)depth / ((int)ONE_PLY*(int)ONE_PLY) + (int)depth / (int)ONE_PLY + 1);
V2.31 vs V2.30
250-42-250
ほぼ変わらず。
・update_stats()、1手前がNULL MOVEかどうかで場合分けしたほうがソースコードがすっきりするので修正。
・bench走らせるごとにnode数が変わるようになってしまった…。
何かやらかしている。
→ 今回の修正コメントアウトしても一致しない。
→ benchで何かクリアしていないものがあるのでは。
→ そうでもなさげ。
→ mate1も関係なさげ。
→ recaptureでスコアつけてないのにpick_best()してた。
case GOOD_RECAPTURES:
endMoves = generateMoves<RECAPTURES>(pos, moves, recaptureSquare);
+ score_captures(); // CAPTUREの指し手の並べ替え
break;
→ よし、修正できた。再度、V2.30と対戦。
■ 2016/04/01 V2.30
・Visual Studio 2015 Update2が出たので以前、内部エラーが出てコンパイルできなかったものをshogi.hに移動させる。
inline int hand_count(Hand hand, Piece pr) { ASSERT_LV2(PIECE_HAND_ZERO <= pr && pr < PIECE_HAND_NB); return (hand >> PIECE_BITS[pr]) & PIECE_BIT_MASK[pr]; }
inline int hand_exists(Hand hand, Piece pr) { ASSERT_LV2(PIECE_HAND_ZERO <= pr && pr < PIECE_HAND_NB); return hand & PIECE_BIT_MASK2[pr]; }
inline void add_hand(Hand &hand, Piece pr, int c = 1) { hand = (Hand)(hand + PIECE_TO_HAND[pr] * c); }
inline void sub_hand(Hand &hand, Piece pr, int c = 1) { hand = (Hand)(hand - PIECE_TO_HAND[pr] * c); }
→ Update2ではコンパイルできた!!
・LONG_EFFECT_LIBRARYをオフにして1手詰めをオフ、ASSERT_LV 0にするとclassicでbenchが960Knps程度。
・LONG_EFFECT_LIBRARYをオフにして1手詰めをオフ、ASSERT_LV 0にするとclassicでbenchが800Knps程度。
LONG_EFFECT、なぜにこんなに遅いのか…。evaluate()の差分計算の何かを潰している可能性すらある。
前実験したときこんな遅くなかったはず…。
benchにおけるevaluate()の全計算 / 呼びだされたい回数
109940 / 19000000
→ LONG_EFFECTありでもなしでも変わらなかった。うむむ?
例)
static u64 c1 = 0;
static u64 c2 = 0;
c1++;
if ((c1 % 100000) == 0)
cout << c2 << " / " << c1 << endl;
if (...)
{
c2++;
}
さすがにおかしい。LONG_EFFECT有りの時にどこがボトルネックになっているのかプロファイラで調べる。
LongEffect::update_by_capture..()で、先後、2%ぐらい食ってる。
このrewindでも2%。captureだけで8%。うーん。遅すぎ。rewind()やめたほうが良いのでは…。
てか、これならLONG_EFFECTなしにしてmate1なしのほうが強い可能性が…。
最終的に利きを評価関数に使いたいので、そのときは仕方ないとしても。
100-8-140
一応、long effectの分ぐらいは回収できとるのか…。そうか…。
rewind()無くすと利きのある評価関数使うときに戻すのに困るのか。なら仕方ないか…。
以前計測したときはrewind()含んでなかったのか。そうか。
・やねうら王classicのRecaptureのオーダリング考える。
V2.30a
- move = *currentMoves++;
+ move = pick_best(currentMoves++, endMoves);
どうせrecapの指し手が2つ以上あることは稀なのでここでオーダリングしてもあまり意味をなさない気もするが。
生成される指し手が少ないなら、pick_best()のコストはほぼ無視できるのでやらないよりはマシのような。
V2.30a vs V2.30
295-32-295
変わらず。
■ 2016/03/31 V2.29
・see()のコード、Position::effected_to()を使ったほうが簡潔になるのか。修正。
■ 2016/03/31 V2.28
・benchコマンドのdefaultのdepthを15に変更。
・benchコマンドで内部的にis_ready()を呼び出すように変更。
740knps // ASSERT_LV 3
775knps // ASSERT_LV 0
750knps // ASSERT_LV 3 , mate1ply()呼び出さない。
・LONG_EFFECT_LIBRARYがあるときのSEE高速化。(thx. tさん)
===========================
Total time (ms) : 32204
Nodes searched : 23523154
Nodes/second : 730441
↓
===========================
Total time (ms) : 31058
Nodes searched : 23523154
Nodes/second : 757394
2,3%ぐらい高速化した?ほぼ変わらない気もする。
see()のコード、少し整理した。
■ 2016/03/31 V2.27
・mate1ply修正。(thx. woodyringさん)
- auto cut_dirs = cutoff_directions(to_direct, long_effect.directions_of(Us, to) & (Effect8::Directions)~LongEffect::long_effect16_of(type_of(pc)));
+ auto cut_dirs = cutoff_directions(to_direct, long_effect.directions_of(Us, to) & (Effect8::Directions)~LongEffect::long_effect16_of(pc));
二箇所。
225-22-206(+R15.3)
■ 2016/03/31 V2.26
・やねうら王2015とくらべてnps2割ぐらい低くてhashの使用率が1/3ぐらいしかない。
hashまわり、何かやらかしているのでは。
・やねうら王2015、思考時間0.1秒になってなかった疑惑。
やねうら王2015 vs V2.25 , 1手3秒、1スレッド、256MBでの勝負。将棋所。
31-7-41
勝ち越しとる…。
V2.25だけ定跡使ってるのもあるのかも。
・やねうら王2015と1.7秒設定で対戦させる。
#95
やねうら王classic V225
evaluate修正, 1スレッド、1.7秒固定設定
YaneuraOu-classicV225.exe
go btime 2000 wtime 2000 byoyomi 0
setoption name Hash value 1024
setoption name Threads value 1
setoption name NetworkDelay value 300
#94
やねうら王2015
1スレッド、1.7秒固定設定
YaneuraOu2015.exe
go btime 100 wtime 100 byoyomi 0
setoption name USI_Hash value 1024
setoption name Threads value 1
setoption name TimeLimitMs value 700
setoption name MinimumThinkingTime value 1700
1-0-50
local-serverを使うと圧倒的に負け越す。なぜ?
何かがおかしい…。
btimeで指定しているから、そこ60で割り算した分しか思考時間使ってないからか。
go btime 0 wtime 0 byoyomi 10000
に変更して1手10秒固定
0-0-42
これでも圧倒的に負け。なんでだろ…。原因よく調べる。
やねうら王2015 0.1秒 vs V2.25 1秒
0-0-90
おかしい。
いくらなんでもおかしすぎる。やねうら王2015がカレントフォルダを変更するから、V2.25で評価関数が読み込めていないのか?
→ ビンゴくさい。そうか。そうだったのか…。
やねうら王2015 vs V2.25 0.1秒
→ よし、互角ぐらい。問題ない。
→ これにてやねうら王2015の作業は終了。
・historyなどのbonus、レーティングの簡易計算法のほうがいいかも…。
cf. http://www.computer-shogi.org/wcsc26/appeal/NineDayFever/NDF-2016.txt
■ 2016/03/30 V2.25
・やねうら王2015に色々portingして比較実験してみる。
・perftコマンドにEVAL_PERFTモード追加。
・isreadyコマンドに対してPosition.set(HIRATE_SFEN)で初期化するように。
・やねうら王2015にperftとEVAL_PERFT、porting完了。
・perft 3においてeval(sum)の値が一致しない。たぶん成り駒関係で何かおかしい。
あと、perftの速度が違いすぎ。evalの速度差がひどい。evaluate()で何かやらかしてる。
sfenとevalの値を書き出してcompareするか。
→ 指し手生成の順番が異なるから比較しにくい。
→ sfenでsortして調べるか…。
歩を手持ちにしている局面の評価値がおかしいことがわかった。
e.g. sfen 1nsgkgsnl/lr5b1/pppppp+Bpp/9/9/2P6/PP1PPPPPP/7R1/LNSGKGSNL w P 4
-1002
あれ?全計算において一致する。やねうら王2015の差分計算がバグっている可能性が微レ存。
違うな。やねうら王2015の全計算こそがbugっていて、これと等価になるように今回portingしたからおかしいのか。
全計算は、そのあとすべてが差分計算がなされるのであれば(相対的な比較は出来るから)bugってようが関係がないのか。そうか…。
よくこれで動いてたな。
ああ、evalで差分計算をretireしたときに、compute_eval()呼び出してないから関係なかったのか。そうか。
・なんとなくわかってきた。
BonaPieceで先手の手駒の歩1と、それを相手の駒にしたときに後手の歩1にならないといけないのに
そうなっていない。
→ eval_list自体が間違っているのか。
→ やねうら王2015のPosition::set()がバグっていた。
- st->pieceList[piece_no].fb = BonaPiece(kpp_hand_index[color][raw_piece].fb + i + 1);
- st->pieceList[piece_no].fw = BonaPiece(kpp_hand_index[color][raw_piece].fw + i + 1);
+ st->pieceList[piece_no].fb = BonaPiece(kpp_hand_index[color][raw_piece].fb + i);
+ st->pieceList[piece_no].fw = BonaPiece(kpp_hand_index[color][raw_piece].fw + i);
これにより駒番号がおかしくなっていたのか。これを基準に評価関数をコンバートしたからおかしかったのか。
ということは上の局面は-1075が正しいわけか。
・BonaPiece、後手の駒を正しく << で表示できてなかったのを修正。
・evaluate、コンバーター書く。
// 手駒の添字、コンバートするときにひとつ間違えてた。(๑´ڡ`๑)
for (int k = 0; k < SQ_NB_PLUS1; ++k)
for (int i = 1; i < fe_end; ++i)
for (int j = 1; j < fe_end; ++j)
{
int i2 = i < fe_hand_end ? i - 1 : i;
int j2 = j < fe_hand_end ? j - 1 : j;
kpp2[k][i][j] = kpp[k][i2][j2];
}
for (int k1 = 0; k1 < SQ_NB_PLUS1; ++k1)
for (int k2 = 0; k2 < SQ_NB_PLUS1; ++k2)
for (int j = 1; j < fe_end + 1; ++j)
{
int j2 = j < fe_hand_end ? j - 1 : j;
kkp2[k1][k2][j] = kkp[k1][k2][j2];
}
memcpy(kkp, kkp2, sizeof(kkp));
memcpy(kpp, kpp2, sizeof(kpp));
これ書いたら、evalぴったり合った…。
→ やねうら王2015とperft 5でevalの合計合致した。
→ perft6の合計も念のために確認する。
→ 合致していた。
・上の評価関数ファイルの読み込み時の変換、デバッグモードだと時間がかかるので新たに書きだして、更新したほうがよさげ。
次のWCSCが終わったタイミングでライブラリ更新してCSAのサイトに新しい評価関数バイナリ上げよう。
・評価関数を修正したのに、思ったほどはレーティング上がってない。
217-25-174(+R38.4)
・差分計算が出来てないケースがあるのがおかしいのか。いくらなんでもnpsが低すぎるのであとで調査する。
・あとはmate1、呼ばないほうがいい可能性も…。
・これで勝率にまだ差が開くなら、やねうら王2015の対局設定、0.1秒思考にはなっていない可能性を疑ったほうが良いのでは…。
あとで普通に将棋所を使って対局させておく。
■ 2016/03/30 V2.24
・evaluate()毎回呼ばないと差分計算できないケースがある?(thx. tさん、わるおさん)
+ // このあとnodeを展開していくので、evaluate()の差分計算ができないと困るから、evaluate()を呼び出していないなら呼び出しておく。
+ if (pos.state()->sumKKP == VALUE_NONE)
+ evaluate(pos);
変更前 bench 590knps
変更後(静止探索、通常探索に追加)
733knps
331-27-265 (+R38.6)
→ やねうら王2014では1Mnpsぐらい出ていたのでまだ何かやらかしている可能性が微レ存。
■ 2016/03/30 V2.23
・置換表格納のときにkeyのcastが間違っていた。もしかするとこれでエントリーが一致しなかったのか?
→ そうでもなさげ。強さに影響は無いみたい。
tt.h
- key16 = (int16_t)(k >> 48);
+ key16 = (uint16_t)(k >> 48);
・depth 4手浅いものより大きいなら置換表のエントリー書き換えたほうが良いのでは。比較してみる。
tt.h
- || (d > depth() - 2 * ONE_PLY) // ここ、2と4とどちらがいいか。あとで比較する。
+ || (d > depth() - 4 * ONE_PLY) // ここ、2と4とどちらがいいか。あとで比較する。
307-36-277(+R17.9)
4のほうが少しよさ気?よくわからん…。もっと回数対戦させたほうがよさ気。
一通り修正してから再度検証すべき。
・CheckInfoのupdate、段階的に出来るようにPositionクラスのcheck_info_update()修正。
classicのコード、通常探索のほう、check_info_update()が抜けるフローがあったので修正。
・classicでnull moveのときにcheck_info_update()していないの修正。
・miniでも同様。
→ リビルドしてexe/フォルダにコピー
279-25-287
(R-4.9)
ほぼ変わらず。
■ 2016/03/30 V2.22
・Positionクラス、eval_list()関数は、戻り値はEval::EvalList型ではなくEval::EvalList*型を返すように修正。(thx. わるおさん)
コピーに若干時間がかかってました…。(T_T)
207-17-189 (R15.8up)
■ 2016/03/25 V2.21
・CounterMoveHistoryStateの更新と取得に失敗していた件、修正。(thx. tさん)
MovePickerのStatsまわり色々修正した。
・miniも同様の修正をしてビルドしなおしてexe/フォルダにコピー。
・nano plusも。
V2.21 vs V2.18
157-14-114
R55up
■ 2016/03/25 V2.20
・置換表にDEPTH_MAX書き出せなくなってた。(thx. tさん)
例)
bool hit;
auto key = pos.state()->key();
auto tte = TT.probe(key, hit);
tte->save(key, VALUE_ZERO, BOUND_EXACT, DEPTH_MAX, MOVE_NONE, VALUE_ZERO, 0);
auto tte2 = TT.probe(key, hit);
std::cout << tte2->depth();
- depth8 = (int8_t)d / (int)ONE_PLY;
+ depth8 = (int8_t)(d / (int)ONE_PLY);
こうしないとd==256だと0になってからONE_PLY(==2)で割られて0が書き出されてしまう。(しまっていた)
あと、int8_tだから、128以上だと-128扱いされてしまうので、MAX_DEPTHを127*ONE_PLYに変更。
- #define MAX_PLY_NUM 128
+ #define MAX_PLY_NUM 127
→ これで1手詰めの値を置換表に書き出したときに効果が変わるかも。
V2.20 vs V2.18
110-7-101
R14.8 up?誤差?
・local serverで対戦させてたら落ちた。打ち歩詰めではないから、たぶん古いlocal serverのバグ。
1<Error : bestmove = P*1b
1<^香^桂^銀 □ □ □ □ 銀^玉
1< □ □ □ □ と □ 馬^銀 □
1<^歩 □^歩^歩 □^歩^歩^歩^金
1< □ □ □ □ □ □ □ □ 龍
1< □^歩 □ □ □ □ □ □ □
1< □ □ □ □ 玉 □ □ □ □
1< 歩 歩 歩 歩 □ 歩 □ □ □
1< □ 角 □ □^金 □ □^龍 □
1< 香 桂 □ 銀^金 □ □^金 □
1<先手 手駒 : 歩 香 桂 , 後手 手駒 : 歩4 香 桂
1<手番 = 先手
1<sfen lns4Sk/4+P1+Bs1/p1pp1pppg/8+R/1p7/4K4/PPPP1P3/1B2g2+r1/LN1Sg2g1 b PLN4pln 107
■ 2016/03/25 V2.19
・pseudo-legalのチェックで、counter moveの手は手番に関係ない(ような実装になっている)ので、
違法手のチェックが必要だったのでその修正。(thx. woodyringさん)
https://github.com/woodyring/YaneuraOu/commit/43a8770ab77f215e53d1d895d8954091a6fe3534
- template <bool All> bool pseudo_legal_s(const Move m) const;
+ template <bool All , bool CounterMove > bool pseudo_legal_s(const Move m) const;
・classicで1手詰めを呼び出すときに王手がかかっているかのチェックするの忘れていたの修正。(thx. woodyringさん)
https://github.com/woodyring/YaneuraOu/commit/fd2faf079063e2abea6790310bb4ec307386b7f7
・mate1ply()でpinnedを使っているので先行してcheck_info_update()が必要。(thx. tさん)
・classic、mini、nano plus修正。
V2.19 vs V2.18
221-24-234
-R10
少し遅くなった分だけ弱くなった?誤差?
■ 2016/03/25 V2.18
・CODEVS5.0が終わったので作業再開。
・古い置換表でバグる件
https://github.com/woodyring/YaneuraOu/commit/e20edfccb16b384beb0de4b0604d740b1c5c20e3
→ 古い置換表では table[key & hashMask]から4要素をclusterとして使っていたので
keyが1bit違う要素が隣り合って格納されることになり、null moveのときに相手番にするときに
bit0を使うのでここでhash衝突のようなことが起きていた。
・古いほうの置換表実装削除。(置換表が弱くなる原因ではなかったようなので)
・nanoでつねにfull depth searchになっていたバグを修正。(thx. kazuさん)
- bool fullDepthSearch = (PV && moveCount == 1);
+ bool fullDepthSearch = (PVNode && moveCount == 1);
・exe/フォルダのnanoの実行ファイル差し替え。
・seeのバグ修正。(thx. tさん、woodyringさん)
https://github.com/woodyring/YaneuraOu/commit/67a49c9e0420fbc43cbd25d00b7f46bb7c0fc1e2
200-8-182 R15程度up
■ 2016/03/07 V2.17
・古いほうの置換表
- uint64_t size = ClusterSize << MSB64((mbSize << 20) / sizeof(TTEntry[ClusterSize]));
+ uint64_t size = size_t(ClusterSize) << MSB64((mbSize << 20) / sizeof(TTEntry[ClusterSize]));
こんなコードになってた。uint64_tに拡張したときに拡張できてなかった。
やねうら王(2014)で4GB以上の置換表の確保に問題があったのこれか。(いまごろ)
ただ、今回の問題はこれとは関係ない。(確保は出来ている状況で新しいほうの置換表より明らかに弱いというものだから)
■ 2016/03/04 V2.16
・打ち歩詰めの判定、間違っていたようだ。(tanuki-さんよりバグ報告があった。)
// 攻撃駒はすべてpinされていたということであり、
// 王の頭に打たれた打ち歩をpinされている駒で取れるケースは、
// いろいろあるが、いずれも玉の頭方向以外のところから頭方向への移動であるから、pinされている方向への移動ということはありえない。
→ 間違い。
sfen +S5b1l/5gg2/p1+S1p2pp/1pKn4k/4PNS2/2+b3S1+r/PP3G1N1/5P3/L1G5L b P8plnr 119
玉^
歩
飛^
香
こういうケースがある。
■ 2016/03/01 V2.15
・比較実験用に古いStockfishの置換表のコード持ってきた。
sfen lns3snl/1r1gk1gb1/pppp1p3/6pRp/4pN3/6P1P/PPPPPP3/1B3S3/LNSGKG2L w Pp 20
→ insert_pvなんとかで落ちた。
勝率めっちゃ悪い。詰みを読みきったあと、逆転負け。何これ。
insert_pv絡みで何か壊しているのか。そんな馬鹿な…。
probe()のときにgenerationをrefreshするように追加したが、関係なかった。何なのこれ。
見たことのない症例。
■ 2016/03/01 V2.14
・classic
// 捕獲から逃れるための指し手に関してはreduction量を減らしてやる。
// 捕獲から逃れるとそれによって局面の優劣が反転することが多いためである。
if (r
&& !(move & MOVE_PROMOTE)
&& pos.effected_to(~us,move_from(move))) // 敵の利きがこの移動元の駒にあるか
r = std::max(DEPTH_ZERO, r - ONE_PLY);
こういう枝刈り(枝刈らない?)を入れてみた。
50.0%
#82
やねうら王classic V214
捕獲から逃れる手のreduction減らす, 1スレッド、0.1秒設定
#0
やねうら王classic V213
悪いhistoryにreduction追加, 1スレッド、0.1秒設定
185-13-185(52.1% R0.0)
→ 効果乏しい。コメントアウトしておく。
V2.14a
singularのmargin調整してみる。
Value rBeta = ttValue - (param1 + 1) * depth / ONE_PLY; // margin = 2 * depth / ONE_PLY
param1 = 0..4ぐらいで。
47.1% 49.0% 51.2% 40.6% 50.5%
#83
やねうら王classic V214a
singular margin=(param1+1)*depth, 1スレッド、0.1秒設定
#0
やねうら王classic V213
悪いhistoryにreduction追加, 1スレッド、0.1秒設定
140-8-157(85.2% R-19.9) 98-8-102(63.8% R-6.9) 103-7-98(33.6% R8.6) 80-11-117(99.7% R-66.0) 100-10-98(41.6% R3.5)
X=2 だからmargin = depth*15/ONE_PLYで最大になっているがあまり他と差がないので
singularは保留しておく。
・npsそもそもいつこんなに下がったのか。
V1.93で1割ほどダウン
V2.07で1割ほどダウン。→静止探索でfutility入れたからか…。
・枝刈り一通り入れたのに、予想外に弱いな。評価値の差分計算が間違ってないか検証する。
→ 差分計算は合ってた。
・やねうら王2015とやってみる。
やねうら王1手0.1秒固定で..
100.0% 0.0% 0.0% 0.0% 0.0%
#84
やねうら王2015
1スレッド、0.1秒設定
#0
やねうら王classic V213
悪いhistoryにreduction追加, 1スレッド、0.1秒設定
100-0-0(0.0% R∞) 0-0-0(100.0% RNaN) 0-0-0(100.0% RNaN) 0-0-0(100.0% RNaN) 0-0-0(100.0% RNaN)
100戦100敗だった。なにこれ。やはり評価関数か何かがおかしいとしか考えられない。
evalstat同じなのにeval違うだと…?
isready
position startpos
eval
これが正しいのか。
positionをセットしたタイミングでevalの全計算をするが、そのときに評価関数が読み込まれていないとまずくて…。
悔しいがevalも差分も完璧なのに…。
1スレッドで負けてるから、lazy SMP悪くないしな。
やねうら王2015とソース見比べるしかないな。
■ 2016/03/01 V2.13
・classic
// historyの値に応じて指し手のreduction量を増減する。
int rHist = (thisThread->history.get(pos.piece_on(move_to(move)),move_to(move))
+ cmh.get(pos.piece_on(move_to(move)),move_to(move))) / 14980;
r = std::max(DEPTH_ZERO, r - rHist * ONE_PLY);
53.2%
#81
やねうら王classic V213
悪いhistoryにreduction追加, 1スレッド、0.1秒設定
#0
やねうら王classic V212
悪いhistoryにreduction追加, 1スレッド、0.1秒設定
201-15-177(9.9% R22.1)
1回落ちた。なんで…。
sfen l3k2r1/p1g5l/1p1ss2g1/+b4pppp/2+bp5/2N2PPPP/+n1PPP2R1/2S1K4/4SG1NL w PN3plg 134
→ よくわからない。
local-server.exe
で対戦させておくか。
→ 3PCで一晩回したが落ちなかった。前プロセスが悪さしてたのかな…。
・miniの最終とclassicと対戦させてみる。
55.5%
#81
やねうら王classic V213
悪いhistoryにreduction追加, 1スレッド、0.1秒設定
#75
やねうら王mini V208
静止探索での駒得しないevasion枝刈り追加, 1スレッド、0.1秒設定
182-7-146(2.0% R38.3)
あまり強くなっていないが、弱くもなっていないので良しとする。
もうちょっと強くなっているはずだったのだが…。
■ 2016/03/01 V2.12
・classic 悪いhistoryにreduction量を増やす枝刈り追加してみる。
// cut nodeや、historyの値が悪い指し手に対してはreduction量を増やす。
if ((!PvNode && cutNode)
|| (thisThread->history.get(pos.piece_on(move_to(move)),move_to(move)) < VALUE_ZERO
&& cmh.get(pos.piece_on(move_to(move)),move_to(move)) <= VALUE_ZERO))
r += ONE_PLY;
61.3%
#80
やねうら王classic V212
悪いhistoryにreduction追加, 1スレッド、0.1秒設定
#0
やねうら王classic V208
静止探索での駒得しないevasion枝刈り追加, 1スレッド、0.1秒設定
92-1-58(0.2% R80.1)
■ 2016/03/01 V2.11
・singularもっかい試す
46.0%
#78
やねうら王classic V211
singular追加, 1スレッド、0.1秒設定
#0
やねうら王classic V208
静止探索での駒得しないevasion枝刈り追加, 1スレッド、0.1秒設定
426-33-501(99.4% R-28.2)
→ どう見ても悪い。原因よく調べる。
・Signals.stop、探索中にこれを調べるなら、Signals.stop.load(std::memory_order_relaxed)とすべき。修正。
・Signals.stop、searchの前のほうでもやるように。
・静止探索でpos.givesCheck()になっていたところ、givesCheckに修正。
V2.11a
・fail lowを引き起こした直前のcounter moveに加点するようにした。
・searchのなかにassertいくつか追加した。
sfen ln1gk3p/1rs1s4/p2ps1N+B+L/lp3p3/+Rn5P1/2G1PPPl1/3P5/P+b1G1S3/4KG3 b 4P3pn 79
静止探索でassertに引っかかった。
ASSERT_LV3(-VALUE_INFINITE < value && value < VALUE_INFINITE);
おかしい…。
value == -32004
置換表に32004を書き込んだ奴がいる。
TTEntry::saveに次のassertを追加。
ASSERT_LV3((-VALUE_INFINITE < v && v < VALUE_INFINITE) || v == VALUE_NONE);
if (!(-VALUE_INFINITE + ss->ply < value && value < VALUE_INFINITE - ss->ply))
{
pos.do_move(move, st, givesCheck);
value = givesCheck ? -qsearch<NT, true>(pos, ss + 1, -beta, -alpha, depth - ONE_PLY)
: -qsearch<NT, false>(pos, ss + 1, -beta, -alpha, depth - ONE_PLY);
pos.undo_move(move);
}
こう書くと原因わかった。
draw scoreにvalue_from_tt()みたいな変換していないからか…。
連続王手での千日手での負け、詰みスコアより低くするのは違う気がするので
やはりvalue_from_ttみたいなことしないといけないのか。
// -----------------------
// 千日手等の検出
// -----------------------
auto draw_type = pos.is_repetition();
if (draw_type != REPETITION_NONE)
return value_from_tt(draw_value(draw_type, pos.side_to_move()), ss->ply);
// 最大手数を超えている、もしくは停止命令が来ている。
if (Signals.stop.load(std::memory_order_relaxed) || ss->ply >= MAX_PLY)
return value_from_tt(draw_value(REPETITION_DRAW, pos.side_to_move()),ss->ply);
こうだ。miniも同様の修正をしておく。
■ 2016/02/29 V2.10
・1手詰めのときmate_in(ply + 1)でないとおかしいのか。忘れてた。修正した。
この修正で弱くなっていないことを確認しておく。
48.5%
#77
やねうら王classic V210
1手詰めスコア修正, 1スレッド、0.1秒設定
#0
やねうら王classic V208
静止探索での駒得しないevasion枝刈り追加, 1スレッド、0.1秒設定
199-14-211(74.0% R-10.2)
→ たぶん弱くはなってなさげ。
■ 2016/02/29 V2.09
・エンジンごとにUSIのオプションが異なるから、
Option::init()でコールバックするべきか。
→ そうした。
・やねうら王classicにNarrowBookのUSIオプション追加。
・やねうら王mini、R2800程度と思われるのでドキュメント類、書き換えておく。
・やねうら王classic、NarrowBookにしたものと対戦させてみる。
終局図までが同じになることが多々あってあまり意味があるとも思えないが…。
→ miniにもこの機能入れて、floodgateにはそれを投入する。
51.8%
#76
やねうら王classic V209
NarrowBook有効, 1スレッド、0.1秒設定
#0
やねうら王classic V208
静止探索での駒得しないevasion枝刈り追加, 1スレッド、0.1秒設定
174-10-162(23.9% R12.4)
あまり偏ってなかった。持ち時間が短いと序盤のミスを咎めるのが難しいからか…。
そもそも大悪手は含まれてないだろうしな…。
■ 2016/02/29 V2.08
・classicの静止探索で駒得しない王手回避と、なんやかや枝刈りするコード追加。
→ Detect non-capture evasions
62.9%
#74
やねうら王classic V208
静止探索での駒得しないevasion枝刈り追加, 1スレッド、0.1秒設定
#0
やねうら王classic V207
静止探索でのfutility追加, 1スレッド、0.1秒設定
90-1-53(0.1% R92.0)
よくはわからないが、とても効果があるみたい。
miniのほうもこの修正入れる。
64.1%
#75
やねうら王mini V208
静止探索での駒得しないevasion枝刈り追加, 1スレッド、0.1秒設定
#73
やねうら王mini V207a
静止探索の1手詰め復活, 1スレッド、0.1秒設定
166-8-93(0.0% R100.7)
■ 2016/02/29 V2.07
・classicの静止探索にfutility追加。
60.4%
#71
やねうら王classic V207
静止探索でのfutility追加, 1スレッド、0.1秒設定
#0
やねうら王classic V206
futility at parent node3, 1スレッド、0.1秒設定
110-9-72(0.2% R73.6)
→ これずいぶん効果がある。自己対局だからかも知れないが。
この枝刈りをminiに入れて、静止探索の一手詰めを削除するとどうなのか。
43.8%
#72
やねうら王mini V207
静止探索のfutility追加。1手詰め削除, 1スレッド、0.1秒設定
#67
やねうら王mini V204b
miniから静止探索の1手詰めだけ復活, 1スレッド、0.1秒設定
81-6-104(96.1% R-43.4)
1手詰めないと散々だな…。
V2.07a
→ miniの一手詰め戻す
これで2.04bに勝ち越すようなら、これで最終とする。
57.2%
#73
やねうら王mini V207a
静止探索の1手詰め復活, 1スレッド、0.1秒設定
#67
やねうら王mini V204b
miniから静止探索の1手詰めだけ復活, 1スレッド、0.1秒設定
91-7-68(2.8% R50.6)
弱くはなってなさそう。
→ exeフォルダのminiを差し替え
■ 2016/02/29 V2.06
・classicに親nodeで負のSEE値を持つ指し手の枝刈りも入れてみる。
// 次の子nodeにおいて浅い深さになる場合、負のSSE値を持つ指し手の枝刈り
if (predictedDepth < 4 * ONE_PLY && pos.see_sign(move) < VALUE_ZERO)
continue;
56.1%
#70
やねうら王classic V206
futility at parent node3, 1スレッド、0.1秒設定
#0
やねうら王classic V205a
futility at parent node2, 1スレッド、0.1秒設定
351-16-275(0.1% R42.4)
・qsearchにコメント追加。
■ 2016/02/29 V2.05
・classicに親nodeでのfutility追加。
// Futility pruning: 親nodeに関して
if (predictedDepth < 7 * ONE_PLY)
{
futilityValue = ss->staticEval + futility_margin(predictedDepth,pos.game_ply()) + param1 * 85;
if (futilityValue <= alpha)
{
bestValue = std::max(bestValue, futilityValue);
continue;
}
}
こうやってparam1 == 0..4ぐらいで前バージョンと対局させてみる。
46.0% 51.9% 55.4% 53.7% 54.5%
#68
やねうら王classic V205
futility at parent node, 1スレッド、0.1秒設定
#0
やねうら王classic V204
classicにhistoryに基づく枝刈り追加, 1スレッド、0.1秒設定
144-7-169(92.9% R-27.8) 160-12-148(22.9% R13.5) 173-8-139(2.4% R38.0) 169-5-146(8.8% R25.4) 168-12-140(4.9% R31.7)
V2.05a
X=2,すなわち170か。とりあえずそうしとく。
■ 2016/02/29 V2.04
・classicにHistoryに基づいた枝刈り追加。
77.9%
#64
やねうら王mini V203a
miniのほうmoveCountベースのfutility追加, 1スレッド、0.1秒設定
#0
やねうら王mini V202
singluar extension追加, 1スレッド、0.1秒設定
102-3-29(0.0% R218.5)
V2.04a
・miniにこの枝刈り入れて、1手詰め、削除するとどうか。
各種枝刈りを入れると一手詰めをの有無が利いてくるのか…。そうか…。
33.3%
#66
やねうら王mini V204a
miniにhistoryに基づく枝刈り追加 mate削除, 1スレッド、0.1秒設定
#0
やねうら王mini V203
moveCountベースのfutility追加, 1スレッド、0.1秒設定
18-0-36(99.5% R-120.4)
V2.04b
・miniから静止探索の1手詰めだけ復活
51.2%
#67
やねうら王mini V204b
miniから静止探索の1手詰めだけ復活, 1スレッド、0.1秒設定
#0
やねうら王mini V203
moveCountベースのfutility追加, 1スレッド、0.1秒設定
84-1-80(34.8% R8.5)
→ 前のバージョンと互角ぐらいっぽいのでこれですっきり。
■ 2016/02/29 V2.03
・classicにmoveCountベースのfutility追加
85.1%
#63
やねうら王mini V203
moveCountベースのfutility追加, 1スレッド、0.1秒設定
#0
やねうら王mini V202
singluar extension追加, 1スレッド、0.1秒設定
143-9-25(0.0% R303.0)
→ これ結構効果あるみたい。
これ入れて、miniのほう、効果の薄いのざっくり消すか。
・やねうら王mini、ソースコード整理して、exeフォルダの中身差し替えた。
■ 2016/02/29 V2.02
・classicにSingular Extension追加。
50.8%
#62
やねうら王mini V202
singluar extension追加, 1スレッド、0.1秒設定
#0
やねうら王mini V201
extend check追加, 1スレッド、0.1秒設定
215-17-208(34.9% R5.8)
おかしい。excludedMove = MOVE_NONEにしていないからか。初期化追加。
・Singular、バグってないはずなのに強くならない。もう少し条件考えたほうがよさげ…。
51.8%
#62
やねうら王mini V202
singluar extension追加, 1スレッド、0.1秒設定
#0
やねうら王mini V201
extend check追加, 1スレッド、0.1秒設定
379-48-352(15.0% R12.8)
■ 2016/02/28 V2.01
・classicに王手による1手延長を追加。
57.5%
#61
やねうら王mini V201
extend check追加, 1スレッド、0.1秒設定
#0
やねうら王mini V200
IID追加, 1スレッド、0.1秒設定
168-9-124(0.4% R52.8)
見かけ上のRはずいぶん上がるが…。
■ 2016/02/28 V2.00
・classicに多重反復深化を入れてみる。
メモリが潤沢にある(or 指し手が1手0.1秒なら)、これによる勝率の変化はほとんどないはず。
51.7%
#60
やねうら王mini V200
ProbCut追加, 1スレッド、0.1秒設定
#59
やねうら王mini V199
ProbCut追加, 1スレッド、0.1秒設定
1153-59-1076(5.1% R12.0)
→ 思ったより変わった。
■ 2016/02/28 V1.99
・classic開発開始。
・ProbCut入れてみる。
・StateInfoの変数名siではなくstにしてStockfishに合わせておく。
・MovePicker::nextMoveではなくnext_move()のほうがいいのでは…。
・MovePickerにProbCut用の指し手生成を追加。
60.0%
#58
やねうら王mini V199
ProbCut追加, 1スレッド、0.1秒設定
#0
やねうら王mini V192
null move追加, 1スレッド、0.1秒設定
150-7-100(0.1% R70.4)
・miniにもProbCutは入れる。ProbCut 10行程度のわりにR70ぐらい増えるのでお得だ。
■ 2016/02/28 V1.98
・miniのlazy SMP条件を調整。
for (Thread* th : Threads)
if (th->completedDepth > bestThread->completedDepth
&& th->rootMoves[0].score > bestThread->rootMoves[0].score)
bestThread = th;
↓
for (Thread* th : Threads)
if (th->completedDepth > bestThread->completedDepth ||
(th->completedDepth == bestThread->completedDepth && th->rootMoves[0].score > bestThread->rootMoves[0].score))
bestThread = th;
どう考えてもこっちのほうがいいと思うのだが…。
これでV1.95と4スレッド1秒で対戦させてみる。
48.2%
#58
やねうら王mini V198
lazySMP改良, 4スレッド、0.1秒設定
#57
やねうら王mini V195
4スレッド設定, 4スレッド、0.1秒設定
477-42-513(88.0% R-12.6)
この改良は駄目なのか。スコアがいいほうが楽観合議のような効果があるのだろうか。
→ 元に戻す。
exeフォルダのminiを差し替える。
classicのほうの開発進める。
■ 2016/02/28 V1.97
・lazy SMP、言うほど強くなってないな…。再検証する。
・completedDepthの初期化忘れていたの修正。
・resignするときにlazy SMP、bestThreadを探す処理、これrootMoves.size()==0だとアクセス違反なのでは。
Stockfishのコードがおかしいんだな…。
→ 修正した。
・4スレッド設定と対局させておく。
75.7%
#57
やねうら王mini V195
4スレッド設定, 4スレッド、0.1秒設定
#56
やねうら王mini V195
razoring戻す, 1スレッド、0.1秒設定
667-15-214(0.0% R197.5)
■ 2016/02/28 V1.96
・Rootで3秒以上経過しているなら探索手を出力するように。
・思ったより強くならない。旧形式からの評価関数バイナリの変換に失敗している可能性がなくもないな…。
検算しよう。
sfen lnsg1k3/9/pppp+N1G2/4pppp1/3l5/2P6/PPS1PPP2/1Kl1G1S2/LN3S+r2 w BRG4pnb 86
eval = -2047
→ 完全に一致してた。
・持ち時間制御をしていないことによる損失は2倍時間ぐらいで、R200ぐらいあるのかも。
・singular extensionをしていない損とかもあるのか…。
・ProbCutはMovePickerに手を入れないと実装できないしな…。
・やねうら王miniはこんなもんでいいか…。じゃあ、miniはこれで完成。
・exeフォルダにやねうら王miniを追加。
■ 2016/02/28 V1.95
・local serverでCreateProcessに失敗したときに復帰できなくなるの修正。
・V1.95a
razoring戻して、V1.94と対戦させておく。
54.2%
#56
やねうら王mini V195
razoring戻す, 1スレッド、0.1秒設定
#55
やねうら王mini V194
定跡修正, 1スレッド、0.1秒設定
266-18-225(2.9% R29.1)
→ これでいいや。
■ 2016/02/28 V1.94
・miniで定跡の指し手が指せていない。修正。
・miniでrootMovesに定跡の指し手が含まれていない場合、定跡の指し手を選択しないように。
・変な定跡を選択していたので勝率がちゃんと計測できてなかった。あらら…。まあいいや。パラメーターはまた調整しよう。
・floodgateに6コアPCで放流しておく。
55.9%
#55
やねうら王mini V194
定跡修正, 1スレッド、0.1秒設定
#0
やねうら王mini V192
null move追加, 1スレッド、0.1秒設定
100-4-79(5.0% R40.9)
■ 2016/02/28 V1.93
・miniにrazoring追加。
const int razor_margin_table[4] = { 483, 570, 603, 554 };
const Value razor_margin(Depth d)
{
ASSERT_LV3(DEPTH_ZERO <= d && d < 4 * ONE_PLY);
return (Value)(512 + 16 * static_cast<int>(d));
return (Value)razor_margin_table[d / ONE_PLY];
}
53.4%
#52
やねうら王mini V193
razoring追加, 1スレッド、0.1秒設定
#0
やねうら王mini V192
null move追加, 1スレッド、0.1秒設定
205-10-179(8.4% R23.6)
→ あまり強くなってない。
V1.93a
Apery風のrazoringにしてみる。
inline Value razor_margin(const Depth d) {
return (Value)(512 + 16 * static_cast<int>(d));
}
if (!PvNode
&& depth < 4 * ONE_PLY
&& eval + razor_margin(depth) < beta
&& ttMove == MOVE_NONE
&& abs(beta) < VALUE_MATE_IN_MAX_PLY)
{
const Value rbeta = beta - razor_margin(depth);
const Value s = qsearch<NonPV, false>(pos, ss, rbeta - 1, rbeta, DEPTH_ZERO);
if (s < rbeta)
return s;
}
47.9%
#53
やねうら王mini V193a
razoring apery風追加, 1スレッド、0.1秒設定
#52
やねうら王mini V193
razoring追加, 1スレッド、0.1秒設定
236-13-257(83.9% R-14.8)
V1.93b
margin、線形にしてみる。
const Value razor_margin(Depth d)
{
static_assert(ONE_PLY == 2,"static_assert ONE_PLY == 2");
ASSERT_LV3(DEPTH_ZERO <= d && d < 4 * ONE_PLY);
return (Value)(512 + 16 * static_cast<int>(d));
}
50.2%
#54
やねうら王mini V193b
razoring apery+stockfish風追加, 1スレッド、0.1秒設定
#52
やねうら王mini V193
razoring追加, 1スレッド、0.1秒設定
112-9-111(44.7% R1.6)
→ ほぼ変わらないから、これでいく。
■ 2016/02/28 V1.92
・miniにnull move pruning追加。
・Position::do_null_move()/undo_null_move()追加。
→ iterationだいぶ回るようになった。
61.9%
#51
やねうら王mini V192
null move追加, 1スレッド、0.1秒設定
#50
やねうら王mini V191
pseudo_legal修正, 1スレッド、0.1秒設定
166-3-102(0.0% R84.6)
■ 2016/02/27 V1.91
・0.1秒自己対局で4000局で1回落ちたようだ。やはりinsert_pv_in_tt()以外で何かやらかしている。
・リリースビルドであれ、デバッガでアタッチさえできればウォッチでpos.sfen()としてsfen文字列を取り出したり、
to_usi_string(move)とかで、指し手文字列を得たりできるので、デバッグは出来るのだが…。
sfen lnsg1k3/9/pppp+N1G2/4pppp1/3l5/2P6/PPS1PPP2/1Kl1G1S2/LN3S+r2 w BRG4pnb 86
・2PCで8時間回して落ちない。
・残りのPCにもVS入れてテストする。
・local server、pseudo-legalのチェック入れるべきか…。
→ すでに入ってた
・MovePickerがpseudo legalの判定するのだが、check_info_update()が呼び出されていないのでは…。
→ と思ったが、呼びだされていた。
・本格的に原因がわからんので、5PCでlocal-server回しておく。
↓
6時間で1回落ちた。
sfen 2bK1G3/7+L1/6+R2/1G6s/1G7/9/1P7/5ps2/2r1pks1+B w 10P3NG5p3lns 247
→ この局面100%落ちるわ..やったー!
59の歩が一歩進んで61の玉をcaptureしてる…。
ああ、置換表に58->59銀みたいな指し手があると、次にkillerでこれが歩に適用されて
59歩不成みたいな指し手が生成されるということなのか。なるほど、駒種を持っていないとこういうことが起こりえるのか…。
動かす駒を持っていればpseudo-legalの判定でその駒でなければ弾かれるのか。うーん、なるほど…。
→ 調べてみたら、counte moveに登録されてこの手が生じたようだ。counter moveって駒が違うと適用されるべきではないのか..そうか..
pseudo_legal拡張して、かつ、駒種は持つべきなのか…そうか…。
置換表サイズ足りない..。
// これ、駒種を持っておいて、駒種が違うときは適用しないほうがオーダリング効率は上がる。
auto cm = thisThread->counterMoves.get(prevPc, prevSq);
Moveが32bitになるとCounterMoveの配列も倍になるしな…。
そもそもそんなに都合よく別の駒が来ていることって現実的にはほとんどない気もするしな…。
・insert_pv_in_tt()のところ戻して、もう一度、変な指し手が生成されていないか確認する。
・Position::legal<bool All>(),pseudo_legal<bool All>()
みたいなチェック入れたほうがいいのか…。うーん..
// All == true : 歩や大駒の不成に対してはfalseを返すpseudo_legal()
template <bool All> bool pseudo_legal_s(const Move m) const;
追加した。
・どこで不成の指し手が出てくるのか以下のコードを追加して調べる。
if (pos.pseudo_legal_s<false>(move) == false)
{
std::cout << pos << move << std::endl;
pos.pseudo_legal_s<false>(move);
}
"ln4s2/1k5b1/p1pgppp1n/1P2l2g1/1G5p1/4P4/P2P1PP1P/2S2S1R1/+n2K1G3 b S5p2lnbr 75"
この局面に対してQCHECKで歩の不成が生成されている。
case PAWN: GEN_MOVE_NONPRO_CHECK(PAWN, pawnEffect, goldEffect); break;
case LANCE: GEN_MOVE_LANCE_CHECK (LANCE, lanceEffect, goldEffect); break;
このへんが怪しい。
if (((Pt == PAWN || Pt == LANCE) &&
((!All && ((Us == BLACK && rank_of(to) >= RANK_3) || (Us == WHITE && rank_of(to) <= RANK_7))) ||
(All && rank_of(to) != (Us == BLACK ? RANK_1 : RANK_9))))
この条件が間違っている。
↓こうではないかと。
if (((Pt == PAWN) &&
((!All && !canPromote(Us,to)) ||
(All && rank_of(to) != (Us == BLACK ? RANK_1 : RANK_9))))
|| ((Pt == LANCE) &&
((!All && ((Us == BLACK && rank_of(to) >= RANK_3) || (Us == WHITE && rank_of(to) <= RANK_7))) ||
(All && rank_of(to) != (Us == BLACK ? RANK_1 : RANK_9))))
↓
rootPos.set("ln4s2/1k5b1/p1pgppp1n/1P2l2g1/1G5p1/4P4/P2P1PP1P/2S2S1R1/+n2K1G3 b S5p2lnbr 75");
cout << rootPos;
for (auto m : MoveList<QUIET_CHECKS>(rootPos))
cout << " " << m;
うまく動いた
Piece moved_piece(Move m) const { return is_drop(m) ? move_dropped_piece(m) : piece_on(move_from(m)); }
これが後手のときに後手の指し手でないのがおかしいのか。
→ これ修正した。駒打ちに関するオーダリングが少し改善されるかも。
・statのupdateにassert追加した。
・Threadsが変更になってからisreadyが送られてこないとisreadyでthread数だけ初期化しているものはこれではまずいのか…。
sfen ln5nl/6gk1/p1sp1g1s1/1P2ppppp/1p1P5/1bP1PPPPP/PRNSBGNS1/6GK1/L2r4L b p 67
setoption name Threads value 1
isready
go infinite
test autoplay
→ わかった。飛車を成って、その成った駒を動かした指し手がcounter moveに登録されている。
これがまずいので、MovePickerではpseudo_legal_s<false>()を呼び出すようにする。
・これで修正できたと思うのでV1.88と対戦回してみる。
53.7%
#50
やねうら王mini V191
pseudo_legal修正, 1スレッド、0.1秒設定
#0
やねうら王mini V188
並列化版 1スレッド設定, 1スレッド、0.1秒設定
237-21-204(5.3% R26.0)
オーダリング改善されたせいかR25ほど上がっているのかも知れない。
・nano plusのほう、リビルドして差し替えておく。
■ 2016/02/27 V1.90
・value_to_tt()の説明間違っていたので修正。
・go infiniteで8時間回しても落ちないのに連続自己対局で落ちるということは
再戦時の初期化がおかしいのか…。
CounterMoveHistory.clear();
for (Thread* th : Threads)
{
th->history.clear();
th->counterMoves.clear();
}
こんだけは初期化されているのに…。
・local serverで落ちたプロセスをtrapするようにする。
→ C#側から2段にCreateProcessしているのがいけないのか…。
→ C#のCreateProcessが子プロセスのエラーを握り潰しているのかも知れない..
・local server単体ならデバッグ可能みたいなのでこれでやる。
落ちた
→ insert_pv_in_tt()
ASSERT_LV3(MoveList<LEGAL>(pos).contains(m));
で落ちた。PVがおかしくなっているのか…。
pv配列の更新はおかしくないから、おかしいPV渡されていることになる。
pseudo-legalの判定怪しいな…。
このLEGALは、LEGAL_ALLのほうがいいのか…。
LEGALでない指し手が含まれているとここで引っかかって落ちるのか。
修正しておく。
→ しかし、ここで角の不成みたいな手が含まれているのがおかしい気がする。
CAPTUREの指し手に不成が含まれているのがおかしいのでは…。
→ 含まれてないな…。おかしいな…。
→ 銀の不成の指し手をcounter moveとして登録して、この位置に角が来ると
角の不成の指し手を生成することになる。
王のcaptureになっているのはどこか他のバグがあるはず…。
このままランニングさせておく。
・pseudo_legalにASSERT少し追加。
・MovePicker
ASSERT_LV3(pos.pseudo_legal_s<false>(move));
こうしてランニングしてみる。
・miniのsilent modeで定跡のcoutへの出力抑制する。
■ 2016/02/26 V1.89
・miniでmain threadでfail high/lowが起きたときにGUIに読み筋を出力するようにした。
・miniでbook moveまわりの処理、整理。
・静止探索で指し手がないときにそれを保存しないようにして比較実験。
// これ保存したほうがいいかどうかは比較実験が必要。
/*
tte->save(posKey, value_to_tt(bestValue,ss->ply) , BOUND_EXACT,
DEPTH_MAX, MOVE_NONE, ss->staticEval, TT.generation());
*/
42.7%
#47
やねうら王mini V189
並列化版 1スレッド設定, 1スレッド、0.1秒設定
#0
やねうら王mini V188
並列化版 1スレッド設定, 1スレッド、0.1秒設定
205-18-275(99.9% R-51.0)
V1.89a
よくわからんけど、勝率悪いので戻す。
保存することで0.5手延長のような効果があるのだろうか..
50.5%
#48
やねうら王mini V189a
並列化版 1スレッド設定, 1スレッド、0.1秒設定
#0
やねうら王mini V188
並列化版 1スレッド設定, 1スレッド、0.1秒設定
563-46-552(37.1% R3.4)
計測しなおした。
50.2%
#47
やねうら王mini V189
並列化版 1スレッド設定, 1スレッド、0.1秒設定
#0
やねうら王mini V188
並列化版 1スレッド設定, 1スレッド、0.1秒設定
4551-411-4514(34.9% R1.4)
1.89、悪くなかった。
■ 2016/02/26 V1.88
・miniのaspirationでfail highのときの処理入れてなかった。修正した。
・よし、さっきの局面では落ちなくなったのでまたもや1スレッドで対局させておく。
・マルチスレッドのバグ、これで取れたのかも知れないので将棋所で自己対局もさせておく。
→ 50局ほどやったが落ちない。
・fail highの処理入れてないからaspirationのdeltaに対する効果が薄かったのかな。
あとで調整する。
・4スレッド版とV1.82と対局させておく。
79.0%
#46
やねうら王mini V188
並列化版 4スレッド設定, 1スレッド、0.1秒設定
#0
やねうら王mini V182
ss->moveCount更新するようにした, 1スレッド、0.1秒設定
413-25-110(0.0% R229.8)
並列化によって4並列時でR230ほど上がっているようだ。
0.5手延長のような効果が出ているだけかも知れないのでこの数字は
あまりアテにならない。PV splitも実装して比較すべき。
あと上記の対局中に2回落ちているようだ。
sfen l2gk4/2s5g/1pn3rp1/2pp1p2N/8p/pP1P5/P1P1SP3/4KS3/LNBG2+p+rL b B5plnsg 75
sfen 5+S+RG+P/4+NK2+P/4P+P1+B1/S2b4+P/1+R1s5/9/P3+nk+n2/1+l3+p1+n+p/9 w 9PLGp2ls2g 232
単体では落ちないか…そうか…。
■ 2016/02/26 V1.87
・miniでseldepthを出力するためにmaxPlyを更新するようにした。
・miniのsearch(),qsearch()に次のassert追加
ASSERT_LV3(-VALUE_INFINITE<=alpha && alpha < beta && beta <= VALUE_INFINITE);
ASSERT_LV3((PvNode || alpha == beta - 1);
・miniでbookMoveがあるときにRootMoves[0]を参照していたの修正。
・将棋所でminiのDebug buildとランダムプレイヤーとを連続対局させておく。
→ 突然落ちる。デバッグ不可。
・Releaseビルドでtest autoplayだと落ちない。わけわからん。
・1スレッド対局で落ちないかテストしよう。
V1.82と対局させておく。
→ V1.87のほう、一回落ちた…。なんで..
sfen ln1gk4/1r1s2pp1/pppppp1s+R/2b4g1/7NB/2P2g3/PPSP5/4S4/LN1GK4 b 3PLN3pl 77
51.5%
#44
やねうら王mini V187
並列化版 1スレッド設定, 1スレッド、0.1秒設定
#0
やねうら王mini V182
ss->moveCount更新するようにした, 1スレッド、0.1秒設定
1205-114-1133(6.8% R10.7)
■ 2016/02/26 V1.86
・complete depthに反映させてなかったの修正。
・miniのPV表示、もっと限定する。
・ThreadPool::init_for_slave()追加
void init_for_slave(const Position& pos, const Search::LimitsType& limits);
・test autoplayコマンドを並列化されている探索部も呼び出せるようにした。
・nano plusのSearch::clear()に
for (Thread* th : Threads)
{
th->history.clear();
th->counterMoves.clear();
}
これ入れるの忘れてた。落ちる原因は、これか…。
・nano plusの実行ファイル差し替え。
・miniはまだ落ちる。なんぞこれ。
auto playでSearch::clear()呼び出さないからか。修正した。
しかし対局中に落ちたのはこれとは違うはずで…。
わからん。デバッグビルドでauto play回しておく。
→ 一晩回して落ちなかった。
・aspirationのdeltaの初期値の調整
50.9% 50.8% 47.1% 50.3% 46.6% 50.3% 49.4% 51.9% 52.0% 47.5% 51.7% 50.0% 50.6% 50.9% 50.4%
#42
やねうら王mini V184a
aspirationの幅可変 param1 * 5, 1スレッド、0.1秒設定
#0
やねうら王mini V182
ss->moveCount更新するようにした, 1スレッド、0.1秒設定
678-75-655(26.4% R6.0) 678-73-657(28.3% R5.5) 617-65-692(98.1% R-19.9) 588-55-582(43.0% R1.8) 543-66-623(99.0% R-23.9) 591-50-583(40.8% R2.4) 568-75-581(64.9% R-3.9) 605-62-560(9.4% R13.4) 603-73-556(8.4% R14.1) 553-59-610(95.3% R-17.0) 601-63-562(12.6% R11.7) 587-58-587(50.0% R0.0) 587-64-573(34.1% R4.2) 589-70-569(27.8% R6.0) 589-64-579(38.5% R3.0)
X=8、すなわち5*8 = 40がベストっぽい。このへんはもう少し作りこんでから再度調整すべき。
■ 2016/02/26 V1.85
・miniの並列化
→ half density matrix、実装できたかも。
aspirationの幅を30にしてテスト。
→ よくわからんのでこれでfloodgateに放流しておく。
・MovePickerのあとのfutilityで刈らない分とlazy SMPでスレッドの空きが発生しない分かで、
4コアで4.7Mnpsぐらい出ている。HT有効にしたほうが良かったりして…。
■ 2016/02/26 V1.84
・並列化のための準備
・aspiration searchの実装
・RootMoves::insert_pv_in_tt()追加
・MoveList::contains()追加
・tt.hにupdate_pv()を追加する。
Search::Stack::pvを更新するようにした。
・miniは、USE_TT_PVを使わないようにした。
・にわかに信じられないが初手58玉の局面でevaluate()を呼ぶと-1500ぐらいの評価値が返ってくる。
V1.82と対戦させてaspirationによって勝率が落ちていないことを確認する。
50.8%
#41
やねうら王mini V184
aspiration search実装, 1スレッド、0.1秒設定
#0
やねうら王mini V182
ss->moveCount更新するようにした, 1スレッド、0.1秒設定
166-25-161(37.0% R5.3)
よくわからない。調整したほうがよさげ。
PV更新で少し時間かかるようになったのと、aspirationの窓の調整がうまく出来ていなくて
あまり効率が上がっていないっぽい。このへんのパラメーターはもう少し作りこんでから調整すべき。
V1.84a
// aspiration windowの幅
// 精度の良い評価関数ならばこの幅を小さくすると探索効率が上がるのだが、
// 精度の悪い評価関数だとこの幅を小さくしすぎると再探索が増えて探索効率が低下する。
delta = Value(param1 * 5);
aspirationの幅をstep 5ずつ変更してparam1 = 0..15ぐらいで最適値を探してみる。
→ 一晩寝かせておく。
■ 2016/02/25 V1.83
・mini、思考開始時にTimerリセットしないと。
・StockfishのSearch::LimitsがstartTime持っているの仕様としておかしい気がする。
→ やねうら王ではTimerクラスに持たせる。
・Timer.init()でstartTimeを初期化するようにして、明示的にはこれをアクセスしないように変更する。
・searchなどの返し値に次のassert入れた。
ASSERT_LV3(-VALUE_INFINITE < v && v < VALUE_INFINITE);
・aspiration windows search、原型だけ書く。
59.2%
#40
やねうら王mini V182
ss->moveCount更新するようにした, 1スレッド、0.1秒設定
#0
やねうら王nano plus V180
EVASIONSのオーダリング追加, 1スレッド、0.1秒設定
302-23-208(0.0% R64.8)
なぜかR60ぐらい上がっている。moveCount絡みのbonusなのか?
■ 2016/02/25 V1.82
・やねうら王mini開発開始
・やねうら王nano plusの思考エンジンの実行ファイルをGitHubにcommit。
・local-server、CreateProcessするときにデバッグ有効にしとくべきか…。
DEBUG_PROCESS
→ これではないのか。うーむ..
デバッガを自動的に起動する
https://msdn.microsoft.com/ja-jp/library/a329t4ed(VS.80).aspx
レジストリエディタを開き
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\currentversion\image file execution options
に、
新しいキーでデバッグ対象の実行ファイルの名前を入れる。"YaneuraOu-mini.exe"とか。
> 新しい文字列値を右クリックし、ショートカット メニューの [名前の変更] をクリックします。
> 名前を debugger に変更します。
> 新しい文字列値を右クリックし、ショートカット メニューの [変更] をクリックします。
> [文字列の編集] ダイアログ ボックスが表示されます。
> [値のデータ] ボックスに、「vsjitdebugger.exe」と入力します。
→ ビンゴ!これでやっとデバッグできる。4コアで24時間ほど回しておく。
・miniに引き分け時スコア)Contenpt)を設定できるようにした。
・miniの日本語化ファイル
YaneuraOu-mini_ja.txt
をexe/に追加。
・miniをMultiPVに対応
isready
setoption name MultiPV value 5
go
→ PVの表示できた。指し手がないように見えるからmateになってしまうので修正。
→ 表示がおかしいだけだった。修正した。
・miscにTimeManagementクラス追加。
・nano plusのss->moveCountの初期化してないな…。まあ、nano plusではあんまり影響ないからいいか。
nano plusで親nodeのss->moveCountを参照しているところコメントアウトしておく。
→ この効果があるのか調べるために前バージョンと対戦させておく。
■ 2016/02/25 V1.81 nano plus (final)
・BAD CAPTUREにSEE<0の指し手回すと強くなるのか?
ほぼ変わらないっぽい。
→ このまま一晩回してみる。
→ 26コアで回して一晩で2回落ちた。誰か原因調べて欲しい…。
53.8%
#38
やねうら王nano plus V181
BAD CAPTURE実装, 1スレッド、0.1秒設定
#0
やねうら王nano plus V180
EVASIONSのオーダリング追加, 1スレッド、0.1秒設定
6571-626-5634(0.0% R26.7)
+R25程度。
■ 2016/02/25 V1.80
・EVASIONのオーダリングにSSEが必要だしな…。
→ evasionのオーダリングと、QCAPTURES_1,2のオーダリングをするようにした。
静止探索のCAPTURESが改善されたので見かけの勝率が随分あがったが…。
たぶん言うほど効果ないと思う。
73.6%
#37
やねうら王nano plus V180
EVASIONSのオーダリング追加, 1スレッド、0.1秒設定
#0
やねうら王nano plus V179
CAPTUREのオーダリング追加, 1スレッド、0.1秒設定
162-17-58(0.0% R178.4)
■ 2016/02/25 V1.79
・MovePickerに他のオーダリングも導入
captureのときのオーダリング追加。
score_capture()追加。
54.4%
#36
やねうら王nano plus V179
CAPTUREのオーダリング追加, 1スレッド、0.1秒設定
#0
やねうら王nano plus V178
counter move追加, 1スレッド、0.1秒設定
210-31-176(3.7% R30.7)
+R30程度?
■ 2016/02/25 V1.78
・nano plusにCounterStats追加。
・nano plusのMovePickerファイルを分離する。
・Position::moved_piece()追加。
・ThreadにCounterMoveHistoryStatsを持たさないといけないのに..これうまく分離できないな…。
#ifdef USE_MOVE_PICKER
// スレッドごとにhistoryとcounter movesのtableを持たないといけない。
CounterMoveHistoryStats history;
MoveStats counterMoves;
#endif
これ、仕方ないな…。
・nano plusのkillerにcountermoveを入れるようにする。
・historyのupdate()の処理入れる。
67.1%
#35
やねうら王nano plus V178
counter move追加, 1スレッド、0.1秒設定
#0
やねうら王nano plus V176b
思考時間0.1~0.3秒, 1スレッド、0.1秒設定
420-19-206(0.0% R123.8)
・プロセスが落ちないか、26コアで一晩回しておく。
・このバージョンをfloodgateに投入しておく。
■ 2016/02/24 V1.77
・劣等局面の判定追加する。
→ 確かに優等局面を発見したときに早く探索が回るが、思考時間が一定なので
この分の時間が得しなくて時間固定の自己対局では勝率が変わらない。
500局やってほぼ互角。
■ 2016/02/24 V1.76
・nano plusに簡単に導入できそうな枝刈りを追加する。
・futilityまず入れる。
// game ply(≒進行度)とdepth(残り探索深さ)に応じたfutility margin。
Value futility_margin(Depth d,int game_ply) {
// 80手目を終盤と定義して、終盤に近づくほどmarginの幅を上げるように調整する。
game_ply = min(80, game_ply);
return Value(50 * d * (param1+1) + game_ply * param2);
}
こうやって、futilityの幅を調整してみる。
param1 = 0..4 , param2を0..4ぐらいの幅で
dにも比例させるべきなのか…そうか…。
return Value(d * ((param1+1) * 30 + game_ply * param2 / 2));
param1 = 0..5 , param2 = 0..3ぐらいで回しておく。
→ X = 0..5
36.1% 62.7% 70.1% 68.2% 62.0% 60.5%
52.8% 44.7% 63.3% 57.3% 55.3% 61.9%
67.7% 78.3% 67.2% 62.8% 56.2% 59.4%
46.7% 65.7% 64.7% 55.1% 63.3% 62.0%
#32
やねうら王nano plus V176
futility margin調整中 , 1スレッド、0.1秒設定
#0
やねうら王nano plus V175
超安定版 , 1スレッド、0.1秒設定
297-10-525(100.0% R-99.0) 506-25-301(0.0% R90.2) 573-15-244(0.0% R148.3) 552-23-257(0.0% R132.8) 502-22-308(0.0% R84.9) 494-16-322(0.0% R74.3)
428-21-383(5.3% R19.3) 360-27-445(99.9% R-36.8) 518-14-300(0.0% R94.9) 460-29-343(0.0% R51.0) 445-27-360(0.1% R36.8) 501-22-309(0.0% R84.0)
545-27-260(0.0% R128.6) 642-12-178(0.0% R222.8) 548-17-267(0.0% R124.9) 427-10-253(0.0% R90.9) 343-14-267(0.1% R43.5) 365-10-249(0.0% R66.4)
286-12-326(95.1% R-22.7) 401-14-209(0.0% R113.2) 392-18-214(0.0% R105.1) 338-11-275(0.5% R35.8) 391-6-227(0.0% R94.5) 377-16-231(0.0% R85.1)
Y=0ではX=2あたりがピーク。depth*90ってことか。Aperyの130ぐらいになってるの意味があるんだな。
Y方向はなぜかY=2がピーク。Y=1の結果が直感に反するのでnanoとも対戦させてみる。
80.9% 95.9% 93.9% 91.1% 91.3% 92.1%
63.9% 73.1% 88.1% 86.1% 93.1% 87.8%
91.3% 83.1% 92.3% 92.2% 90.0% 86.5%
80.6% 94.1% 93.3% 86.5% 86.8% 81.4%
#32
やねうら王nano plus V176
futility margin調整中 , 1スレッド、0.1秒設定
#30
やねうら王nano V172
テスト用のnano
463-20-109(0.0% R251.3) 560-8-24(0.0% R547.2) 551-5-36(0.0% R473.9) 534-6-52(0.0% R404.6) 538-3-51(0.0% R409.3) 538-8-46(0.0% R427.2)
367-18-207(0.0% R99.5) 413-27-152(0.0% R173.6) 509-14-69(0.0% R347.1) 506-4-82(0.0% R316.1) 543-9-40(0.0% R453.1) 509-12-71(0.0% R342.2)
527-15-50(0.0% R409.1) 468-29-95(0.0% R277.0) 537-10-45(0.0% R430.7) 540-6-46(0.0% R427.9) 505-18-56(0.0% R382.0) 468-19-73(0.0% R322.8)
435-20-105(0.0% R246.9) 526-1-33(0.0% R481.0) 518-5-37(0.0% R458.5) 469-18-73(0.0% R323.1) 478-9-73(0.0% R326.4) 428-9-98(0.0% R256.1)
・まだ落ちる局面があるようだ。詰み絡みのようだが…。静止探索絡みか?
sfen ln4+P1p/9/ppp1kp2R/b2p5/K6+R1/2g6/P3+lg3/3s4+p/L+b7 b S2G9pl3n2s 173
よくわからないのでDebugビルドでtest autoplayで回しておく。
これでバグが発見するのに要する時間は、2時間×5PC*10倍nps = 100時間ぐらい回さないといけないのか。
いくらなんでもひどいな。Releaseモードで回すか。これなら10時間程度で見つかるはず..
→ これ自動テストのなかでもっと効率的に見つけられないのか?
if (param1!=5)
{
}
みたいにすれば特定のパラメータでその処理を省略することは出来るから
一晩寝かせておけばそこそこ原因がわかるはず…。
→ と思ったが3時間ほど回して落ちない…。
・連続自己対局のときに思考時間ばらつかせないとな…。
・V1.76b
連続自己対局のために
go time 100
のようにしたら100ms秒だけ考えるという仕様にするか?
go randtime 100
としたときに100~300ms考えるという仕様にするとか?
go rtime 100
こうするか。実装した。
→ availableTime = Limits.rtime + prng.rand(Limits.rtime * 2);
→ 終局の局面はそこそこバラけるようになったる
■ 2016/02/24 V1.75
・25000局ほど回して、V1.74、1度だけ落ちてる。
1<sfen 1n3k3/1PK2g3/2np5/2+B2+B3/L1pPp4/6p1+p/5G3/2G1GP2+p/1+rS3+r+l1 w 3P2LN3S6pn 142
→ 例によって単体だと落ちない。26コアで8時間かけて1回落ちる程度のバグは探すの大変。
long effect絡みのような気もするが、これ修正するのは容易ではないな…。
QUIET_CHECKがpseudo-legalか確認しておく。
→ 王手がかかっていない局面なので回避手になっているかは調べる必要がない。
ああ、わかった。
MovePickerの静止探索用のほうも、endMoves間違えてた
endMoves += (_ttMove != MOVE_NONE);
↓
endMoves += (ttMove != MOVE_NONE);
これでいいや。よしよし。
■ 2016/02/23 V1.74
・乱数seed、外部から読み込めるようにしたほうがよさげ。
thread idではなくprocess idにしたら解消するか?
→ まあいいや。
・0.1秒で3万局やって47回落ちてた。26並列対局において1時間で6回ぐらい落ちるわけか。10分で1回落ちるな。
対局ログサイズ2.7MB
ASSERTに引っかかったケースなし。うわぁぁぁ。
思考エンジンからログを書きだそうにもバッティングするしな..
local server、思考エンジンからのエラーは先頭にErrorの文字を入れるように。
・ランダマイズやはり何かおかしい気がする。子プロセスだとthread idが固定化されているとしか思えない。
process IDにするか..。定跡局面で定期的にランダム思考させるか。うむむ..
→ thread IDでバラけてた。うわぁぁぁ。
・PRNG、初期化時に乱数まわすようにした。
int n = (int)get_thread_id() & 1024; // 最大1024回、乱数を回してみる
for (int i = 0; i < n; ++i) rand<uint64_t>();
・local serverにメッセージをbypassする仕組みが要るのでは…。
Redirectorのread()で"Error"の文字列をbypassするようにした。
文字列はERRORではなくErrorで統一することにした。
・定跡早い段階で抜けると同じ展開になるというのはあるのか…。
MultiPVで思考するとかしないと同じ展開を抜けられないな。まあ、仕方ないか。
local serverで開始タイミングばらけさせるの意味ないな。
・nano plus、静止探索をreturn evaluate(pos);にしてどうなるかやろう。
→ これでも落ちるのか..
・置換表の指し手、無効化してみる。
// ttMove = ttHit ? tte->move() : MOVE_NONE;
ttMove = MOVE_NONE;
→ これでもないのか。なんなのだ…。
・killerも無効化してみる。
case KILLERS:
move = *currentMoves++;
#if 0
if ( move != MOVE_NONE // ss->killer[0],[1]からコピーしただけなのでMOVE_NONEの可能性がある
&& move != ttMove // 置換表の指し手を重複除去しないといけない
&& pos.pseudo_legal(move)
&& !pos.capture_or_pawn_promotion(move)) // 直前にCAPTURES_PRO_PLUSで生成している指し手を除外
return move;
#endif
break;
→ これも違うのか..
mate1消す
LONG_EFFECT_LIBRARYも使わない。
→ これでもあかんのか。なんなん…。
// (ss + 2)->killers[0] = (ss + 2)->killers[1] = MOVE_NONE;
#if 0
auto draw_type = pos.is_repetition();
if (draw_type != REPETITION_NONE)
return draw_value(draw_type,pos.side_to_move());
#endif
これでどうか。→ あかん。
MovePicker、これでどうか。
// KILLERS, // KILLERの指し手
// BAD_CAPTURES, // 捕獲する悪い指し手
GOOD_QUIETS, // CAPTURES_PRO_PLUSで生成しなかった指し手を生成して、一つずつ返す
// BAD_QUIETS, // ↑で点数悪そうなものを後回しにしていたのでそれを一つずつ返す
これもあかんのか。probeの直後、
ttHit = false; // 置換表にhitしていないことにする。
これでどうか。→ 落ちない?
// -----------------------
// 局面を評価値によって静的に評価
// -----------------------
ttHit = false; // 置換表にhitしていないことにする。
ここならどうか。→ 落ちる
Move ttMove = RootNode ? thisThread->rootMoves[thisThread->PVIdx].pv[0]
: ttHit ? tte->move() : MOVE_NONE;
ttHit = false; // 置換表にhitしていないことにする。
ここは? → 落ちる
MovePicker mp(pos, MOVE_NONE /*ttMove*/ ,ss);
これは? → 落ちないくさい。MovePickerの置換表絡み怪しげ。
endMoves += (ttMove_!= MOVE_NONE);
これか。
endMoves += (ttMove != MOVE_NONE);
こうやん..。
→ 2000局やって、落ちない。これだった…。やっと改良に戻れる。
→ V1.70と対局させてみる。
→ 弱くはなってなさげ。
50.2%
#28
やねうら王nano plus V172
落ちる原因調査 , 1スレッド、0.1秒設定
#25
やねうら王nano plus V170
千日手判定追加 , 1スレッド、0.1秒設定
12481-389-12401(30.6% R1.1)
■ 2016/02/22 V1.73
・定跡のrandomizeのため、randのrandomizeの性能を上げる。
→ thread idもseedに用いるように変更。
・local server、終局時のsfen出力して、同一局面でないことを確認したほうがいいのでは..
・てか、どこをいじった結果かは知らんが落ちなくなってる…。
→ と思ったら落ちたようだ。
sfen ln1g4+L/1s4s1P/p1p1pk3/1P4pp1/P8/1B4n1R/2NS1+p3/3GS3K/L4g1N1 b 5PLBG4pr 103
・DrawValue、関数を通すようにする。→ draw_value()
同じところで落ちてるな。単体だとここで落ちないんだよな…。
→ てかrandom playerでも落ちるんか?それを先に確認しないと原因の絞りようがない。
→ random player落ちないな…。test rpで落ちないのだから落ちないか…そうか…。
→ nanoも連続自己対局させてみる。
→ nanoは4000局で落ちないのか…。
つまりpseudo_legal()は正しい。
nano plusのMovePickerとかis_repetitionとかが怪しいのかな?
is_repetition、シンプルだし、たぶん合ってる。
QUIET_CHECKSが怪しい。
case QCHECKS:
// endMoves = generateMoves<QUIET_CHECKS>(pos, moves);
endMoves = moves; // 生成しないと?
break;
→ 生成しなくとも落ちた。なんなんこれ…。
sfen +B+P1S+P1+L2/3+R5/1p1p+Pp+L+R1/1kp6/p6G1/9/P3+p1P2/5+b1K1/L1G6 b 7PL4N3SGg 131
sfen 1s3pR+R1/l3kg2P/p1+Np4+P/4pbl2/P2Pn4/L1P1K4/1P7/1sS2PB+p1/3G5 b PLS5p2n2g 151
nano plusのMovePicker、ちゃんと見なおしたほうがよさげ…。
sfen 3+P2kp+R/l3gl+r2/pppp1pp2/7sB/9/9/PPP2SPPN/1B3P1G1/L1SG2K2 b 3PL2NGpns 105
・nano plus、"go infinite"に対応させる。
is_repetition を 無効化して落ちるかのテスト。
→ 落ちたか。これはきつい。
・ASSERTに関して、errorでも出力できればいいのだが…。
local-serverで"ERROR:"というメッセージをリダイレクトするようにして、
ASSERTでは"ERROR:xxx"と出力できるようにするか。
→ USE_DEBUG_ASSERT追加
#define ASSERT(X) { if (!(X)) std::cout << "\nERROR : ASSERT(" << #X << ")\n"; }
こうした。
・local-serverでgame over時にsfenの出力
・thread idだと同じ番号なのか…?
local-serverの開始タイミングをずらすか。
→ こうした。
for (auto th : Threads.slaves)
{ th->start_searching(); sleep(10); } // 開始タイミングをずらすことで乱数seedをばらけさせる
→ これでもまだ乱数偏るな…なんなの…。
→ thread_idが同じ値なのか?うむむ?
乱数seed調整してみた。
PRNG() : s(now() ^ uint64_t(this) + get_thread_id()*1234567) {}
→ これでも駄目か..
// 乱数のseedなどとしてthread idを使いたいが、
// C++のthread idは文字列しか取り出せないので無理やりcastしてしまう。
inline uint64_t get_thread_id()
{
auto id = std::this_thread::get_id();
if (sizeof(id) >= 8)
return *(uint64_t*)(&id);
else if (sizeof(id) >= 4)
return *(uint32_t*)(&id);
else
return 0; // give up
}
別マシンと同じthread idを引いてくることってありえるのか?わからん..
→ そうでもなさげなのでこれはいいや。
・ASSERTでエラーが出力されるようにしたnano plus、1300局でやっと落ちたが、
ASSERTにはかからず。
sfen ln1g4+L/1s4s1P/p1p1pk3/1P4pp1/P8/1B4n1R/2NS1+p3/3GS3K/L4g1N1 b 5PLBG4pr 103
■ 2016/02/22 V1.72
・また落ちる局面があった。
sfen l+R2+L3+P/g4P2G/pppp3b1/4+r2bk/4p4/P1PSP4/1P1S1G3/2KG5/LNS5+p w 2N6plns 142
→ 落ちない。わからん。
sfen 1G4+L1+S/+r8/1p+S4+P1/2N1+B4/9/4GP2+B/+ln2K2p+R/k5s1p/1g+p1G1+p+p+n w 6PLN4pls 186
sfen +R8/5G3/1p2+B+N1+B1/p1ps5/2k4K1/P1+rP1+sP2/4g4/9/+s1G4+p1 b 5P3L2NS6plng 133
・打ち歩詰めの指し手生成、~UsではなくUsか。修正した。
Bitboard pe = pawnEffect(Us,pos.king_square(~Us));
→ 違った。あってた。
・歩を打つときの判定、legal_pawn_drop()にまとめた。
・nano-plusのmate1ply()、残り深さがONE_PLYより大きいときにのみ呼ぶようにした。
・local game serverでエンジン名ではなく実行ファイル名を表示するように。
・local game serverでtime out時(おそらくエンジンが停止した)に、継続できるように修正。
→ これで永続的にランニングできる…はず。(暴走したエンジンがに残存しなければ)
・floodgateに投入してあるほう、R2200付近の対戦相手が少なくて正確なレーティングがわからない。
たぶんR2200ぐらいなのではあるのだろうけども。もうちょっと強くしないとな。
・この局面の指し手、おかしい
>1:position startpos moves 7i6h 3c3d 8h7i 8c8d 6i7h 8d8e 3i4h 8e8f 8g8f 8b8f P*8g 8f8d 5g5f P*8f 8g8f 8d8f P*8g 8f5f 5i6i 2b4d 6h5g 5f5e 5g4f 5e8e 4h5g 5c5d 5g6f 8e2e 3g3f 2a3c 2i3g 2e8e 7g7f 4a5b 8i7g 8e8b 2h5h P*8f 8g8f 8b8f P*8g 8f7f 5h5d 7f7d 5d5f 4d6b 6f6e 7d9d 5f8f P*8b P*5d 7c7d 8f5f 8a7c 4f5e 7d7e 2g2f 6b2f 4i3h 3a4b 3f3e 2f3e 7i3e 3d3e 5f2f B*1d 2f5f 3e3f B*2b 3f3g+ 3h3g 3c4e 3g4f N*3d 4f3f P*3e 5d5c+ 4b5c 2b3c+ 5c4b 3c4b 5a4b S*2e 3e3f 2e1d 1c1d P*5c 5b6b 6e5d 4e3g+ 6i7i B*8c 5d4c+ 4b4c
・local serverで暴走した局面集
shogi-observer-log.txt(570): 4<sfen ln1g4+L/1s4s1P/p1p1pk3/1P4pp1/P8/1B4n1R/2NS1+p3/3GS3K/L4g1N1 b 5PLBG4pr 103
shogi-observer-log.txt(702): 1<sfen ln1g4+L/1s4s1P/p1p1pk3/1P4pp1/P8/1B4n1R/2NS1+p3/3GS3K/L4g1N1 b 5PLBG4pr 103
shogi-observer-log.txt(1425): 4<sfen +S2+N5/8+R/G8/9/3K+R4/9/4+s+p+p+pg/1+p3+b+p2/1k1+b+p+n+p+p+p b 8PLp3l2n2s2g 157
shogi-observer-log.txt(1745): 4<sfen ln1g4+L/1s4s1P/p1p1pk3/1P4pp1/P8/1B4n1R/2NS1+p3/3GS3K/L4g1N1 b 5PLBG4pr 103
shogi-observer-log.txt(2041): 2<sfen 1b4+LG1/9/2nP1+P2k/1P1+R1K1N1/6PP1/2p2g1+r1/4+p2g1/1S5+p1/+pN4+pb1 b 6PS2p3ln2sg 251
shogi-observer-log.txt(2249): 2<sfen l1n3+L1+S/1kr+B1p3/pp1+Sp1+b2/2p6/9/2PG2P2/P1K2P3/4G4/9 w 4PL3N2SR2G5pl 140
shogi-observer-log.txt(2606): 1<sfen ln1g4+L/1s4s1P/p1p1pk3/1P4pp1/P8/1B4n1R/2NS1+p3/3GS3K/L4g1N1 b 5PLBG4pr 103
shogi-observer-log.txt(2840): 3<sfen lns3+L2/4+R4/ppkpp4/2p3+B2/3N1pK2/8+R/PPPP5/1B4+l2/LNSG2+p2 w 4P2S3G3pn 82
shogi-observer-log.txt(2999): 4<sfen ln4+L1+N/k8/1g2G+B1+S1/p8/6K2/1+r2+p4/+p1+p6/7p+p/2+r5+p w 8P2L2S2G3p2nsb 180
shogi-observer-log.txt(3888): 4<sfen ln1g4+L/1s4s1P/p1p1pk3/1P4pp1/P8/1B4n1R/2NS1+p3/3GS3K/L4g1N1 b 5PLBG4pr 103
shogi-observer-log.txt(4669): 2<sfen 4g1k2/3Ps1p2/R8/2+B3LBL/ppP1SP3/1RN6/6N2/3SK4/3G1GS2 b 5PLN7plng 133
shogi-observer-log.txt(4874): 2<sfen 3+P2+L1+S/1+P4+N+B+P/7+S1/4+rlg1P/4P1p2/1P1GS1g1p/P2P+b+p1+p1/LKS3k2/5P+p1+n w 2P2NR2plg 238
shogi-observer-log.txt(5108): 3<sfen ln1g4+L/1s4s1P/p1p1pk3/1P4pp1/P8/1B4n1R/2NS1+p3/3GS3K/L4g1N1 b 5PLBG4pr 103
shogi-observer-log.txt(5327): 2<sfen lnsg1+L3/9/ppppk4/2N2gpb1/1K4P2/1P4R1s/P1P+r3+p1/2s1p4/L1+b1+n1S2 w P2G6pln 146
shogi-observer-log.txt(5723): 4<sfen ln1g4+L/1s4s1P/p1p1pk3/1P4pp1/P8/1B4n1R/2NS1+p3/3GS3K/L4g1N1 b 5PLBG4pr 103
shogi-observer-log.txt(6331): 4<sfen ln1g4+L/1s4s1P/p1p1pk3/1P4pp1/P8/1B4n1R/2NS1+p3/3GS3K/L4g1N1 b 5PLBG4pr 103
shogi-observer-log.txt(7151): 4<sfen ln1g4+L/1s4s1P/p1p1pk3/1P4pp1/P8/1B4n1R/2NS1+p3/3GS3K/L4g1N1 b 5PLBG4pr 103
shogi-observer-log.txt(7569): 4<sfen ln6+L/2ksg4/pppppp3/3rN4/4+b4/2PPS4/PP1K1PN2/6S2/LNSG1G2+p w BR6plg 70
shogi-observer-log.txt(8258): 1<sfen 5s1+P+B/1rk6/2nss3+N/1p2p3G/9/2+r6/1+b1P3p+p/2PK2+p1+p/+n+l1G2+p+p+p w 5P2Gp3lns 170
shogi-observer-log.txt(9067): 2<sfen ln1g4+L/1s4s1P/p1p1pk3/1P4pp1/P8/1B4n1R/2NS1+p3/3GS3K/L4g1N1 b 5PLBG4pr 103
shogi-observer-log.txt(13072): 4<sfen ln1g4+L/1s4s1P/p1p1pk3/1P4pp1/P8/1B4n1R/2NS1+p3/3GS3K/L4g1N1 b 5PLBG4pr 103
shogi-observer-log.txt(13169): 2<sfen ln1g4+L/1s4s1P/p1p1pk3/1P4pp1/P8/1B4n1R/2NS1+p3/3GS3K/L4g1N1 b 5PLBG4pr 103
shogi-observer-log.txt(13791): 4<sfen ln1g4+L/1s4s1P/p1p1pk3/1P4pp1/P8/1B4n1R/2NS1+p3/3GS3K/L4g1N1 b 5PLBG4pr 103
shogi-observer-log.txt(14215): 4<sfen lnS+S4+P/1n2+R3+P/k+B7/1pp3np1/p7K/6P2/P8/1L2+l1G2/LN6+R w 10P2SB3G 180
shogi-observer-log.txt(15356): 2<sfen ln4+L2/1r1+S+BG2P/pkp1+B3+N/1p1p5/9/2P6/PP1P2+p2/4K2+p+p/LNSG1S2+p b 4PLNRGpsg 87
→ 同じ局面いっぱいある…。定跡、そんなにバラけてないのか…。それは残念…。連続自己対局、思考時間、ランダム化したほうがいいのでは…。
random playerをしばらく回す。
→ 検出できない。nano plusが何かバグっているのか…。そうか…。
→ nano plusを1プロセス内で連続自己対戦させるか。
→ testコマンドにautoplay追加。
・LimitTypeにサイレントモード追加。
・nano plusにサイレントモード追加。
・is_draw()、最初に2手遡るの忘れていたので修正。
・is_repetitionに名前変更。
setoption name Hash value 4
isready
test autoplay
これでしばらく回しておく。
→ 一時間回して落ちない。
ASSERT、引っかかるときにメッセージを出すようなASSERT作るべきかも..
仕方ないので、自己対局で落ちるかのテストをする。
■ 2016/02/22 V1.71
・色々いじったので、search()のなかでmate1有効にしてみる。
// RootNodeでは1手詰め判定、ややこしくなるのでやらない。
// 置換表にhitしたときも1手詰め判定は行われていると思われるのでこの場合もはしょる
if (!RootNode && !ttHit )
{
bestMove = pos.mate1ply();
if (bestMove != MOVE_NONE)
{
// 1手詰めスコアなので確実にvalue > alphaなはず。
alpha = mate_in(ss->ply);
tte->save(posKey, value_to_tt(alpha, ss->ply), BOUND_EXACT,
DEPTH_MAX , bestMove, ss->staticEval, TT.generation());
return alpha;
}
}
こうしておく。なんか前のバージョンに有意に勝ち越す気がしなくもない…。
・V1.71a
if (!RootNode && !ttHit && depth > param1*ONE_PLY)
こうして、param1 = 0 .. 8ぐらいで最適値を調べてみる。PVとnon PVで違ってくるのか..まあいいか…。
49.1% 50.4% 50.7% 50.8% 51.1%
#27
やねうら王nano plus V171a
search()でmate1呼び出すように param1でそのdepth変更 , 1スレッド、0.1秒設定
#0
やねうら王nano plus V170
千日手判定追加 , 1スレッド、0.1秒設定
1613-37-1672(84.8% R-6.2) 1658-51-1630(31.3% R3.0) 1596-47-1550(20.6% R5.1) 1571-45-1521(18.4% R5.6) 1579-31-1511(11.1% R7.6)
depth > ONE_PLY
これぐらいで呼び出さないとリターン小さすぎなのか。そうか。
■ 2016/02/22 V1.70
・Position::is_draw()追加した。
・nano-plusに連続王手の千日手の検出コードを追加する。
・nano-plusでMAX_PLY到達のときのスコアを引き分けのスコアに変更する。
→ 変更した。無駄な探索が減った分と、連続王手でMAX_PLYまで延長していたのが
解消した分だけ強くなっているような…。(+R20)
53.0%
#25
やねうら王nano plus V170
千日手判定追加 , 1スレッド、0.1秒設定
#0
やねうら王nano plus V169c
打ち歩詰め関係の修正 , 1スレッド、0.1秒設定
351-18-311(5.5% R21.0)
■ 2016/02/21 V1.69
・指し手生成に打ち歩詰め入れて、pseudo_legal()で打ち歩詰め判定入れるの忘れていた。修正。
・V1.69a
legal_dropを呼ぶときにその前に敵玉がいるかの判定が要るんだった…。修正。
王手になる打ち歩の指し手生成、修正。
・V1.69b
Square pawn_attack = (sideToMove == BLACK) ? to + SQ_U : to + SQ_D;
if (sq_king != pawn_attack)
return true;
// → この判定の仕方だと、kingが駒落ちでSQ_NBにいるときにSQ_NB - 9の場所に歩を打つとkingの
// 行き場所がないから打ち歩詰めと判定されてしまう。
if (pawnEffect(sideToMove, to) != Bitboard(sq_king))
return true;
こう書くべきなのか…。同様のミス、他はやってなかった。
・V1.69c
pseudo_legal()を以下のように修正。
// 歩のとき
if (pr == PAWN)
if ((pieces(us, PAWN) & FILE_BB[file_of(to)]) // 二歩
|| ((pawnEffect(us, to) == Bitboard(king_square(~us)) && !legal_drop(to)))) // 打ち歩詰め
return false;
legal_drop()に玉の位置に関するASSERT追加。
王手となる打ち歩の指し手生成、以下のように修正。
// 二歩と打ち歩詰めでないならこの指し手を生成。
if (!(FILE_BB[file_of(to)] & pos.pieces(Us,PAWN)) &&
!((pawnEffect(Us, to) == Bitboard(king_square(~Us)) && !pos.legal_drop(to))))
mlist++->move=make_move_drop(PAWN, to);
・勝率の偏りはないと思うが、1000局ほどランニングしておく。
→ 弱くはなってなさそうなのでこれでOk.
4000局やってみたところ、+R10程度上がっていることがわかった。
■ 2016/02/21 V1.68
・nano plus、full depth searchも、nonPVでやるべきでは..
→ 修正した。
・LMRのreduction量、ONE_PLYを引いてからリダクションしないといけないの、間違えていたので修正。
・V1.68a
・full depth searchで探索窓狭くしていなかったの修正。
130ぐらい低いな…。わけがわからん…。
Depth d = max(newDepth - r + (Depth)1, ONE_PLY);
こうしたら、めっちゃ勝率上がった。わけがわからん…。
77.9%
#20
やねうら王nano plus V168
LMR、full depth search修正,1スレッド、0.1秒設定
#
やねうら王nano plus V166
通常探索でevaluate()を呼び出すように,1スレッド、0.1秒設定
187-1-53(0.0% R219.0)
・V1.68b
Depth d = max(newDepth - r , ONE_PLY);
こう戻してみる。
37.1%
#21
やねうら王nano plus V168b
LMR変更テスト,1スレッド、0.1秒設定
#
やねうら王nano plus V166
通常探索でevaluate()を呼び出すように,1スレッド、0.1秒設定
109-3-185(100.0% R-91.9)
→ やはり-R90ぐらいになる。わけがわからん。
・V1.68c
捕獲はreduction減らす。
→ 関係なさげ。
reduction、0.5手延長のようになって強いだけなのか?
一度、nanoと比較してみる。
94.0%
#22
やねうら王nano plus V168c
LMR変更テスト2,1スレッド、0.1秒設定
#1
やねうら王nano V140
やねうら王nanoの最終版1スレッド、0.1秒設定
156-1-10(0.0% R477.2)
88.2%
#21
やねうら王nano plus V168b
LMR変更テスト,1スレッド、0.1秒設定
#1
やねうら王nano V140
やねうら王nanoの最終版1スレッド、0.1秒設定
150-1-20(0.0% R350.0)
→ どうも0.5手延長の効果のような気がしてきた。
ちょっと気分は悪いが、今回のものを採用する。
・Position::capture(),capture_or_promotion()でdrop除外するの忘れていた。修正。
→ これのためにLMRの処理がおかしくなっていたのか?
→ これを修正したが、それでもV1.68bにはかなり負け越す。
30.1%
#
やねうら王nano plus V168c
LMR変更テスト2,1スレッド、0.1秒設定
#21
やねうら王nano plus V168b
LMR変更テスト,1スレッド、0.1秒設定
31-1-72(100.0% R-146.4)
・V1.68d
わかった。
value = depth < ONE_PLY ?
は、まちがい。
value = newDepth < ONE_PLY ?
これが正しい。
1.66と対戦させる。結構勝ち越すようだ。
これでcommitしておく。
floodgateでR2500以上つくなら、これでnano plusは開発終了。
■ 2016/02/21 V1.67
・nano plus、improvingフラグ用意。
→ この改良は微差のようなのでこのままランニングさせておくる
50.5%
#19
やねうら王nano plus V167
improving追加,1スレッド、0.1秒設定
#0
やねうら王nano plus V166
通常探索でevaluate()を呼び出すように,1スレッド、0.1秒設定
934-3-915(32.9% R3.6)
ほぼ変わらない…。なんなの…。
■ 2016/02/21 V1.66
・nano plus、通常探索でeval保存するようにした。
+R50ぐらいup?
通常探索でevalが呼び出されると差分計算が出来るようになるのでその分だけ得なのか…。
やや高速化した気がする。
・Eval::eval()という関数名、気に入らないのでevaluate()と名前を変更する。
・連続対戦のときの戦績が偏るの、同じseedの乱数を使って定跡選択をしているからという話はないか…?
→ uint64_t(this)を乱数seedにしているので実行ファイルの読み込みのランダム化が行われているなら問題なさげ…。
■ 2016/02/21 V1.65
・まだ落ちる局面があるようだ。もしかして255手目でMAX_PLYに到達して落ちた感じ?
4<Error : engine timeout , engine name = YaneuraOu nano plus KPP 1.62 64 AVX2
4< □ 金 □ □ 玉 金 と □ と
4< □ □ 圭 □ □ 圭 □ 杏 □
4< □ □ と □ □ □ □ と と
4< □ □ □ □ □ 馬 □ □ □
4< □ □ □ □ □ □ □^歩^と
4< □ □ □ □ □ □ □^と □
4< □ □ □ □^全 □^と □ □
4< □ □ □ □^龍^と^玉^と^と
4< □^金^と □ □ □^と^と^と
4<先手 手駒 : 歩2 香 角 , 後手 手駒 : 香2 桂2 銀3 飛 金
4<手番 = 先手
4<sfen 1G2KG+P1+P/2+N2+N1+L1/2+P4+P+P/5+B3/7p+p/7+p1/4+s1+p2/4+r+pk+p+p/1g+p3+p+p+p b 2PLB2l2n3srg 255
→ nano plusのsearch stackがkillerの初期化でアクセス違反になるっぽい。
search<Root>は、やめたほうがいいのでは..うーん。id_loop()、あとで考え直す。
とりあえずss+1にしてるのはおかしいのでそこだけ修正する。
あとsearchにMAX_PLYの判定追加する。
連続王手の千日手、判定していないのでそれ絡みで無限に延長されてPVでMAX_PLYに到達して落ちるのか。そうか…。
とりあえずMAX_PLYの判定だけ追加した。
1<Error : engine timeout , engine name = YaneuraOu nano plus KPP 1.64 64 AVX2
1<^香 □^玉 □ □ □ □ □ と
1< □ □^龍^金 □ □ □ 馬 □
1< □ □^桂 □ □ と □ □ □
1< □ □ □^歩 □ □ □ □ □
1< □ □ □ □ 歩 □ □ □ □
1< □ □ 馬 □ □ □ □^歩 □
1<^と □ □ □ 玉 □ □ □^と
1< □ □ □ □ □ □ □^と^と
1< □ □ 龍 □ □ □ □^と □
1<先手 手駒 : 歩4 桂3 銀 金 , 後手 手駒 : 歩4 香3 銀3 金2
1<手番 = 先手
1<sfen l1k5+P/2+rg3+B1/2n2+P3/3p5/4P4/2+B4p1/+p3K3+p/7+p+p/2+R4+p1 b 4P3NSG4p3l3s2g 157
・前のバージョンに対してだいぶ負けるようになった。もしかして前のバージョン、連続王手の千日手で不利になったときに逃れているパターンがあるのか?
// 最大手数を超えている
if (ss->ply >= MAX_PLY)
return VALUE_ZERO; // Draw Score
→ こう変更して引き分けを回避させよう。
→ これでもV1.64に-R100ほど負け越している感じ。なんなん…。
→ 打ち歩詰め絡みで何かやらかしたのか?
→ recap深さは、やはり-3のほうが良いということなのか..戻した。
・メモリ8GBのときnormal perft、うまく動かないという報告が。
→ 固定で確保してるんだった…。
■ 2016/02/21 V1.64
・nano plusで静止探索、深さ-5までCAPTURESを生成しているの、よくない可能性が微レ存。
// 静止探索でこれより深い(残り探索深さが少ない)ところではRECAPTURESしか生成しない。
DEPTH_QS_RECAPTURES = -3*(int)ONE_PLY,
→ 1.57aと対戦させておく。こっちのほうが明らかに強いな..
・V1.64a
// 静止探索でこれより深い(残り探索深さが少ない)ところではRECAPTURESしか生成しない。
DEPTH_QS_RECAPTURES = -2*(int)ONE_PLY,
→ こう変更するとどうなのだ?
→ こっちのほうがわずかに強いっぽい。うわぁぁぁ。
今後、これを基準ソフトにしよう..
50.7%
#16
やねうら王nano plus V164a
静止探索のRECAPの深さ-3→-2に変更,1スレッド、0.1秒設定
#0
やねうら王nano plus V164
静止探索のRECAPの深さ-5→-3に変更,1スレッド、0.1秒設定
1687-16-1638(19.8% R5.1)
→ floodgateに放流しておく。
■ 2016/02/21 V1.63
・local server、timeout時にMOVE_RESIGNを返すように変更。
・local server、非合法手もMOVE_RESIGN扱いするように変更。
・そのときにエラーを出力するように変更。
・local server、エンジンを配置するpath変更できるように。
→ engine-config.txtのほうでエンジン名にpathが指定されていればいいか…。
■ 2016/02/21 V1.62
・打ち歩詰めの処理、LongEffect有り時の高速化
→ 綺麗には書けた気がする。あまり呼び出し頻度の高くない部分のコードなので高速化には寄与していない気が…。
===========================
Total time (ms) : 16981
Nodes searched : 20291525
Nodes/second : 1194954
1%ぐらいnpsが上がったのか?ちょっと嬉しい。
・nano-plusのデバッグ用のコード消してなかったの修正。
■ 2016/02/21 V1.61
・long effectがあるときにeffected_toは高速化できるのでそのコード追加。
改良前とbenchのnode数が変わらないことを検証する。
===========================
Total time (ms) : 17606
Nodes searched : 20291524
Nodes/second : 1152534
→ 変更後。nps 0.2%ぐらい上がった?
===========================
Total time (ms) : 17578
Nodes searched : 20291524
Nodes/second : 1154370
ASSERT無効にしてベンチ
===========================
Total time (ms) : 17142
Nodes searched : 20291525
Nodes/second : 1183731
何故かノード数が1だけ変わる…。do_move()するようなASSERTどこかに入っているのか..?あとで調べる。
とりあえずこれでcommitして、floodgateに放流しておく。
・nanoとnano plusと対局させておく。
■ 2016/02/21 V1.60
・pos.legal()の判定おかしいのか。
position startpos moves 7i6h 5c5d 6i7h 3c3d 2g2f 8c8d 7g7f 2b8h+ 7h8h 7a6b 6h7g 3a3b 2f2e 3b3c 4i5h 4a3b 5h6h 4c4d 6h7h 5a4a 5i5h 6a5b 7g8f 7c7d 8f7g 5b4c 5h6i 4a3a B*5b 3a2b 5b6a+ B*9d 6a9d 9c9d B*5b 4c4b 5b6a+ B*4c 6a4c 4b4c 6i5h 6b5c 2e2d 3c2d 7g6f 9d9e 6f6e B*8c 8i7g 6c6d 6e5f 7d7e 7f7e P*7f 7g6e 6d6e 9g9f 9e9f P*2e 2d3c 7e7d 8c7d 9i9f 9a9f P*7e 7d8c B*6c N*8e 8g8f 8e9g+ 8h8g 9g8g 7h8g 9f9g+ 8g7f 8c9d 7f6e P*7f P*9e 9d7b N*9d 7b6c 9d8b+ L*2g 2h2g 5d5e 2g2h G*2g 6e7d
go btime 169000 wtime 29000 byoyomi 10000
^飛 王 ★
★の升に移動する指し手はevasionにはならない。
ゆえにpos.legal()の判定、これを考慮しないといけない。
effected_to()の仕様がおかしいんだな。修正した。
■ 2016/02/21 V1.59
・local server、応答がなくなる原因わかった。bestmove待ちでエンジンがbestmoveを返さないと
そのまま待ち状態になるのがいけないのか。1分でtimeoutとしよう。
// タイムアウトチェック(連続自己対戦で1手に1分以上考えさせない
if (now() >= start + 60 * 1000)
{
sync_cout << "Error : engine timeout" << endl << pos << sync_endl;
return MOVE_NONE;
}
・また、local server、一行ずつ出力するのをデフォルトとしよう。
こちらのほうが、外部から自動操作するときに出力をparseするのが簡単だから。
// 1行ずつ結果を出力するモード
#define ONE_LINE_OUTPUT_MODE
■ 2016/02/21 V1.58
・DEPTH_QS_RECAPTURESとりあえず-10にしておく。この値でそんなに悪くはなさそうなので。
→ また後日調整する。
■ 2016/02/20 V1.57b
・local server機能で、プロセスが終了しないとき用の修正。
→ これでも終了しないことがあるためprocessのkillも行なうようにした。
→ これでもプロセス残ることがある。おかしい。ソース、読みなおす。
→ local-serverのidle_loopにsleep(5)を追加。
→ 長手数による引き分け、条件がMAX_PLYになっていたのを256に修正。
→ こっちの問題ではなさげ..
→ ソースコード、再度整理する。
・nano-plusのrecaptureの指し手生成間違っていたのを修正。
・nano-plusで静止探索での3手以上延長しないほうがいいのか実験。
// 探索深さが-3以下ならこれ以上延長しない。
if (param1)
{
if (depth < -3 * ONE_PLY)
{
// せっかくevaluateを呼び出したので置換表にhitしていないなら今回のevaluateの値を保存しておく。
if (!ttHit)
tte->save(posKey, value_to_tt(bestValue, ss->ply), BOUND_LOWER,
DEPTH_NONE, MOVE_NONE, ss->staticEval, TT.generation());
return bestValue;
}
}
→ なぜかR220ほど下がる。
RECAPTURESの指し手生成なにかおかしいのでは..
RECAPのフェーズをparam1依存にして、これでパラメーターを変えた実験をしてみる。
延々、同じ升でRECAPするだけのはずなのにレーティング下がるのなんで…。
else if (depth > /*DEPTH_QS_RECAPTURES*/ (Depth)(-3-param1))
stage = QSEARCH_WITHOUT_CHECKS_START;
→ MovePickerでttDepth突っ込んでたから延々とCAPTURESが生成されてたくさい。
→ これ修正したらずいぶんマシになった気がする。ベストな値を探す。
51.8% 56.0% 59.6% 59.8% 64.6% 62.7% 63.9%
#
やねうら王nano plus V157b
やねうら王nano plus param1!=0なら静止探索で3手以上延長しない,1スレッド、0.1秒設定
#0
やねうら王nano plus V157a
やねうら王nano plus 静止探索のオーダリングいじった,1スレッド、0.1秒設定
489-0-455(12.7% R12.5) 529-0-415(0.0% R42.2) 561-0-381(0.0% R67.2) 536-0-360(0.0% R69.1) 579-0-317(0.0% R104.6) 562-0-334(0.0% R90.4) 470-0-266(0.0% R98.9)
↓条件をこう変えてみる
else if (depth > /*DEPTH_QS_RECAPTURES*/ (Depth)(-7-param1))
stage = QSEARCH_WITHOUT_CHECKS_START;
70.3% 65.9% 72.1% 64.0% 65.3% 64.1% 60.0%
#13
やねうら王nano plus V157b
やねうら王nano plus param1に応じて静止探索のrecapまでの手数変更,1スレッド、0.1秒設定
#0
やねうら王nano plus V157a
やねうら王nano plus 静止探索のオーダリングいじった,1スレッド、0.1秒設定
270-0-114(0.0% R149.8) 244-6-126(0.0% R114.8) 253-1-98(0.0% R164.8) 224-2-126(0.0% R100.0) 226-6-120(0.0% R110.0) 223-4-125(0.0% R100.6) 210-2-140(0.0% R70.4)
■ 2016/02/20 V1.57a
・nano-plusで静止探索の1つ目の深さでは、CAPTURESの指し手を生成するように。(+R180)
・指し手生成に以下の2つを追加
QUIET_CHECKS, // 王手となる指し手(歩の不成などは含まない)で、CAPTURESの指し手は含まない指し手
QUIET_CHECKS_ALL, // 王手となる指し手(歩の不成なども含む)でCAPTURESの指し手は含まない指し手
■ 2016/02/20 V1.57
・nano-plusで静止探索で置換表のlookupをするように。(棋力にほぼ影響なさげ..)
→ これnanoのものに戻してもいいぐらいだな..。静止探索絡みはminiに持ち越すか…。
・置換表でdepthが深いと1byteに収まらないのでONE_PLYで割った値を格納するように変更。
・Depthの定数に色々追加。
■ 2016/02/19 V1.56
・nano-plusにLMRを追加。+R150
・静止探索1手詰め + LMRで +R210ぐらいになるはずだが、実際はnanoからはR+145程度のようだ。
おそらく静止探索1手詰めで強くなっているように見えたのが0.5手延長で強くなるように見えるのと同じ現象で、まやかし。
・local-game-serverでmainスレッド以外がエンジン名を設定しているの危ないので修正。
■ 2016/02/19 V1.55
・nano-plusに静止探索でのみ1手詰めを呼び出すようにした。-R20(long effectの更新分)+R70(1手詰めの効果) = +R50(nanoから)
■ 2016/02/19 V1.54c
・nano-plusで静止探索での1手詰め
{
// 1手詰み
Move m;
if (PvNode && param1)
m = pos.mate1ply();
else
m = MOVE_NONE;
if (m != MOVE_NONE)
return mate_in(ss->ply);
}
・通常探索での一手詰め判定
Move bestMove = MOVE_NONE;
// RootNodeでは1手詰め判定、ややこしくなるのでやらない。
// 置換表にhitしたときも1手詰め判定は行われていると思われるのでこの場合もはしょる
if (!RootNode && !ttHit && (PvNode && param2))
{
bestMove = pos.mate1ply();
if (bestMove != MOVE_NONE)
{
// 1手詰めスコアなので確実にvalue > alphaなはず。
alpha = mate_in(ss->ply);
goto TT_SAVE;
}
}
50.6% 48.7%
56.5% 54.2%
#1
やねうら王nano V140
やねうら王nanoの最終版1スレッド、0.1秒設定
#7
やねうら王nano plus V154c
やねうら王nano plus、1手詰め呼び出し条件の実験,1スレッド、0.1秒設定
2948-0-2876(17.3% R4.3) 2834-0-2990(98.0% R-9.3)
3292-0-2532(0.0% R45.6) 3101-0-2616(0.0% R29.5)
静止探索では無条件で1手詰めを呼ぶのがよさげ。
自己対戦だと0.5手延長みたくなって、勝率が上がっているだけかも知れないが。
・1.54d
// RootNodeでは1手詰め判定、ややこしくなるのでやらない。
// 置換表にhitしたときも1手詰め判定は行われていると思われるのでこの場合もはしょる
if (!RootNode && !ttHit & param1)
{
bestMove = pos.mate1ply();
if (bestMove != MOVE_NONE)
{
// 1手詰めスコアなので確実にvalue > alphaなはず。
alpha = mate_in(ss->ply);
goto TT_SAVE;
}
}
42.0% 54.4%
#1
やねうら王nano V140
やねうら王nanoの最終版1スレッド、0.1秒設定
#8
やねうら王nano plus V154d
やねうら王nano plus、通常探索で1手詰め呼び出すか,1スレッド、0.1秒設定
1397-0-1931(100.0% R-56.2) 1710-0-1432(0.0% R30.8)
→ 呼び出さないほうが強いようだ。
■ 2016/02/18 V1.54
・local server、結果を1行ずつ出力するモード用意。
・local server、finish時に子プロセスのエンジン開放するためにquitコマンドを送信するように変更。
・nano-plusでの実験用にoptionとしてParam1,Param2追加。
■ 2016/02/18 V1.53
・mate1で漏れているケースがあったので修正。
sfen p2g3n1/2gn4g/+P1s1k3s/1ppr2+Lbp/1P1p1K2b/4P1Ppl/3+n1P1RP/LS3p1PL/3P+p2NS w Ppg 160
test rp
Random Player test , loop_max = 100000000
mate found = 10000 , mate miss = 746 , mate found rate = 93.0579%
mate found = 20000 , mate miss = 1460 , mate found rate = 93.1966%
mate found = 30000 , mate miss = 2181 , mate found rate = 93.2227%
mate found = 40000 , mate miss = 2939 , mate found rate = 93.1554%
mate found = 50000 , mate miss = 3759 , mate found rate = 93.0077%
mate found = 60000 , mate miss = 4617 , mate found rate = 92.8548%
mate found = 70000 , mate miss = 5387 , mate found rate = 92.8542%
mate found = 80000 , mate miss = 6204 , mate found rate = 92.8031%
mate found = 90000 , mate miss = 6882 , mate found rate = 92.8965%
mate found = 100000 , mate miss = 7561 , mate found rate = 92.9705%
mate found = 110000 , mate miss = 8327 , mate found rate = 92.9627%
→ 0.2%ほど詰み発見率が上がった。
■ 2016/02/18 V1.52
Position.cppで評価関数を使わないときに
#ifndef EVAL_NO_USE
で囲み忘れていたところがあったので修正。
■ 2016/02/11 V1.51
・コマンドライン引数の複数コマンドの実行機能を追加。fileからの実行機能も追加。
■ 2016/02/10 V1.50
・自己対局サーバー、1スレッド×同時対局(マルチスレッド)に対応させる。goコマンドがThreads数を反映するように。
→ マルチスレッド化した。
■ 2016/02/09 V1.49
・スレッドまわり改修して、協力詰めエンジンがコンパイル通らなくなっていたの修正。
MainThread::searchがvirtualなので単にsearchって書くとthink()が呼び出されてしまうので注意。
次のように書く必要がある。
void MainThread::think() {
for (auto th : Threads.slaves) th->start_searching();
Thread::search();
for (auto th : Threads.slaves) th->wait_for_search_finished();
}
void Thread::search() { HelpMate::id_loop(rootPos, (int)thread_id(), (int)Options["Threads"]); }
■ 2016/02/09 V1.48
・Threadまわり全面的に書き直す。
→ 大改修したら落ちなくなった。やはりそうだったのか…。
→ スレッドまわりがすっきりして気分がいい。
・nanoとminiとビルドしなおしてローカル自己対局。
→ 直ってる気がする。そうか。スレッドまわりだったのか…。
・自己対局のときにコマンドラインではなくファイルから開始コマンドを受け取りたいのでusi.cppを改良。
引数で指定されたものを連結して一つのコマンドとして実行する機能があればいいのか…そうか。
次のような.batファイルを作ってそれを実行すれば連続自己対局が簡単に開始できる。
> local-game-server.exe go btime 500
・解説.txtの説明が古かったので刷新。
・スレッドまわり大改修したのでexeフォルダのnanoのバイナリ差し替え。
・shogi.hからマクロ関係をextra/macros.hに移動。
■ 2016/02/09 V1.47
・あかん。__mm_mallocが失敗する状況において、newも失敗する。これランタイムおかしいのでは…。
revertする。
・Releaseビルド時のランタイムなら落ちない。Debugビルド時のnewでまわり、高負荷時にかち合うと失敗するのでは。
main threadのnewをするタイミングが早すぎてランタイムの初期化が終わっていないことがあるのでは…。
→ main threadのnewは、ThreadPool::init()のなかが最初。これは、main関数のなかのThreads.init()から
呼び出される。ということは、問題なさげ。
そもそも、sizeof(MainThread)==1312しかないのに。
// Tの基底クラスはstd::threadなのでスライシングされて正しく代入されるはず。
*th = std::thread([&] {((T*)th)->idle_loop(); });
// →どうもMSVCのデバッグ用ランタイム、これやるとatomic_boolとかの実装と相まってまずいようだ。
■ 2016/02/09 V1.46
・自動対局サーバー、ときどき3つ目ぐらいのインスタンス走らへん。原因調査。
・自己対局サーバーに子プロセスとの通信ログ出力機能追加。
・Position::material、EVAL_NO_USEのときに参照している箇所があったのでifdefで囲んだ。
・デバッガで再現しない。また、local game server自体が落ちることがある。原因調査。
→ どうも負荷状態において _mm_malloc()が失敗して未初期化のポインターが返ってきているような感じなのだが…。
→ ランタイムが何か共有してて、同時起動時において初期化がされないのではないかな。MSVC、ひどい実装だな。
マルチスレッドデバッグDLLに何かバグがある予感。
→ VSからCtrl+F5連打でこの現象が起きる。
→ _mm_malloc()自前で実装する。
// --------------------
// __mm_malloc(),__mm_free()
// --------------------
// MSVCの__mm_malloc(),__mm_free()が高負荷状態において失敗するので自前で用意。
// 速度的には遅いがそんなに急所でこの関数を呼び出すわけではないので構わない。
// size = 要求メモリ量(byte単位)、align_size = アライメントするサイズ
inline void* my_mm_malloc(size_t size, size_t align_size)
{
const auto ptr_alloc = sizeof(void*); // この分余分に確保して[-1]のところに元のポインターを保存しておく。
size_t request_size = size + align_size;
const auto needed = ptr_alloc + request_size;
auto alloc = ::operator new(needed);
void* alloc2 = (uint8_t*)alloc + ptr_alloc;
auto ptr = std::align(align_size, size, alloc2, request_size);
((void**)ptr)[-1] = alloc;
return ptr;
}
inline void my_mm_free(void* ptr)
{
if (ptr)
{
void* alloc = ((void**)ptr)[-1];
::operator delete(alloc);
}
}
■ 2016/02/09 V1.45
・1手詰め見つけたときにスコアおかしいな。
mate distance pruning入れないと駄目なのか
→ 入れたらなおった..よしよし。
・nano plusにnode stackを導入する。
・nanoとnano plusでbenchでの探索node数が合致するようにする。
nano
===========================
Total time (ms) : 13332
Nodes searched : 13282757
Nodes/second : 996306
nano plus、1手詰めなし、mate distance pruningなし。
===========================
Total time (ms) : 11896
Nodes searched : 10584735
Nodes/second : 889772
→ 合致しない。ソース比較する。
MovePickerが原因としか考えられない。うわー。
MovePicker nanoにものと差し替えたらnode数合致した。
===========================
Total time (ms) : 14328
Nodes searched : 13282757
Nodes/second : 927048
LONG_EFFECTの更新で7%ぐらい遅くなってるのか..これで利きを使わない評価関数だとだいぶ損だな。
ああ、MovePicker、ttMoveと先頭のをswapするのでオーダリング違うのか。そうか。
===========================
Total time (ms) : 11129
Nodes searched : 10584735
Nodes/second : 951094
LONG_EFFECT更新なしにして7%ぐらい上がった。
MovePickerで段階生成にしてるので4%ほど損してるのか。
いまの状況だとほぼall nodeになるので仕方ないか。
・nano plusにkiller move実装したら枝刈り性能あがった気がする。
===========================
Total time (ms) : 3863
Nodes searched : 4850357
Nodes/second : 1255593
bench d 時のdepth上げる。
===========================
Total time (ms) : 12855
Nodes searched : 13773887
Nodes/second : 1071480
・nanoと対局させる。
nano VS nano plus
62-0-38
46-1-53
48-0-52
166-3-131
161-4-135
---------
483/892=0.54
killerで枝刈り効率が上がっているはずだが、LONG_EFFECTの更新の7%と
MovePickerの逐次化による5%ほどとが回収できてないのか…。大変だな。
■ 2016/02/09 V1.44
・benchコマンド追加。
・MAX_DEPTH、設計良くないな。削除。
・これに伴い、nano,nano plusのid_loop、修正。
・benchコマンド完成。
→ nano plusのベンチマーク、異常に悪い件。
===========================
Total time (ms) : 14419
Nodes searched : 11172282
Nodes/second : 774830
・比較用にnanoもベンチが通るように修正する。
nano plusへの修正をbackport
nanoのほう
===========================
Total time (ms) : 13476
Nodes searched : 13282757
Nodes/second : 985660
・nano/nano plusのconfigure、testコマンド、デフォルト有効にしておく。
・nano plus ASSERTなしでbench
===========================
Total time (ms) : 12411
Nodes searched : 11172282
Nodes/second : 900191
めっちゃ変わった。どのASSERTがそんなに重いというのか..わからん。
MATE1外してみる。
===========================
Total time (ms) : 12257
Nodes searched : 10584735
Nodes/second : 863566
探索木変わったのでむしろ増えた。
mate1外してnanoと探索ノード数が同じでないの、おかしい。あとで原因調べる。
mate1、non PVでも有効にして、ASSERTなしにして、nanoと対戦させておく。
non PVでもmate1入れるとnps増えた。mate1で枝刈りされて無駄な指し手生成が端折られたからか?
===========================
Total time (ms) : 5016
Nodes searched : 5955513
Nodes/second : 1187303
nano-nano plus
112-4-84
103-3-94
107-0-93
少しの負け越しで済んだが、やはり何かおかしいな。
benchの探索node数が同じにならないのはバグだろうから、調査する。
■ 2016/02/08 V1.43
・nano plusのMovePickerで段階的な指し手生成を実装。
→ やってみたがnpsほぼほぼ上がってない。(気がする。)
mate1入れたせいもあるのか。
・1手詰め、うまく詰ませられない。
position startpos moves 1g1f 8c8d 7g7f 8d8e 8h7g 7a6b 6g6f 5a4b 2h8h 5c5d 7i7h 4b3b 3i3h 6b5c 5i4h 3c3d 3g3f 5c4d 7h6g 5d5e 4g4f 6a5b 6i5h 7c7d 5h4g 9c9d 1f1e 2b3c 2i3g 8a7c 4h3i 9d9e 3i2h 3c4b 2g2f 8b8d 6f6e 7c6e 7g6f 8d8a 5g5f 5e5f 6g5f 6c6d 4f4e 4d3c P*5d 5b6c 5f5e 3b2b 3g2e 4a3b 3f3e 3d3e 8h5h 8e8f 5e4f 8f8g+ 2e3c 4b3c 6f3c+ 3b3c 5h5i P*5g B*7b 8a8f 7b6c+ 8g7g 6c6d 8f8h+ 6d6e 7g6h 5i5g 8h8i N*2e 3c3b 6e5e N*3c P*3d N*4b 4f3e 8i7i 5d5c+ B*7h 3d3c+ 2a3c 2e3c+ 3b3c N*2e P*3b 5c4c N*3d 4c3c 3b3c 2e3c+ 2b2a G*2b 3a2b
go btime 0 wtime 0 byoyomi 30000000
→ 修正した。
・nano-nono plus
59-1-40
60-1-39
47-2-51
55-5-40
0.56
枝刈りが甘い状況ではmate1にそんなに価値がないのかも。
PV nodeでだけ呼び出すか。
→ 1手詰め判定は通常探索、静止探索ともにPV nodeのみに変更。
もう寝るのでこの条件で2000回対戦させておく。
318-4-178
315-11-174
332-5-163
330-8-162
---------
1295-28-677
0.656
めっちゃ負けてる。おかしい。差分取る。
→ mate1は軽いのでnon PVでも入れたほうがいいということか。
→ MovePickerで遅くなった分、回収できていないのか。
→ bench書く。
・自動対戦サーバー、ときどき3つ目ぐらいのインスタンス走らへん。あとで原因調べる。
■ 2016/02/08 V1.42
・nano plus、1手詰め判定追加。
87-4-109 R35ほどup?大したことないな。枝刈りが甘いからmate見つけてもリターンが小さいんだな。
・config.h、デフォルトではdefineしないことに。
・add_hand(),sub_hand()、inlineにしていると内部コンパイルエラーになるときがあるのでshogi.cppのほうで定義するように変更。
・Depth自体は32bitでいいのでは..
■ 2016/02/08 V1.41
・materialの計算もifndef EVAL_NO_USE内に分離
・clangでコンパイルが通るように。
http://llvm.org/releases/download.html
> Download LLVM 3.7.1
> Clang for Windows (64-bit) (.sig)
LLVM-3.7.1でコンパイルが通るように頑張る。
→ ClangだとAVX関係が色々難しいみたい。gccならいけそうだが…。
gccでコンパイル通すのはまた今度にする。
・これコメントアウト
/*
// 静止探索時の最大探索深さ
const int MAX_QUIET_PLY = 6;
// 通常探索時の最大手数である128に、静止探索時の最大深さを加えた定数。
// 局面バッファ(StateInfo)などは、すべてこのサイズで確保する。
const int MAX_SEARCH_PLY = MAX_PLY + MAX_QUIET_PLY;
*/
・DEPTH_MAXが必要なので修正。
■ 2016/02/08 V1.40
・実行ファイルを配布するにあたって、定跡ファイルを移動させて、評価関数バイナリの置き場を変更する。
将来的に評価関数バイナリを切り替えられるようにする。また、将来的に定跡を複数から選択可能にする。
eval/kpp16ap.bin
eval/kkp32ap.bin
book/standard_book.db
→ exe/YaneuraOu-nano-readme.txtに詳しく書いた。
・やねうら王nano plusの開発開始。
engine/nano-plus-engine追加。
■ 2016/02/07 V1.39
・やねうら王nanoの探索部、少し改良
→ nonPV用の処理を少し書く。
→ そこそこうまく書けた気がする。floodgateに投入しておく。
これでR2000ぐらいになっているならnanoの開発はこれにて終了。
■ 2016/02/07 V1.38
・差分計算時のテスト
isready
position startpos moves 7g7f 8b3b 5i6h 5a6b 2g2f 6b7b 2f2e 3c3d 3i4h 3d3e 8h2b+ 3a2b 2e2d 2c2d 7i7h 5c5d 7h7g 2b2c B*6f B*2b 6f2b+ 3b2b 6h7h 2c3d 4g4f 2d2e 4h4g 2e2f B*6f B*3c 6f3c+ 2a3c 4i3h B*4i B*5f 3d2e 4g5h 4i5h+ 6i5h S*5e B*1e 4a3b 5f4g 5e4f 4g5f 5d5e
go btime 10000000
info depth 8 score cp -1502 nodes 16874114 nps 1063204 hashfull 420 time 15871 pv 5f6e 1c1d 1e3c+ 3b3c 3g3f B*4i 5h6h 2e3f
// 差分計算なし。
info depth 8 score cp -1502 nodes 16874114 nps 896414 hashfull 420 time 18824 pv 5f6e 1c1d 1e3c+ 3b3c 3g3f B*4i 5h6h 2e3f
17%ぐらいnps up!!
計算合った。これで良し。
・EVAL_KPP、差分計算、実装完了。
・read_book()、デバッグ中だったの戻した。
・DirtyPiece型導入。
・StateInfoからkingSquare除く。
■ 2016/02/07 V1.37
・Eval::compute_eval()で全計算して初期化する。
・差分で遡るの1局面前までに限定する。
・差分計算デバッグ中。
・README.md、整形
■ 2016/02/07 V1.36
・KPP評価関数の差分計算まわり。
・StateInfoにdirtyPiece追加。
・Eval/evaluate_kpp分離
・Eval/evaluate_bona_piece分離
・shogi.hのほうに
int hand_count(Hand hand, Piece pr) { ASSERT_LV2(PIECE_HAND_ZERO <= pr && pr < PIECE_HAND_NB); return (hand >> PIECE_BITS[pr]) & PIECE_BIT_MASK[pr]; }
int hand_exists(Hand hand, Piece pr) { ASSERT_LV2(PIECE_HAND_ZERO <= pr && pr < PIECE_HAND_NB); return hand & PIECE_BIT_MASK2[pr]; }
を書くと内部コンパイルエラーになるのでshogi.cppのほうに移動。
・EVAL_KPPのevaluateに差分計算追加。
・kingSquare、StateInfoに移動させる。
■ 2016/02/06 V1.35
・nanoのid_loopまわり、ちょっと整理した。
■ 2016/02/06 V1.34
・定跡DBの読み書き、std::mapではなくstd::unorder_mapを使うように変更。
■ 2016/02/05 V1.33
・定跡ファイルに定跡フォーマットのバージョン識別文字列を追加。
■ 2016/02/05 V1.32
・定跡にその指し手が採択された回数の項目を追加。
・nanoで定跡の指し手に関して、採択確率を出力するようにした。(将棋所ではこれでうまく表示される)
■ 2016/02/05 V1.31
・extra/book.hとcpp追加。
・test_cmd.cppから移動。
・bookの読み込み、書き込み等の操作を細かくして追加。
・read_all_lines()でエラーのときに1を返すように。
・nanoの定跡にbook.dbを用いるように変更した。
■ 2016/02/05 V1.30
・定跡部、何かフレームワークからのサポートを考える。
→ 考えた。解説に書いた。nano以外ではこれを使うことにする。
・read_all_lines()、空行はskipするように。
・makebookコマンド、sfen→db変換実装した。
・doc/nano-book.db削除。
・doc/book.db追加。
■ 2016/02/05 V1.29
・nanoの秒読み時の使用時間、もう少し少なくしないとtime upになるので修正。
・USIオプションに"NetworkDelay"追加。
・YaneuraOuMini_ja.txt → YaneuraOu_ja.txtにリネーム
バイナリは全部YaneuraOu.exeでいいや。
■ 2016/02/04 V1.28
・nano、floodgateに放流している人を見るとR1700ぐらいらしい。もう少しチューンする。
・nanoの静止探索で王手がかかっているならalpha = -VALUE_INFINITEにして、
あと静止探索の延長は3手までにする。
→ 少し強くなった気が。
・nanoの静止探索の指し手生成、RECAPTURESからCAPTURES_PRO_PLUSに変更してみる。
→ 弱くなった。
・Position::is_ok()にcheckesの検証を追加。
・CAPTURES_PRO_PLUSで歩の成りに自駒のある場所を除外していなかったのを修正。
position startpos moves 2g2f 3c3d 7g7f 8c8d 2f2e 1c1d 2e2d 2c2d 2h2d
go btime 169000 wtime 17100000 byoyomi 0
・検証用のコード
for (auto p = currentMoves; p != endMoves; ++p)
if (!pos.pseudo_legal(*p))
{
cout << pos << *p;
for (auto m : MoveList<CAPTURES_PRO_PLUS>(pos))
cout << m.move << " ";
}
・nanoに定跡追加。
→ 序盤、少しだけマシになった。
・misc.h/cppにread_all_lines()追加。
・プロジェクトのdoc/nano-book.sfen追加。
・対局中おかしかった局面のテスト
position startpos moves 7g7f 8b3b 5i6h 5a6b 2g2f 6b7b 2f2e 3c3d 3i4h 3d3e 8h2b+ 3a2b 2e2d 2c2d 7i7h 5c5d 7h7g 2b2c B*6f B*2b 6f2b+ 3b2b 6h7h 2c3d 4g4f 2d2e 4h4g 2e2f B*6f B*3c 6f3c+ 2a3c 4i3h B*4i B*5f 3d2e 4g5h 4i5h+ 6i5h S*5e B*1e 4a3b 5f4g 5e4f 4g5f 5d5e
go btime 10000000
・nanoの通常探索の指し手生成、CAPTURESさきに生成すると枝刈り性能が上がるはず。→ 少し強くなった。
・あと探索の並列化と評価関数の差分更新をやるとR200ぐらい上がるかも。
・2016年1月の作業メモから完了分
【完了】・1手詰め判定ルーチン、影の利きを考慮した詰み
【完成】・1手詰め判定ルーチン、打ちと移動による簡単な詰み
【完成】・undo_move()で利きの差分更新処理(戻す処理)、実装完了。ランダムプレイヤーによる自動テストをpassした。
【完成】・do_move()での利きの差分更新処理が正しいかをランダムプレイヤーによる自動テストにより確認。
【完成】・Position::do_move()のときのcaptureとnon_captureのときの利きの差分更新処理
【完成】・Position::do_move()のdropのときの利きの差分更新処理
【完成】・Long Effect Library
【完成】・利きの初期化処理
【完成】・自動対局サーバーの開始局面のランダマイズ機能
【完成】・自動対局サーバー機能、書けた。
【完成】・32bit環境用のコード、ちゃんと動くようになった。(手元に32bit環境がないので実際の環境で試してはいない。)
■ 2016/02/01 V1.27
・mate1plyで漏れているケースをいくつか修正。
sfen 1nk3G2/l4+RGb1/s1p5l/n2p3pp/1p1PP4/4KPPP1/NPP1S3P/LR3ppGL/B2+p+n1S2 b 2PSG 123
→詰むようになった。0.1%ほど詰み発見率が上がった。
sfen +P1+Lg1S+P1b/+P2k4p/1N1l1+R2n/1LG1Gp2L/S5p2/1PPP1g1p1/B3R3n/pp2+n1KsP/1S4P2 b 2P2p 203
→詰むようにした。0.2%ほど詰み発見率が上がった。
・USI拡張コマンドとして"mate1"コマンド追加。
test rp
Random Player test , loop_max = 100000000
mate found = 10000 , mate miss = 793 , mate found rate = 92.6526%
mate found = 20000 , mate miss = 1524 , mate found rate = 92.9195%
mate found = 30000 , mate miss = 2257 , mate found rate = 93.0031%
mate found = 40000 , mate miss = 3035 , mate found rate = 92.9476%
mate found = 50000 , mate miss = 3877 , mate found rate = 92.804%
mate found = 60000 , mate miss = 4764 , mate found rate = 92.6441%
mate found = 70000 , mate miss = 5544 , mate found rate = 92.6612%
mate found = 80000 , mate miss = 6376 , mate found rate = 92.6183%
mate found = 90000 , mate miss = 7079 , mate found rate = 92.708%
mate found = 100000 , mate miss = 7795 , mate found rate = 92.7687%
mate found = 110000 , mate miss = 8561 , mate found rate = 92.7792%
mate found = 120000 , mate miss = 9318 , mate found rate = 92.7945%
■ 2016/02/01 V1.26
・static const排除。実行ファイルのサイズが20KBほど縮んだ。
悪い影響はなさそうなのでこれでいく。
・Recaptureの指し手生成器、作る。
・movegenの指し手生成、選択式のするのやめる。どうせ呼び出していなければリンカーで削除される。
・NON_EVASIONS_ALL追加。
→ 呼びださなければ実行ファイル、1バイトも増えない。よしよし。
・nanoの静止探索、RECAPTURESを使って書き換え。
■ 2016/01/31 V1.25
・nanoの静止探索、standPatと比較するの忘れてた。修正。
→ 修正したら少し強くなった感。
■ 2016/01/31 V1.24
・評価値、局面の差分更新をしたときにおかしくなるので、駒番号まわりのテストコード追加する。
→ 難しい。書きにくい。
・BonaPieceの文字列での出力関数実装
・evalstatにPieceListの内容を表示、追加。
・test rpコマンドのランダムプレイヤーに評価値の差分計算のチェック機構追加。
・undo_move()で駒番号おかしくなっていたの修正。
・mateのときの手数表示がおかしいの修正。
■ 2016/01/31 V1.23
・nanoのデバッグ進める。
・USI::score_to_usi()追加
・USI::pv()追加。
・評価関数の値がおかしい気がしなくもない。
・sfenコマンド追加。(以前のものを変更)
■ 2016/01/31 V1.22
・nanoにはsee使わない。
・nanoの静止探索書く。
・nanoにid_loop導入。
・TanspositionTableにvalue_to_tt()とか追加する。
・goコマンドのデフォルトを秒読み1秒にしておく。(テストしにくいので)
・USI::Optionのコンストラクタで、on_changeのイベントハンドラを呼び出すように変更。
→ この設計だと駄目なのか。仕方ないので置換表のコンストラクタでデフォルト16MB確保する。
・USI::pv()追加。読み筋表示用。
■ 2016/01/30 V1.21
・Position::sse()追加。
・extra/see.cpp追加。
・USE_SEE追加。
■ 2016/01/29 V1.20
・評価関数、旧バージョンと値の比較。
・EvalList::set_piece修正。
position sfen lnsgkgsnl/1r5b1/pppppppp1/9/9/2P5p/PP1PPPPP1/LB5R1/1NSGKGSNL w p 8
■ 2016/01/27 V1.19
・やねうら王nanoとminiの探索部書いていく。
・評価関数のimportしてくるところから。
→ だいたい出来た気がする
・put_pieceで落ちる。
→ 王手がかかっているのにEVASIONS呼び出さなかったからか。
> position startpos moves 3i4h 3c3d
> position startpos moves 7g7f 3c3d 8h2b
evalおかしい。何これ。
■ 2016/01/27 V1.18
・Bitobardのoperator == () がまさかの高速化。これ、そもそもほとんど使ってないのであまり変わらんが…。
■ 2016/01/25 V1.17
・ByteBoard、WordBoard、無理やり取ってくるなら端にpaddingしといたほうが無難か…。
■ 2016/01/24 V1.16
・1手詰めに影の利きを考慮した詰みも追加。
・1手詰めで漏れているケースもう少し追加する。
・uint8_t -> u8とかtypedefする
・24近傍の9近傍への長い利きを回収するコード追加。
・mate1plyの移動による詰みをlambdaに変更。
・1手詰め判定で影の利き考慮するようにした。
test rp
Random Player test , loop_max = 100000000
mate found = 10000 , mate miss = 827 , mate found rate = 92.3617%
mate found = 20000 , mate miss = 1590 , mate found rate = 92.6355%
mate found = 30000 , mate miss = 2354 , mate found rate = 92.7242%
mate found = 40000 , mate miss = 3190 , mate found rate = 92.614%
mate found = 50000 , mate miss = 4072 , mate found rate = 92.4693%
mate found = 60000 , mate miss = 5015 , mate found rate = 92.2864%
mate found = 70000 , mate miss = 5822 , mate found rate = 92.3215%
mate found = 80000 , mate miss = 6704 , mate found rate = 92.2679%
mate found = 90000 , mate miss = 7435 , mate found rate = 92.3693%
mate found = 100000 , mate miss = 8202 , mate found rate = 92.4197%
mate found = 110000 , mate miss = 8984 , mate found rate = 92.4494%
詰み率 92%ちょいぐらいになった。8%ぐらいが影の利きありでの1手詰めなのか。
ランダムプレイヤーで数時間まわしておく。
→ 1.6億局面をpassしたのでうまく動いてるやろ…。
■ 2016/01/23 V1.15
・dirs_bw_of()→long_effect_ofとリネーム
・mate1plyの判定率、ランダムプレイヤーで計測できるようにした。
Random Player test , loop_max = 100000000
mate found = 10000 , mate miss = 28848 , mate found rate = 25.7414%
mate found = 20000 , mate miss = 58089 , mate found rate = 25.6118%
mate found = 30000 , mate miss = 87252 , mate found rate = 25.5859%
mate found = 40000 , mate miss = 116252 , mate found rate = 25.5997%
mate found = 50000 , mate miss = 146594 , mate found rate = 25.4331%
mate found = 60000 , mate miss = 176384 , mate found rate = 25.3824%
mate found = 70000 , mate miss = 206668 , mate found rate = 25.3011%
mate found = 80000 , mate miss = 237090 , mate found rate = 25.2294%
→ おかしい。低すぎ。
・移動による詰み、駒打ち用のdirectionsテーブルではまずいのか…。修正した。
test rp
Random Player test , loop_max = 100000000
mate found = 10000 , mate miss = 1590 , mate found rate = 86.2813%
mate found = 20000 , mate miss = 3134 , mate found rate = 86.4528%
mate found = 30000 , mate miss = 4722 , mate found rate = 86.4006%
mate found = 40000 , mate miss = 6296 , mate found rate = 86.4006%
mate found = 50000 , mate miss = 7953 , mate found rate = 86.2768%
mate found = 60000 , mate miss = 9620 , mate found rate = 86.1821%
mate found = 70000 , mate miss = 11028 , mate found rate = 86.3899%
mate found = 80000 , mate miss = 12651 , mate found rate = 86.3455%
mate found = 90000 , mate miss = 14175 , mate found rate = 86.3931%
mate found = 100000 , mate miss = 15725 , mate found rate = 86.4118%
→ だいぶ上がった。もう少し上がって欲しい気が。
■ 2016/01/23 V1.14
・do_move()に関するベンチが要るな。
test rpbenchコマンド追加。書けた。4600 games/sec程度。
1局が大抵256手まで行くことを考えると256×4600回の指し手生成 + do_move()/undo_move()だから妥当なところ?
ASSERT、long_effectオフにしたら6327 gps
long_effectだけオフにしたら5909gps
ASSERTだけオフにしたら4959 gps。
・ASSERTで5%ほど低下。long_effectは探索部と評価関数がなしだとすると30%ぐらい低下ということなのかな。
・Effect8に各駒の利き追加する
・1手詰め作っていく。
・UnitTestにMate1Ply関連のテストコード追加。
・HAND_KIND_ZERO追加。
・PRO_GOLD→QUEENに変更してeffects_fromにQUEEN追加。
・effects_fromにNO_PIECEのときの処理追加。
・駒打ちによる1手詰め判定できるようになった。
・桂の移動による1手詰め判定できるようになった。
・銀の移動による1手詰め判定うまく動いた。
・ランダムプレイヤーで1手詰め判定の自動テストするコードを追加。
・pseudo_legal()で金の成る手のチェックが抜けていたのを修正。
・1手詰めでの大駒による長い利きの遮断修正。
・1手詰めで桂打ちで利きを遮断するケース考慮。
・ランダムプレイヤーでランニング。動いているようだ。
■ 2016/01/22 V1.13
・undo_move()で戻す処理に利きを戻す処理も書くことにする。たぶん、そんなに遅くないはずで…。
・undo_move()も先後分けた。
・LongEffectLibraryに利きの更新の逆変換関数追加。
・ランダムプレイヤーで利きのrevertのテスト。
このまましばらくランニングさせておく。
・関数の名前revertでなくrewindにしよう。
・Position::set_effect、LongEffect::に移動。
■ 2016/01/22 V1.12
・captureとnon_captureのときの利きの更新処理追加。
→ これで利きの更新処理は一通り書けた。あとは…
・ランダムプレイヤーによる利きの更新の自動テスト追加。
・UNREACHABLE、ASSERT_LV3に変更。
・undo_moveで利きを巻き戻す作業がいるのか..これは難しい..
・LSB32/64にASSERT_LV3追加。
・利きのdo_move()での更新はこれで問題なさげ。undo_move()をどうするか考え中。
■ 2016/01/22 V1.11
・長い利き、WordBoardでないとまずいのか…。書き直し。
・make_piece()引数の順番変更。Colorをつねに先に。
・ENABLE_BIT_OPERATORS_ONに operator &= などを追加。
・WordBoardの表示修正。
・利きの初期化部、マクロいくつか削除。
・LongEffect::dir_bw_of()追加。
・Directionsのenumに定数追加。
・Position::do_move()のdropのときの利きの更新処理書けた。
あとはcaptureとnon_captureのときの利きの更新処理!
■ 2016/01/21 V1.10
・has_long_effect()追加。
・↑をUnitTestに追加。
・UPDATE_EFFECT_BY_PUTTING_PIECE、マクロ化した。(利きの差分更新のところでも使うため。)
・LONG_EFFECTにINCもDECも要らんかった。一つにまとめた。
・Direction削除。Effect8のものを持ってきて、これを使うことにする。
・SQWW_RIGHT→SQWW_Rとかにリネーム。
・Position::do_move()を内部的に、先後分ける。
・pop_lsb(uint8_t)追加。
・pop_directionsの引数変更。
・ENABLE_BIT_OPERATORS_ON追加。
・Directionsにbegin(),end()追加。
→ あかん。よくなかった。削除。
・pop_lsb()をbitop.hに移動。templateで書くことにした。
■ 2016/01/20 V1.09
・Effect8::directions_of()追加。
・長い利きの初期化コード書けた。→ 正しそう。
・ByteBoardの出力関数書いた。
・MAX_PLY_ → MAX_PLY_NUMにリネーム。
・LONG_EFFECT→LONG_EFFECT_LIBRARYにリネーム。
・long_effect.h/cpp、ifdef LONG_EFFECT_LIBRARYで囲った。
■ 2016/01/19 V1.08
・user.cpp、わかりにくいのでuser-engine.cppにリネーム。
・Positionクラスに利きを持たせる。
・利きの初期化コードおよび差分更新コードを追加する。
・Position::set_effect()書いた。
・評価関数、shogi.hで選択可能にする。(まずは準備だけ)
・config.h、書式整えた。
■ 2016/01/19 V1.07
・SquareWithWall追加。これを使って利き関係の初期化処理を書き直す。
・dist、これがあれば不要? → 不要ではなかった。
・LongEffectライブラリにSquareWithWallの差分値追加。
■ 2016/01/19 V1.06
・aligned_stack、内部的にvectorを使うように変更。
■ 2016/01/19 V1.05
・std::stack<StateInfo>を用いるときにpush()に対して内部的にstackがStateInfoをnewするのだが
これがalignmentされてなくてまずいのか…。そんな問題があるのか…。
→ StateInfoにcustom new/delete追加。
// custom allocator(このクラスはstd::stack<StateInfo>のpush()によって内部的にnewされるが、そのときに
// alignasが無視されるので、custom allocatorが必要になる…ようだ。)
static void* operator new (std::size_t count){ return _mm_malloc(count,alignof(StateInfo)); }
static void operator delete(void* p) { _mm_free(p); }
→ これでも駄目なのか。難しい…。
// C++11では、std::stack<StateInfo>がalignasを無視するために、代わりにstack相当のものを自作。
template <typename T> struct aligned_stack {
void push(const T& t) { auto ptr = (T*)_mm_malloc(sizeof(T), alignof(T)); *ptr = t; container.push(ptr); }
T& top() const { return *container.top(); }
~aligned_stack() { while (container.size()) { auto ptr = container.top(); _mm_free(ptr); container.pop(); } }
private:
std::stack<T*> container;
};
こうしてみた。
■ 2016/01/19 V1.04
・engine/mate-engine/ 追加。このあとコードを書いていく。
■ 2016/01/19 V1.03
・自動対局フレームワークの開始局面をランダマイズする機能追加。
→ 定跡を読み込めるようにした。
■ 2016/01/19 V1.02
・move_from_usi()に合法チェック追加。
・連続自動対局フレームワーク、一通り動くようになった。
→ 対局開始局面のrandomize出来たほうがいいので何か考える。
■ 2016/01/18 V1.01
・連続自己対戦サーバー用のProcessNegotiatorで入出力のリダイレクトは出来るようになった。
あとはこれを非同期入出力にして連続自己対局が出来るようにすればOk.
■ 2016/01/18 V1.00
・連続自己対戦サーバー機能追加作業開始。
engine/local-game-server
・"Version"がwindows.hの内部の文字列と衝突した。"ENGINE_VERSION"にリネーム。
・_mm_malloc()~_mm_free()を使うように変更。
■ 2016/01/18 V0.99
・bitop.hとkey128.hのコメント掃除。
■ 2016/01/18 V0.98
・128bit hash keyを用いるときにalignmentが合ってないエラーがでうるのを修正。
■ 2016/01/18 V0.97
・x86で正常動作するようになった。指し手生成とか半分ぐらいの速度しか出ないが…。
・aligned_allocをbitop.hに移動させた。
■ 2016/01/18 V0.96
・size_t、x86環境だと32bitなのか…。ランダムプレイヤー修正。
・ランダムプレイヤー、GitHubにpushするの忘れてたので追加。
■ 2016/01/18 V0.95
・x86用のコード、allocatorだけ追加しておく。
・USE_AVX2をコメントアウトしたときにコンパイルが通らなくなっていたの修正。
■ 2016/01/18 V0.94
・Stockfishの升の差分を表現するDELTA_Nとか読みにくくてカナワンので、SQ_UPとかに変更。
■ 2016/01/18 V0.93
・engine関係、ひとつのフォルダにまとめる
・ランダムプレイヤーをengineとして追加。
・とりあえず、ビルドのデフォルトをランダムプレイヤーにしておく。(やねうら王miniの探索部が書けたらそれをデフォルトに変更する)
・StateInfo,Positionクラスのアライメントの調整をしたせいか、指し手生成が少し速くなったようだ。指し手生成祭りの局面で5.4M回/s程度(Core i7 4771にて)
・PRNGクラス、少しメンバー追加した。
■ 2016/01/18 V0.92
・x86用にコード修正。コンパイルは通るようになったが、Bitboardの代入等で落ちる。(アライメント合ってないから?)
コンパイル時に、こんな警告。
> source\thread.cpp(15): warning C4316: 'MainThread': ヒープで割り当てられたオブジェクトが 16 にアラインメントされていない可能性があります
→ thread.cppのnewしているところでaligned_new<T>()みたいなものが必要っぽいのだが、これを修正しても
ランタイムで落ちるようだ。よくわからんので誰か助けて欲しい…。
・よく考えるとKey256を使う場合も_mm256_store_si256()が32byteでアライメントされていることを要求するから、
これと同じ問題があるのか…。誰も使ってないだろうからそっちはまあいいか…。
■ 2016/01/17 V0.91
・x86用のemulation code、各種追加。
■ 2016/01/17 V0.90
・GitHubにて公開。