From 2792338fe03055e429586c112a7782e56c75eac1 Mon Sep 17 00:00:00 2001 From: yaneurao Date: Thu, 19 Oct 2023 03:38:29 +0900 Subject: [PATCH] =?UTF-8?q?-=20history=20stats=E3=81=AB=E9=96=A2=E3=81=97?= =?UTF-8?q?=E3=81=A6=E6=B7=BB=E5=AD=97=E3=82=92Stockfish=E3=81=8B=E3=82=89?= =?UTF-8?q?=E5=85=A5=E3=82=8C=E6=9B=BF=E3=81=88=E3=81=A6=E3=81=84=E3=82=8B?= =?UTF-8?q?=E4=BB=B6=E3=80=81search.cpp=E3=81=AB=E3=82=B3=E3=83=A1?= =?UTF-8?q?=E3=83=B3=E3=83=88=E3=82=92=E3=81=8B=E3=81=AA=E3=82=8A=E8=BF=BD?= =?UTF-8?q?=E5=8A=A0=E3=81=97=E3=81=9F=E3=80=82=20=20=20-=20=E6=A3=8B?= =?UTF-8?q?=E5=8A=9B=E3=81=AB=E5=BD=B1=E9=9F=BF=E3=81=99=E3=82=8B=E5=A4=89?= =?UTF-8?q?=E6=9B=B4=E3=81=AF=E3=81=97=E3=81=A6=E3=81=AA=E3=81=84=E3=80=82?= =?UTF-8?q?(=E3=81=A4=E3=82=82=E3=82=8A)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yaneuraou-engine/yaneuraou-search.cpp | 95 +++++++++++++++++-- source/movepick.cpp | 17 ++++ source/movepick.h | 17 ++-- source/thread.cpp | 4 + source/thread.h | 2 +- 5 files changed, 119 insertions(+), 16 deletions(-) diff --git a/source/engine/yaneuraou-engine/yaneuraou-search.cpp b/source/engine/yaneuraou-engine/yaneuraou-search.cpp index 599bce1b4..e0a09d5a7 100644 --- a/source/engine/yaneuraou-engine/yaneuraou-search.cpp +++ b/source/engine/yaneuraou-engine/yaneuraou-search.cpp @@ -778,6 +778,10 @@ void search_thread_init(Thread* th, Stack* ss , Move pv[]) for (int i = 7; i > 0; --i) { (ss - i)->continuationHistory = &th->continuationHistory[0][0][SQ_ZERO][NO_PIECE]; // Use as a sentinel + // ↑continuationHistoryに関して + // Stockfishは、 [inCheck][capture][pc][sq]の順 + // やねうら王は、[inCheck][capture][sq][pc]の順 + // なので注意。 (ss - i)->staticEval = VALUE_NONE; } @@ -1619,6 +1623,11 @@ namespace { { int penalty = -stat_bonus(depth); thisThread->mainHistory[from_to(ttMove)][us] << penalty; + // ↑mainHistoryに関して + // Stockfishは [c][from_to]の順 + // やねうら王は[from_to][c]の順 + // なので注意。 + update_continuation_histories(ss, pos.moved_piece_after(ttMove), to_sq(ttMove), penalty); } } @@ -1840,6 +1849,10 @@ namespace { // この右辺の↑係数、調整すべきだろうけども、4 Eloのところ調整しても…みたいな意味はある。 thisThread->mainHistory[from_to((ss-1)->currentMove)][~us] << bonus; + // ↑mainHistoryに関して + // Stockfishは [c][from_to]の順 + // やねうら王は[from_to][c]の順 + // なので注意。 } // Set up the improvement variable, which is the difference between the current @@ -1913,6 +1926,11 @@ namespace { && !( !ttCapture && ttMove && thisThread->mainHistory[from_to(ttMove)][us] < 989)) + // ↑mainHistoryに関して + // Stockfishは [c][from_to]の順 + // やねうら王は[from_to][c]の順 + // なので注意。 + // 29462の根拠はよくわからないが、VALUE_TB_WIN_IN_MAX_PLY より少し小さい値にしたいようだ。 // そこまではfutility pruningで枝刈りして良いと言うことなのだろう。 @@ -1957,6 +1975,10 @@ namespace { // null moveなので、王手はかかっていなくて駒取りでもない。 // よって、continuationHistory[0(王手かかってない)][0(駒取りではない)][SQ_ZERO][NO_PIECE] ss->continuationHistory = &thisThread->continuationHistory[0][0][SQ_ZERO][NO_PIECE]; + // ↑continuationHistoryに関して + // Stockfishは、 [inCheck][capture][pc][sq]の順 + // やねうら王は、[inCheck][capture][sq][pc]の順 + // なので注意。 pos.do_null_move(st); @@ -2078,6 +2100,10 @@ namespace { [true ] // captureOrPromotion [to_sq(move) ] [pos.moved_piece_after(move)]; + // ↑continuationHistoryに関して + // Stockfishは、 [inCheck][capture][pc][sq]の順 + // やねうら王は、[inCheck][capture][sq][pc]の順 + // なので注意。 pos.do_move(move, st); @@ -2147,11 +2173,14 @@ namespace { nullptr , (ss - 4)->continuationHistory , nullptr , (ss - 6)->continuationHistory }; - // 直前の指し手で動かした(移動後の)駒 : やねうら王独自 - Piece prevPc = pos.piece_on(prevSq); - // 1手前の指し手(1手前のtoとPiece)に対応するよさげな応手を統計情報から取得。 - Move countermove = prevSq != SQ_NONE ? thisThread->counterMoves[prevSq][prevPc] : MOVE_NONE; + // 1手前がnull moveの時prevSq == SQ_NONEになるのでこのケースは除外する。 + Move countermove = prevSq != SQ_NONE ? thisThread->counterMoves[prevSq][pos.piece_on(prevSq)] : MOVE_NONE; + // ※ ↑counterMovesに関して + // Stockfishは [pc][to]の順 + // やねうら王は [to][pc]の順 + // なので注意。 + MovePicker mp(pos, ttMove, depth, &thisThread->mainHistory, &captureHistory, @@ -2328,14 +2357,20 @@ namespace { int history = (*contHist[0])[to_sq(move)][movedPiece] + (*contHist[1])[to_sq(move)][movedPiece] + (*contHist[3])[to_sq(move)][movedPiece]; - // contHist[][]はStockfishと逆順なので注意。 + // ↑contHistに関して + // Stockfishは、 [pc][sq]の順 + // やねうら王は、[sq][pc]の順 + // なので注意。 if (lmrDepth < PARAM_PRUNING_BY_HISTORY_DEPTH/*6*/ && history < -3875 * (depth - 1)) continue; history += 2 * thisThread->mainHistory[from_to(move)][ us]; - // mainHistory[][]もStockfishと逆順なので注意。 + // ↑mainHistoryに関して + // Stockfishは [c][from_to]の順 + // やねうら王は[from_to][c]の順 + // なので注意。 lmrDepth += history / 5793; lmrDepth = std::max(lmrDepth, -2); @@ -2526,6 +2561,10 @@ namespace { && move == ttMove && move == ss->killers[0] && (*contHist[0])[to_sq(move)][movedPiece] >= PARAM_QUIET_TT_EXTENSION /*4194*/) + // ↑contHistに関して + // Stockfishは、 [pc][sq]の順 + // やねうら王は、[sq][pc]の順 + // なので注意。 extension = 1; } @@ -2563,6 +2602,10 @@ namespace { [capture ] [to_sq(move)] [movedPiece ]; + // ↑continuationHistoryに関して + // Stockfishは、 [inCheck][capture][pc][sq]の順 + // やねうら王は、[inCheck][capture][sq][pc]の順 + // なので注意。 // ----------------------- // Step 16. Make the move @@ -2640,9 +2683,17 @@ namespace { // 【計測資料 11.】statScoreの計算でcontHist[3]も調べるかどうか。 // contHist[5]も/2とかで入れたほうが良いのでは…。誤差か…? ss->statScore = 2 * thisThread->mainHistory[from_to(move)][us] + // ↑mainHistoryに関して + // Stockfishは [c][from_to]の順 + // やねうら王は[from_to][c]の順 + // なので注意。 + (*contHist[0])[to_sq(move)][movedPiece] + (*contHist[1])[to_sq(move)][movedPiece] + (*contHist[3])[to_sq(move)][movedPiece] + // ↑contHistに関して + // Stockfishは、 [pc][sq]の順 + // やねうら王は、[sq][pc]の順 + // なので注意。 - 3848; // Decrease/increase reduction for moves with a good/bad history (~25 Elo) @@ -2981,6 +3032,10 @@ namespace { int bonus = (depth > 6) + (PvNode || cutNode) + (bestValue < alpha - PARAM_COUNTERMOVE_FAILLOW_MARGIN /*653*/) + ((ss-1)->moveCount > 11); update_continuation_histories(ss-1, pos.piece_on(prevSq), prevSq, stat_bonus(depth) * bonus); thisThread->mainHistory[from_to((ss-1)->currentMove)][~us] << stat_bonus(depth) * bonus / 2; + // ↑mainHistoryに関して + // Stockfishは [c][from_to]の順 + // やねうら王は[from_to][c]の順 + // なので注意。 } // 将棋ではtable probe使っていないのでmaxValue関係ない。 @@ -3475,6 +3530,10 @@ namespace { if ( !capture && (*contHist[0])[to_sq(move)][pos.moved_piece_after(move)] < 0 && (*contHist[1])[to_sq(move)][pos.moved_piece_after(move)] < 0) + // ↑contHistに関して + // Stockfishは、 [pc][sq]の順 + // やねうら王は、[sq][pc]の順 + // なので注意。 continue; @@ -3495,6 +3554,10 @@ namespace { [capture ] [to_sq(move) ] [pos.moved_piece_after(move)]; + // ↑continuationHistoryに関して + // Stockfishは、 [inCheck][capture][pc][sq]の順 + // やねうら王は、[inCheck][capture][sq][pc]の順 + // なので注意。 quietCheckEvasions += !capture && ss->inCheck; @@ -3705,7 +3768,10 @@ namespace { for (int i = 0; i < quietCount; ++i) { thisThread->mainHistory[from_to(quietsSearched[i])][us] << -bestMoveBonus; - // StockfishはmainHistory↑は、[Color][from_to]の順なので注意。 + // ↑mainHistoryに関して + // Stockfishは [c][from_to]の順 + // やねうら王は[from_to][c]の順 + // なので注意。 update_continuation_histories(ss, pos.moved_piece_after(quietsSearched[i]), to_sq(quietsSearched[i]), -bestMoveBonus); } @@ -3714,7 +3780,8 @@ namespace { // Increase stats for the best move in case it was a capture move captured = type_of(pos.piece_on(to_sq(bestMove))); captureHistory[to_sq(bestMove)][moved_piece][captured] << quietMoveBonus; - // ※ StockfishはcaptureHistory↑は[pc][to][captured]の順なので注意。 + // ※ StockfishはcaptureHistory↑は[pc][to][captured]の順 + // やねうら王は、 [to][pc][captured]の順なので注意。 } // Extra penalty for a quiet early move that was not a TT move or @@ -3758,6 +3825,10 @@ namespace { break; if (is_ok((ss - i)->currentMove)) (*(ss - i)->continuationHistory)[to][pc] << bonus; + // ↑continuationHistoryに関して + // Stockfishは、 [inCheck][capture][pc][sq]の順 + // やねうら王は、[inCheck][capture][sq][pc]の順 + // なので注意。 } } @@ -3784,6 +3855,10 @@ namespace { Thread* thisThread = pos.this_thread(); thisThread->mainHistory[from_to(move)][us] << bonus; + // ↑mainHistoryに関して + // Stockfishは [c][from_to]の順 + // やねうら王は[from_to][c]の順 + // なので注意。 update_continuation_histories(ss, pos.moved_piece_after(move), to_sq(move), bonus); // Update countermove history @@ -3792,6 +3867,10 @@ namespace { // 直前に移動させた升(その升に移動させた駒がある。今回の指し手はcaptureではないはずなので) Square prevSq = to_sq((ss - 1)->currentMove); thisThread->counterMoves[prevSq][pos.piece_on(prevSq)] = move; + // ※ ↑counterMovesに関して + // Stockfishは [pc][to]の順 + // やねうら王は [to][pc]の順 + // なので注意。 } } diff --git a/source/movepick.cpp b/source/movepick.cpp index 300fe43c4..2dc4ebce4 100644 --- a/source/movepick.cpp +++ b/source/movepick.cpp @@ -279,10 +279,19 @@ void MovePicker::score() PieceType moved_piece = type_of(pos.moved_piece_before(m)); m.value = (*mainHistory)[from_to(m)][pos.side_to_move()] + // ↑mainHistoryに関して + // Stockfishは [c][from_to]の順 + // やねうら王は[from_to][c]の順 + // なので注意。 + 2 * (*continuationHistory[0])[movedSq][movedPiece] + (*continuationHistory[1])[movedSq][movedPiece] + (*continuationHistory[3])[movedSq][movedPiece] + (*continuationHistory[5])[movedSq][movedPiece] + // ↑continuationHistoryに関して + // Stockfishは、 [pc][sq]の順 + // やねうら王は、[sq][pc]の順 + // なので注意。 + // 移動元の駒が安い駒で当たりになっている場合、移動させることでそれを回避できるなら価値を上げておく。 #if 0 + (threatened & from_sq(m) ? @@ -336,8 +345,16 @@ void MovePicker::score() else // 捕獲しない指し手に関してはhistoryの値の順番 m.value = (*mainHistory)[from_to(m)][pos.side_to_move()] + // ↑mainHistoryに関して + // Stockfishは [c][from_to]の順 + // やねうら王は[from_to][c]の順 + // なので注意。 + 2 * (*continuationHistory[0])[to_sq(m)][pos.moved_piece_after(m)] - (1 << 28); + // ↑continuationHistoryに関して + // Stockfishは、 [pc][sq]の順 + // やねうら王は、[sq][pc]の順 + // なので注意。 } } diff --git a/source/movepick.h b/source/movepick.h index 0112d088f..5a667650f 100644 --- a/source/movepick.h +++ b/source/movepick.h @@ -100,31 +100,32 @@ enum StatsType { NoCaptures, Captures }; /// (~11 elo) // ButterflyHistoryは、 現在の探索中にquietな指し手がどれくらい成功/失敗したかを記録し、 // reductionと指し手オーダリングの決定のために用いられる。 -// 添字は[from_to][color]の順。 // cf. http://chessprogramming.wikispaces.com/Butterfly+Boards // 簡単に言うと、fromの駒をtoに移動させることに対するhistory。 // やねうら王では、ここで用いられるfromは、駒打ちのときに特殊な値になっていて、盤上のfromとは区別される。 // そのため、(SQ_NB + 7)まで移動元がある。 // ※ Stockfishとは、添字の順番を入れ替えてあるので注意。 +// やねうら王では、添字は[from_to][color]の順。 using ButterflyHistory = Stats; /// CounterMoveHistory stores counter moves indexed by [piece][to] of the previous /// move, see www.chessprogramming.org/Countermove_Heuristic -// CounterMoveHistoryは、直前の指し手の[to][piece]によってindexされるcounter moves(応手)を格納する。 +// CounterMoveHistoryは、直前の指し手の[piece][to]によってindexされるcounter moves(応手)を格納する。 /// cf. http://chessprogramming.wikispaces.com/Countermove+Heuristic // ※ Stockfishとは、添字の順番を入れ替えてあるので注意。 +// やねうら王では、[to][piece]の順。 using CounterMoveHistory = Stats; /// CapturePieceToHistory is addressed by a move's [piece][to][captured piece type] -// CapturePieceToHistoryは、指し手の[to][piece][captured piece type]で示される。 -// ※ Stockfishとは、添字の順番を変更してあるので注意。 -// Stockfishでは、[piece][to][captured piece type]の順。 +// CapturePieceToHistoryは、指し手の [piece][to][captured piece type]で示される。 +// ※ やねうら王ではStockfishとは、添字の順番を変更してあるので注意。 +// やねうら王では、[to][piece][captured piece type]の順。 using CapturePieceToHistory = Stats; /// PieceToHistory is like ButterflyHistory but is addressed by a move's [piece][to] -/// PieceToHistoryは、ButterflyHistoryに似たものだが、指し手の[to][piece]で示される。 +/// PieceToHistoryは、ButterflyHistoryに似たものだが、指し手の[piece][to]で示される。 // ※ Stockfishとは、添字の順番を入れ替えてあるので注意。 -// Stockfishでは[piece][to]の順。 +// やねうら王では[to][piece]の順。 using PieceToHistory = Stats; /// ContinuationHistory is the combined history of a given pair of moves, usually @@ -135,6 +136,8 @@ using PieceToHistory = Stats; // 普通、1手前によって与えられる現在の指し手(によるcombined history) // このnested history tableは、ButterflyBoardsの代わりに、PieceToHistoryをベースとしている。 // ※ Stockfishとは、添字の順番を入れ替えてあるので注意。 +// Stockfishでは、 [pc][to]の順。 +//  やねうら王では、[to][pc]の順。 using ContinuationHistory = Stats; diff --git a/source/thread.cpp b/source/thread.cpp index b987080d7..90f73d25f 100644 --- a/source/thread.cpp +++ b/source/thread.cpp @@ -57,6 +57,10 @@ void Thread::clear() // Tweak history initialization : https://github.com/official-stockfish/Stockfish/commit/7d44b43b3ceb2eebc756709432a0e291f885a1d2 for (auto& to : continuationHistory[inCheck][c]) + // ↑Stockfishでは [pc][to]の順、 + // やねうら王では[to][pc]の順だから + // ここではStockfishではpcが来るのが正しいのだが、なぜか + // Stockfishのソースコード、変数名がtoになっている。 for (auto& h : to) h->fill(-71); diff --git a/source/thread.h b/source/thread.h index 471a6dfd4..c5bb2c1fa 100644 --- a/source/thread.h +++ b/source/thread.h @@ -142,7 +142,7 @@ class Thread // コア数が多いか、長い持ち時間においては、ContinuationHistoryもスレッドごとに確保したほうが良いらしい。 // cf. https://github.com/official-stockfish/Stockfish/commit/5c58d1f5cb4871595c07e6c2f6931780b5ac05b5 - // 添字の[2][2]は、[inCheck(王手がかかっているか)][captureOrPawnPromotion] + // 添字の[2][2]は、[inCheck(王手がかかっているか)][capture] // → この改造、レーティングがほぼ上がっていない。悪い改造のような気がする。 ContinuationHistory continuationHistory[2][2];