Skip to content

やねうら王の更新履歴2023DR4

yaneurao edited this page Dec 21, 2023 · 2 revisions

■ 2023年電竜戦4までとハードウェア統一戦までのやねうら王開発版の更新履歴

YaneuraOuNNUE_V774taya-dr4_1024.exe : 第4回電王戦バージョン「水匠」探索部

  • V7.74taya-t1
    • V7.74taya-r2より。
      • movepick.cppのqsearch()以前のコードにrollback
	// 王手がかかっているなら王手回避のフェーズへ。さもなくばQSEARCHのフェーズへ。
//	stage = (pos.in_check() ? EVASION_TT : QSEARCH_TT) + !(ttm && pos.pseudo_legal(ttm));

	// ⇨ Stockfish 16のコード、ttm(置換表の指し手)は無条件でこのMovePickerが返す1番目の指し手としているが、これだと
	//    TTの指し手だけで千日手になってしまうことがある。これは、将棋ではわりと起こりうる。
	//    対策としては、qsearchで千日手チェックをしたり、SEEが悪いならskipするなど。
	//  ※ ここでStockfish 14のころのように置換表の指し手に条件をつけるのは良くなさげ。(V7.74l3 と V7.74mとの比較)

	// Stockfish 14のコード

	stage = (pos.in_check() ? EVASION_TT : QSEARCH_TT) +
		!(ttm
			&& (pos.in_check() || depth > DEPTH_QS_RECAPTURES || to_sq(ttm) == recaptureSquare)
			&& pos.pseudo_legal(ttm));
engine1 = YaneuraOuNNUE_V774taya-r2_1024.exe , eval = Li
engine2 = YaneuraOuNNUE_V774taya-t1_1024.exe , eval = Li
T2,b1000,2411 - 149 - 2400(50.11% R0.79[-7.44,9.03]) winrate black , white = 51.88% , 48.12%
⇨ 弱くはなってない。問題なし。
  • V7.74taya-t2

    • SkillLevel無効化。

    • value_draw無効化。

      engine1 = YaneuraOuNNUE_V774taya-r2_1024.exe , eval = Li engine2 = YaneuraOuNNUE_V774taya-t2_1024.exe , eval = Li T2,b1000,263 - 16 - 261(50.19% R1.33[-23.62,26.27]) winrate black , white = 51.72% , 48.28%

  • V7.74taya-t3

    • 探索部上から順番に..

      engine1 = YaneuraOuNNUE_V774taya-r2_1024.exe , eval = Li engine2 = YaneuraOuNNUE_V774taya-t3_1024.exe , eval = Li T2,b1000,2014 - 142 - 1994(50.25% R1.73[-7.29,10.76]) winrate black , white = 52.69% , 47.31% ⇨ 問題なさげ。r2が時々timeoutで落ちるが…。

  • V7.74taya-t4

    • 探索部 search() 1/5ぐらい。

      engine1 = YaneuraOuNNUE_V774taya-t2_1024.exe , eval = Li engine2 = YaneuraOuNNUE_V774taya-t4_1024.exe , eval = Li T2,b1000,2233 - 156 - 2041(52.25% R15.62[6.87,24.37]) winrate black , white = 52.2% , 47.8% ⇨ あー、なんかやらかしてる。 コメント以外はtime managementまわりしか変更ないんだが…。これでなんで弱くなるのか。固定秒やぞ? あー、increaseDepthが変わるから、再度同じ条件で探索してるのか。ここ、rollbackするか。

				else if (!mainThread->ponder
						 && Time.elapsed() > totalTime * 0.58)
					Threads.increaseDepth = false;
				else
					Threads.increaseDepth = true;
⇑以前のコード
⇓t4
				// 前回からdepthが増えたかのチェック。
				// depthが増えて行っていないなら、同じ深さで再度探索する。
				else if (!mainThread->ponder && Time.elapsed() > totalTime * 0.50)
					Threads.increaseDepth = false;
				else
					Threads.increaseDepth = true;
あー、問題箇所、ここだけではないのか。totalTimeの計算式自体が違うのか…。あー、そうか…。

⇓以前のコード、貼り付けておく。あとでrollbackして比較する。
		// 残り時間的に、次のiterationに行って良いのか、あるいは、探索をいますぐここでやめるべきか?
		if (Limits.use_time_management())
		{
			// まだ停止が確定していない
			// (このへんの仕組み、やねうら王では、Stockfishとは異なる)
			if (!Threads.stop && Time.search_end == 0)
			{
				// 1つしか合法手がない(one reply)であるだとか、利用できる時間を使いきっているだとか、

				double fallingEval = (69 + 12 * (mainThread->bestPreviousAverageScore - bestValue)
										 +  6 * (mainThread->iterValue[iterIdx] - bestValue)) / 781.4;
				fallingEval = std::clamp(fallingEval, 0.5, 1.5);

				// If the bestMove is stable over several iterations, reduce time accordingly
				// もしbestMoveが何度かのiterationにおいて安定しているならば、思考時間もそれに応じて減らす

				timeReduction = lastBestMoveDepth + 10 < completedDepth ? 1.63 : 0.73;
				double reduction = (1.56 + mainThread->previousTimeReduction) / (2.20 * timeReduction);

				// rootでのbestmoveの不安定性。
				// bestmoveが不安定であるなら思考時間を増やしたほうが良い。
				double bestMoveInstability = 1 + 1.7 * totBestMoveChanges / Threads.size();

#if 0
				int complexity = mainThread->complexityAverage.value();
				double complexPosition = std::clamp(1.0 + (complexity - 326) / 1618.1, 0.5, 1.5);
				double totalTime = Time.optimum() * fallingEval * reduction * bestMoveInstability * complexPosition;
				// → やねうら王ではcomplexityを導入しないので、以前のコードにしておく。
#endif

				// 合法手が1手しかないときはtotalTime = 0となり、即指しする計算式。
				double totalTime = rootMoves.size() == 1 ? 0 :
					Time.optimum() * fallingEval * reduction * bestMoveInstability;

				// bestMoveが何度も変更になっているならunstablePvFactorが大きくなる。
				// failLowが起きてなかったり、1つ前の反復深化から値がよくなってたりするとimprovingFactorが小さくなる。
				// Stop the search if we have only one legal move, or if available time elapsed

				if (Time.elapsed() > totalTime)
				{
					// 停止条件を満たした

					// 将棋の場合、フィッシャールールではないのでこの時点でも最小思考時間分だけは
					// 思考を継続したほうが得なので、思考自体は継続して、キリの良い時間になったらcheck_time()にて停止する。

					// ponder中なら、終了時刻はponderhit後から計算して、Time.minimum()。
					if (mainThread->ponder)
						Time.search_end = Time.minimum();
					else
					{
						// "ponderhit"しているときは、そこからの経過時間を丸める。
						// "ponderhit"していないときは開始からの経過時間を丸める。
						// そのいずれもTime.elapsed_from_ponderhit()で良い。
						Time.search_end = std::max(Time.round_up(Time.elapsed_from_ponderhit()), Time.minimum());
					}
				}

				else if (!mainThread->ponder
						 && Time.elapsed() > totalTime * 0.58)
					Threads.increaseDepth = false;
				else
					Threads.increaseDepth = true;
			}
		}
  • V7.74taya-t5

    • 探索部 search() 2/5ぐらい。

    • VALUE_KNOWN_WIN削除

      engine1 = YaneuraOuNNUE_V774taya-t2_1024.exe , eval = Li engine2 = YaneuraOuNNUE_V774taya-t5_1024.exe , eval = Li T2,b1000,170 - 10 - 160(51.52% R10.53[-20.9,41.96]) winrate black , white = 53.94% , 46.06% // 問題なさげ。

  • V7.74taya-t6

    • 探索部 search() 3/5ぐらい。

      engine1 = YaneuraOuNNUE_V774taya-t2_1024.exe , eval = Li engine2 = YaneuraOuNNUE_V774taya-t6_1024.exe , eval = Li T2,b1000,262 - 17 - 191(57.84% R54.91[27.75,82.07]) winrate black , white = 48.57% , 51.43%

      ⇨ 何か壊してるわ。

      improvingまわりで壊してるっぽい。

  • V7.74taya-t7

    • ⇑の修正。

    • time managementいったん丸ごと元に戻す。

          improving =   (ss - 2)->staticEval != VALUE_NONE ? ss->staticEval > (ss - 2)->staticEval
                      : (ss - 4)->staticEval != VALUE_NONE ? ss->staticEval > (ss - 4)->staticEval
                                                          : true;
      

      engine1 = YaneuraOuNNUE_V774taya-t2_1024.exe , eval = Li engine2 = YaneuraOuNNUE_V774taya-t7_1024.exe , eval = Li T2,b1000,379 - 19 - 382(49.8% R-1.37[-22.07,19.33]) winrate black , white = 52.3% , 47.7%

      ⇨ 問題なさげ。

  • V7.74taya-t8

    • ss->depth削除

    • MOVE_WINをTTに格納するのやめる。 ⇨ これでちょっと損してる可能性はあるのか…。 ⇨ t7とt8と比較する。

      engine1 = YaneuraOuNNUE_V774taya-t2_1024.exe , eval = Li engine2 = YaneuraOuNNUE_V774taya-t8_1024.exe , eval = Li T2,b1000,587 - 36 - 587(50.0% R-0.0[-16.67,16.67]) winrate black , white = 49.32% , 50.68% ⇨ 計測できない差

      engine1 = YaneuraOuNNUE_V774taya-t7_1024.exe , eval = Li engine2 = YaneuraOuNNUE_V774taya-t8_1024.exe , eval = Li T2,b1000,945 - 62 - 873(51.98% R13.77[0.36,27.18]) winrate black , white = 52.53% , 47.47% ⇨ あかんっぽい。マジかよ…。

  • V7.74taya-t9

    • V7.74taya-t7にrollback
    • MOVE_WINをTTに格納するの再開。
    • time managementのコード
				else if (!mainThread->ponder
						 && Time.elapsed() > totalTime * 0.58)
					Threads.increaseDepth = false;
				else
					Threads.increaseDepth = true;
ここだけ適用する。

engine1 = YaneuraOuNNUE_V774taya-t7_1024.exe , eval = Li
engine2 = YaneuraOuNNUE_V774z3_1024.exe , eval = Li
T3,b1000,470 - 42 - 378(55.42% R37.84[18.11,57.57]) winrate black , white = 52.12% , 47.88%
⇨ まだだいぶ負けてるなー。

engine1 = YaneuraOuNNUE_V774taya-t7_1024.exe , eval = Li
engine2 = YaneuraOuNNUE_V774taya-t9_1024.exe , eval = Li
T2,b1000,1418 - 92 - 1490(48.76% R-8.6[-19.2,2.0]) winrate black , white = 51.2% , 48.8%
⇨ t7よりt9の方が良さそう…。
⇨ MOVE_WINをTTに格納して良くなったのかわからんか…。これだけ個別にテストしないと。
  • V7.74taya-t10
    • 宣言勝ちと1手詰め、置換表に保存しない。
//				tte->save(posKey, value_to_tt(bestValue, ss->ply), ss->ttPv, BOUND_EXACT,
//					MAX_PLY, m, ss->staticEval);
//					tte->save(posKey, value_to_tt(bestValue, ss->ply), ss->ttPv, BOUND_EXACT,
//						MAX_PLY, move, /* ss->staticEval */ bestValue);
engine1 = YaneuraOuNNUE_V774taya-t9_1024.exe , eval = Li
engine2 = YaneuraOuNNUE_V774taya-t10_1024.exe , eval = Li
T2,b1000,1462 - 96 - 1442(50.34% R2.39[-8.21,13.0]) winrate black , white = 52.55% , 47.45%
⇨ 優劣不明。よくわからん…。
  • V7.74taya-t11

    • V7.74taya-t9から
    • 宣言勝ちと1手詰め、置換表に保存する時に DEPTH_NONEにする。 ⇨ よく考えたら枝刈りされなくてよくなさげ。MAX_PLY/4の方がいいか。
  • V7.74taya-t12

    • V7.74taya-t9から

    • qsearch()のmate1plyも置換表に書き出すことにした。

      engine1 = YaneuraOuNNUE_V774taya-t9_1024.exe , eval = Li engine2 = YaneuraOuNNUE_V774taya-t12_1024.exe , eval = Li T2,b1000,2937 - 198 - 2865(50.62% R4.31[-3.19,11.81]) winrate black , white = 51.38% , 48.62% ⇨ 得しなさそうなのでこんな際どいのやめとく。

  • V7.74taya-t13

    • V7.74taya-t9より。

    • 置換表から取り出した指し手のlegality checkに引っかかったら置換表にhitしなかったことにする。

	// ⇑ここ、tte->move()はMove16なので、やねうら王ではpos.to_move()でMoveに変換する必要があることに注意。
	// pos.to_move()でlegalityのcheckに引っかかったパターンなので置換表にhitしなかったことにする。
	if (tte->move().to_u16() && !ttMove)
		ss->ttHit = false;

	pvHit   = ss->ttHit && tte->is_pv();
⇨ 影響軽微だと思うので、他の改造も。
  • quietsSearched 64→32手に変更

    engine1 = YaneuraOuNNUE_V774taya-t9_1024.exe , eval = Li engine2 = YaneuraOuNNUE_V774taya-t13_1024.exe , eval = Li T2,b1000,1971 - 155 - 1964(50.09% R0.62[-8.49,9.73]) winrate black , white = 51.92% , 48.08% ⇨ この影響、計測不可能な差。

  • V7.74taya-t14

    • Reductionテーブルの初期化で、スレッド数も考慮するようにした。
	for (int i = 1; i < MAX_MOVES; ++i)
		Reductions[i] = int((PARAM_REDUCTIONS_PARAM1 / 100.0 /*(100で割ったあとの数値が)20.37*/  + std::log(THREAD_SIZE) / 2) * std::log(i));
// Reductionsテーブルの初期化用
// 重要度 ★★★★★
// 元の値 = 2037 ,step = 8
// [PARAM] min:1500,max:2500,step:2,interval:2,time_rate:1,fixed
PARAM_DEFINE PARAM_REDUCTIONS_PARAM1 = 2037;
engine1 = YaneuraOuNNUE_V774taya-t13_1024.exe , eval = Li
engine2 = YaneuraOuNNUE_V774taya-t14_1024.exe , eval = Li
T4,b1000,1105 - 104 - 1101(50.09% R0.63[-11.53,12.79]) winrate black , white = 51.41% , 48.59%
⇨ 4スレで悪化してないので良しとする。
  • V7.74taya-t15
    • excludedMoveがあっても同じhash keyを参照するようにした。
	posKey  = excludedMove == MOVE_NONE ? pos.hash_key() : pos.hash_key() ^ HASH_KEY(make_key(excludedMove));
engine1 = YaneuraOuNNUE_V774taya-t14_1024.exe , eval = Li
engine2 = YaneuraOuNNUE_V774taya-t15_1024.exe , eval = Li
T2,b1000,278 - 7 - 175(61.37% R80.4[52.86,107.95]) winrate black , white = 54.3% , 45.7%

⇨ なんかバグってる。
⇨ SQ_NONEのチェック要るのか…。わからん。一旦、これrollbackする。
  • V7.74taya-t16

    • V7.74taya-t14から。

    • MOVE_WIN置換表に書き出さないように変更。

    • SQ_NONE導入

      engine1 = YaneuraOuNNUE_V774taya-t14_1024.exe , eval = Li engine2 = YaneuraOuNNUE_V774taya-t16_1024.exe , eval = Li T2,b1000,79 - 3 - 48(62.2% R86.55[34.46,138.65]) winrate black , white = 51.18% , 48.82% ⇨ まだバグったままだった。

  • V7.74taya-t17

    • pos.legal()移動 // Check for legality ⇨ 棋力に影響はないはず
	else if (excludedMove)
	{
		// Providing the hint that this node's accumulator will be used often brings significant Elo gain (~13 Elo)

		//Eval::NNUE::hint_common_parent_position(pos);
		// TODO : → 今回のNNUEの計算は端折れるのか?

		eval = ss->staticEval;
	}
ここ、ss->staticEvalが値が違うのでこれ適用したら駄目なのか…。いったんrollbackする。

engine1 = YaneuraOuNNUE_V774taya-t14_1024.exe , eval = Li
engine2 = YaneuraOuNNUE_V774taya-t17_1024.exe , eval = Li
T2,b1000,1471 - 101 - 1468(50.05% R0.35[-10.19,10.89]) winrate black , white = 53.18% , 46.82%
⇨ 影響なさそう。OK。
  • V7.74taya-t18

    • scoreLowerbound , scoreUpperbound の更新処理
    • 棋力に影響するところはあまり変えてないつもりだけど、一応、棋力チェック。

    engine1 = YaneuraOuNNUE_V774taya-t14_1024.exe , eval = Li engine2 = YaneuraOuNNUE_V774taya-t18_1024.exe , eval = Li T2,b1000,1618 - 109 - 1753(48.0% R-13.92[-23.77,-4.07]) winrate black , white = 51.79% , 48.21%

  • V7.74taya-t19

    • 枝刈りの条件など最新のやねうら王に倣う。
    • 棋力に影響するところはあまり変えてないつもりだけど、一応、棋力チェック。

    engine1 = YaneuraOuNNUE_V774taya-t18_1024.exe , eval = Li engine2 = YaneuraOuNNUE_V774taya-t19_1024.exe , eval = Li T2,b1000,55 - 2 - 53(50.93% R6.43[-48.34,61.21]) winrate black , white = 48.15% , 51.85% ⇨ 壊してることはなさそうなのでOKとする。

  • V7.74taya-t20

    • update_all_stats()、なるべく倣った。stat_malus()はまだ導入しておらず。パラメーターも変えておらず。

    engine1 = YaneuraOuNNUE_V774taya-t18_1024.exe , eval = Li engine2 = YaneuraOuNNUE_V774taya-t20_1024.exe , eval = Li T2,b1000,450 - 28 - 452(49.89% R-0.77[-19.79,18.25]) winrate black , white = 47.67% , 52.33% ⇨ 壊してなさそうなので良しとする。

  • V7.74taya-t21

    • update_continuation_histories() で 1,2,4,6でなく1,2,3,4,6に。
    • capture()になっていたところ、capture_stage()に変更。
      • capture_stage()の実装がcapture()を呼び出しているので、棋力に変化はないはず。

    engine1 = YaneuraOuNNUE_V774taya-t20_1024.exe , eval = Li engine2 = YaneuraOuNNUE_V774taya-t21_1024.exe , eval = Li T2,b1000,1099 - 63 - 998(52.41% R16.75[4.26,29.24]) winrate black , white = 52.22% , 47.78%

    ⇨ 強くなってなさそうなのでrollback

  • V7.74taya-t22

    • PARAM_NULL_MOVE_MARGIN0、削除
    • check extensionの条件追加。
				&& depth > 9
				// !!重要!!
				// この条件、やねうら王では独自に追加している。
				// → 王手延長は、開き王手と駒損しない王手に限定する。
				//  将棋だと王手でどんどん延長させる局面があり、探索が終わらなくなる。
				&& (pos.is_discovery_check_on_king(~us, move) || pos.see_ge(move))
engine1 = YaneuraOuNNUE_V774taya-t20_1024.exe , eval = Li
engine2 = YaneuraOuNNUE_V774taya-t22_1024.exe , eval = Li
T2,b1000,1445 - 97 - 1488(49.27% R-5.09[-15.65,5.46]) winrate black , white = 51.45% , 48.55%
⇨ マイナスになってないなら、長い時間では追加しておいたほうがよさげ。
  • V7.74taya-t23

    • fail highするごとにdepthを下げていく処理 Depth adjustedDepth = std::max(1, rootDepth - failedHighCnt - searchAgainCounter); ⇓ Depth adjustedDepth = std::max(1, rootDepth - failedHighCnt - 3 * (searchAgainCounter + 1) / 4);

    1手詰めsaveするdepthをMAX_PLYから⇓に変更。 std::min(MAX_PLY - 1, depth + 6)

    • ⇓この初期化、いらんっぽい。削除 (ss + 1)->ttPv = false;

    engine1 = YaneuraOuNNUE_V774taya-t20_1024.exe , eval = Li engine2 = YaneuraOuNNUE_V774taya-t23_1024.exe , eval = Li T2,b1000,2885 - 182 - 2933(49.59% R-2.87[-10.36,4.63]) winrate black , white = 51.13% , 48.87% ⇨ 弱くはなってなさそう?

  • V7.74taya-t24

    • stat_malus導入。ただし、パラメーターの値はいまのまま。
    • update_all_stats()、丸コピーした。

    engine1 = YaneuraOuNNUE_V774taya-t20_1024.exe , eval = Li engine2 = YaneuraOuNNUE_V774taya-t24_1024.exe , eval = Li T2,b1000,2994 - 207 - 2799(51.68% R11.7[4.19,19.21]) winrate black , white = 51.77% , 48.23%

    engine1 = YaneuraOuNNUE_V774taya-t23_1024.exe , eval = Li engine2 = YaneuraOuNNUE_V774taya-t24_1024.exe , eval = Li T2,b1000,3053 - 178 - 2769(52.44% R16.96[9.46,24.46]) winrate black , white = 51.49% , 48.51%

    ⇨ ちょっと弱くなってるな。何かやらかしてる可能性がある。t23→t24 rollbackする

  • V7.74taya-t25

    • alphaを上回った時の更新処理、書き直した。
	// 反復深化のiterationが浅いうちはaspiration searchを使わない。
	// 探索窓を (-VALUE_INFINITE , +VALUE_INFINITE)とする。
	bestValue = delta = alpha = -VALUE_INFINITE;
	beta = VALUE_INFINITE;
⇨ やめた。
// ここまでは同等のはず..
  • V7.74taya-t26

    • ProbCutのdepthをdepth > 4でなく depth > 3から適用するように変更。

    engine1 = YaneuraOuNNUE_V774taya-t20_1024.exe , eval = Li engine2 = YaneuraOuNNUE_V774taya-t26_1024.exe , eval = Li T2,b1000,1518 - 98 - 1384(52.31% R16.05[5.44,26.67]) winrate black , white = 52.14% , 47.86%

  • V7.74taya-t27

    • singular depthの計算式変更 Depth singularDepth = (depth - 1) / 2; ⇓ Depth singularDepth = newDepth / 2;
    • Recapture extension追加。
            // Recapture extensions (~1 Elo)
            else if (PvNode && move == ttMove && to_sq(move) == prevSq
                     && captureHistory(movedPiece, to_sq(move), type_of(pos.piece_on(to_sq(move))))
                          > 4000)
                extension = 1;
  • V7.74taya-t28
	// nonPVでは置換表の指し手で枝刈りする
	// PVでは置換表の指し手では枝刈りしない(前回evaluateした値は使える)
	if (  !PvNode
		&& tte->depth() >= ttDepth
  • V7.74taya-t29 delta = Value(PARAM_ASPIRATION_SEARCH_DELTA) + int(avg) * avg / 15799; ⇓ delta = Value(PARAM_ASPIRATION_SEARCH_DELTA /10/) + int(avg) * avg / 15335; わずかに定数変わるな…。

      int bonus = std::clamp(-18 * int((ss - 1)->staticEval + ss->staticEval), -1817, 1817);
    

    ⇓ int bonus = std::clamp(-18 * int((ss-1)->staticEval + ss->staticEval), -1812, 1812);

    probCutBeta = beta + 413; ⇓ probCutBeta = beta + PARAM_PROBCUT_MARGIN3 /416/;

    engine1 = YaneuraOuNNUE_V774taya-t20_1024.exe , eval = Li engine2 = YaneuraOuNNUE_V774taya-t29_1024.exe , eval = Li T2,b1000,1522 - 97 - 1381(52.43% R16.89[6.27,27.51]) winrate black , white = 50.91% , 49.09%

  • V7.74taya-t30

    • V7.74taya-t23→t24でstat_malusを追加したのが原因なので
// History and stats update bonus, based on depth
// depthに基づく、historyとstatsのupdate bonus
int stat_bonus(Depth d) {
	return std::min(336 * d - 547, 1561);
}

// History and stats update malus, based on depth
// depthに基づく、historyとstatsのupdate malus
// ※ malus(「悪い」、「不利益」みたいな意味)は
// 「統計的なペナルティ」または「マイナスの修正値」を計算するために使用される。
// この関数は、ある行動が望ましくない結果をもたらした場合に、その行動の評価を減少させるために使われる

int stat_malus(Depth d) { return std::min(364 * d - 438, 1501); }

int stat_malus(Depth d) {
	return std::min(336 * d - 547, 1561);
}

まず、stat_bonusと同等にする。

engine1 = YaneuraOuNNUE_V774taya-t20_1024.exe , eval = Li
engine2 = YaneuraOuNNUE_V774taya-t30_1024.exe , eval = Li
T2,b1000,2199 - 149 - 2252(49.4% R-4.14[-12.7,4.43]) winrate black , white = 51.02% , 48.98%
→ 計測回数的に優劣わからないが悪くはなさそう。
  • V7.74taya-t31
    • V7.74taya-t29より。
// History and stats update bonus, based on depth
// depthに基づく、historyとstatsのupdate bonus
int stat_bonus(Depth d) {
	// return std::min(364 * d - 438, 1501);
	// ⇑Stockfish 16の式。⇓Stockfish 14の式
	return std::min(336 * d - 547, 1561);
}

// History and stats update malus, based on depth
// depthに基づく、historyとstatsのupdate malus
// ※ malus(「悪い」、「不利益」みたいな意味)は
// 「統計的なペナルティ」または「マイナスの修正値」を計算するために使用される。
// この関数は、ある行動が望ましくない結果をもたらした場合に、その行動の評価を減少させるために使われる

int stat_malus(Depth d) {
	// return std::min(452 * d - 452, 1478);
	// ⇓係数は1.09で割る。定数は1.24掛ける。limitは1.04掛ける。
	return std::min(414 * d - 560, 1537);
}
engine1 = YaneuraOuNNUE_V774taya-t20_1024.exe , eval = Li
engine2 = YaneuraOuNNUE_V774taya-t31_1024.exe , eval = Li
T2,b1000,2049 - 121 - 1900(51.89% R13.12[4.02,22.21]) winrate black , white = 53.03% , 46.97%
→ 話にならんレベルであかんかった。
  • V7.74taya-32
    • V7.74taya-t29より。
    • stat_bonusとstata_malusをStockfish 16に倣う。
// History and stats update bonus, based on depth
// depthに基づく、historyとstatsのupdate bonus

int stat_bonus(Depth d) { return std::min(364 * d - 438, 1501); }
	// → やねうら王では、Stockfishの統計値、統計ボーナスに関して手を加えないことにしているので
	// この値はStockfishの値そのまま。

// History and stats update malus, based on depth
// depthに基づく、historyとstatsのupdate malus
// ※ malus(「悪い」、「不利益」みたいな意味)は
// 「統計的なペナルティ」または「マイナスの修正値」を計算するために使用される。
// この関数は、ある行動が望ましくない結果をもたらした場合に、その行動の評価を減少させるために使われる
int stat_malus(Depth d) { return std::min(452 * d - 452, 1478); }
engine1 = YaneuraOuNNUE_V774taya-t20_1024.exe , eval = Li
engine2 = YaneuraOuNNUE_V774taya-t32_1024.exe , eval = Li
T2,b1000,2093 - 154 - 2093(50.0% R-0.0[-8.83,8.83]) winrate black , white = 50.48% , 49.52%
→ 優劣判定不能…。
  • V7.74taya-t33
    • V7.74taya-30より。
    • negative extension削除
				// If the eval of ttMove is less than alpha, we reduce it (negative extension)
				else if (ttValue <= alpha)
					extension = -1;
  • likely faillowのnegative extension条件変更
		if (   ss->ttPv
			&& !likelyFailLow)
			r -= cutNode && tte->depth() >= depth + 3 ? 3 : 2;
		if (   ss->ttPv
			&& !likelyFailLow)
			r -= cutNode && tte->depth() >= depth ? 3 : 2;

engine1 = YaneuraOuNNUE_V774taya-t20_1024.exe , eval = Li engine2 = YaneuraOuNNUE_V774taya-t33_1024.exe , eval = Li T2,b1000,2798 - 192 - 3010(48.17% R-12.69[-20.19,-5.18]) winrate black , white = 52.57% , 47.43% → 悪くなかった

  • V7.74taya-t34
    • Pvのreduction減らす。
		// Decrease reduction for PvNodes (~2 Elo)
		// PvNodeではreductionを減らす。

		if (PvNode && !ss->inCheck && abs(ss->staticEval - bestValue) > 250)
			r--;

		// Decrease reduction for PvNodes based on depth
		if (PvNode)
			r -= 1 + 12 / (3 + depth);
			

		if (PvNode)
			r--;

engine1 = YaneuraOuNNUE_V774taya-t20_1024.exe , eval = Li engine2 = YaneuraOuNNUE_V774taya-t34_1024.exe , eval = Li T2,b1000,2877 - 190 - 2933(49.52% R-3.35[-10.85,4.15]) winrate black , white = 51.53% , 48.47% → なんか悪化しとる気がする。これいったんrollbackするか..

  • V7.74taya-t35
    • doEvenDeeperSearch削除 const bool doEvenDeeperSearch = value > alpha + 711 && ss->doubleExtensions <= 6; → 削除 ss->doubleExtensions = ss->doubleExtensions + doEvenDeeperSearch; → 削除

        	newDepth += doDeeperSearch - doShallowerSearch + doEvenDeeperSearch;
      

⇓ newDepth += doDeeperSearch - doShallowerSearch;

engine1 = YaneuraOuNNUE_V774taya-t20_1024.exe , eval = Li engine2 = YaneuraOuNNUE_V774taya-t35_1024.exe , eval = Li T2,b1000,2861 - 196 - 2943(49.29% R-4.91[-12.41,2.59]) winrate black , white = 52.46% , 47.54% → 影響軽微

  • V7.74taya-t36 : 第4回 電竜戦バージョン「水匠」探索部 = YaneuraOuNNUE_V774taya-dr4_1024.exe value = -search(pos, ss+1, -(alpha+1), -alpha, newDepth - (r > 4), !cutNode); ⇓ value = -search(pos, ss + 1, -(alpha + 1), -alpha, newDepth - (r > 3), !cutNode);

      if (PvNode && (moveCount == 1 || (value > alpha && (rootNode || value < beta))))
      ⇓
      if (PvNode && (moveCount == 1 || value > alpha))
    
      	
      	if (moveCount > 1 && newDepth >= depth && !capture)
      		update_continuation_histories(ss, movedPiece, to_sq(move), -stat_bonus(newDepth));
      ⇓
      削除
    

    engine1 = YaneuraOuNNUE_V774taya-t20_1024.exe , eval = Li engine2 = YaneuraOuNNUE_V774taya-t36_1024.exe , eval = Li T2,b1000,2822 - 172 - 3006(48.42% R-10.97[-18.46,-3.48]) winrate black , white = 53.31% , 46.69% → これはよさげな改良。

  • V7.74taya-t37

    • V7.74taya-t34をrollback
				const bool doDeeperSearch = value > (bestValue + 64 + 11 * (newDepth - d));
⇓
				const bool doDeeperSearch     = value > (bestValue + 64 + 2 * newDepth); // (~1 Elo)

→ これ影響でかいのかも知れん。あとで検証する。

  • V7.74taya-t38
				const bool doDeeperSearch = value > (bestValue + 64 + 11 * (newDepth - d));
⇓
				const bool doDeeperSearch     = value > (bestValue + 50 + 2 * newDepth); // (~1 Elo)

engine1 = YaneuraOuNNUE_V774taya-t37_1024.exe , eval = Li engine2 = YaneuraOuNNUE_V774taya-t38_1024.exe , eval = Li T2,b1000,2910 - 208 - 2882(50.24% R1.68[-5.83,9.19]) winrate black , white = 51.12% , 48.88% → 悪くはなってなさそう。

  • V7.74taya-t39
		return eval;
    ⇓
		return (eval + beta) / 2;


			if (   capture || givesCheck)
			{
				// Futility pruning for captures (~2 Elo)
				Piece capturedPiece = pos.piece_on(to_sq(move));

				if (   !givesCheck
					&& !PvNode
					&& lmrDepth < 7
					&& !ss->inCheck
					&& ss->staticEval + 197 + 248 * lmrDepth + CapturePieceValuePlusPromote(pos,move)
					 + captureHistory(movedPiece, to_sq(move), type_of(capturedPiece)) / 7 < alpha)
					continue;

				// SEE based pruning for captures and checks (~11 Elo)
				if (!pos.see_ge(move, - Value(PARAM_LMR_SEE_MARGIN1 /*212*/) * depth)) // (~25 Elo)
					continue;
⇓
			if (   capture || givesCheck)
			{
				// Futility pruning for captures (~2 Elo)
				if (!givesCheck && lmrDepth < 7 && !ss->inCheck)
				{
					Piece capturedPiece = pos.piece_on(to_sq(move));
					// TODO : ここのパラメーター、調整すべきか? 2 Eloだから無視していいか…。
					int   futilityEval =
						ss->staticEval + 197 + 248 * lmrDepth + CapturePieceValuePlusPromote(pos, move)
						+ captureHistory(movedPiece, to_sq(move), type_of(capturedPiece)) / 7;

					if (futilityEval < alpha)
						continue;
				}

				// SEE based pruning for captures and checks (~11 Elo)
				if (!pos.see_ge(move, - Value(PARAM_LMR_SEE_MARGIN1 /*212*/) * depth)) // (~25 Elo)
					continue;
			}

engine1 = YaneuraOuNNUE_V774taya-t38_1024.exe , eval = Li engine2 = YaneuraOuNNUE_V774taya-t39_1024.exe , eval = Li T2,b1000,2899 - 210 - 2891(50.07% R0.48[-7.03,7.99]) winrate black , white = 51.11% , 48.89% → 計測できない差なので良しとする。

  • V7.74taya-t40

				// Continuation history based pruning (~2 Elo)
				// Continuation historyに基づいた枝刈り(historyの値が悪いものに関してはskip)

				if (lmrDepth < PARAM_PRUNING_BY_HISTORY_DEPTH/*6*/ && history < -3832 * depth)
					continue;

				history += 2 * thisThread->mainHistory(us, from_to(move));

				lmrDepth += history / 7011;
				lmrDepth = std::max(lmrDepth, -2);

⇓

				// Continuation history based pruning (~2 Elo)
				// Continuation historyに基づいた枝刈り(historyの値が悪いものに関してはskip)

				if (lmrDepth < PARAM_PRUNING_BY_HISTORY_DEPTH/*6*/ && history < -3645 * depth)
					continue;

				history += 2 * thisThread->mainHistory(us, from_to(move));

				lmrDepth += history / 7836;
				lmrDepth = std::max(lmrDepth, -1);


engine1 = YaneuraOuNNUE_V774taya-t39_1024.exe , eval = Li engine2 = YaneuraOuNNUE_V774taya-t40_1024.exe , eval = Li T2,b1000,2923 - 206 - 2871(50.45% R3.12[-4.39,10.63]) winrate black , white = 51.73% , 48.27% → 少し悪化してる可能性あるか…。historyの値変えるの良くないか…。

  • V7.74taya-t41
		if (   depth >= 2
			&& moveCount > 1 + (PvNode && ss->ply <= 1)
			&& (   !ss->ttPv
				|| !capture
				|| (cutNode && (ss - 1)->moveCount > 1)))

⇓
		if (   depth >= 2
			&& moveCount > 1 + rootNode
			&& (   !ss->ttPv
				|| !capture
				|| (cutNode && (ss - 1)->moveCount > 1)))

engine1 = YaneuraOuNNUE_V774taya-t40_1024.exe , eval = Li engine2 = YaneuraOuNNUE_V774taya-t41_1024.exe , eval = Li T2,b1000,2958 - 196 - 2846(50.96% R6.71[-0.8,14.21]) winrate black , white = 52.31% , 47.69%

明確に悪化してますやん…。

  • V7.74taya-t42
	else if (!priorCapture && prevSq != SQ_NONE)
	{
		int bonus = (depth > 5) + (PvNode || cutNode) + (bestValue < alpha - 113 * depth) + ((ss - 1)->moveCount > 12);
		update_continuation_histories(ss - 1, pos.piece_on(prevSq), prevSq,
										stat_bonus(depth) * bonus);
	}

⇓
	else if (!priorCapture && prevSq != SQ_NONE)
	{
		int bonus = (depth > 6) + (PvNode || cutNode) + (bestValue < alpha - PARAM_COUNTERMOVE_FAILLOW_MARGIN /*657*/)
				    + ((ss - 1)->moveCount > 10);
		update_continuation_histories(ss - 1, pos.piece_on(prevSq), prevSq,
										stat_bonus(depth) * bonus);

    // ⇑ここはこのまま。⇓ここ追加

		thisThread->mainHistory(~us, from_to((ss - 1)->currentMove))
			<< stat_bonus(depth) * bonus / 2;
	}

engine1 = YaneuraOuNNUE_V774taya-t41_1024.exe , eval = Li engine2 = YaneuraOuNNUE_V774taya-t42_1024.exe , eval = Li T2,b1000,2852 - 198 - 2950(49.16% R-5.87[-13.37,1.63]) winrate black , white = 51.48% , 48.52%

→ いいのこれだけですやん…。

engine1 = YaneuraOuNNUE_V771a_1024.exe , eval = Li engine2 = YaneuraOuNNUE_V774taya-t42_1024.exe , eval = Li T2,b1000,1128 - 94 - 1508(42.79% R-50.44[-61.68,-39.19]) winrate black , white = 51.48% , 48.52% V7.70に対して+R50かぁ…。そこからR15差が縮まったとしてR35差。

engine1 = YaneuraOuNNUE_V774taya-t36_1024.exe , eval = Li engine2 = YaneuraOuNNUE_V774taya-t42_1024.exe , eval = Li T2,b1000,2738 - 229 - 2723(50.14% R0.95[-6.78,8.69]) winrate black , white = 52.39% , 47.61% → 計測できない差。ほぼ互角。

engine1 = YaneuraOuNNUE_V774taya-t38_1024.exe , eval = Li engine2 = YaneuraOuNNUE_V774taya-t42_1024.exe , eval = Li T2,b1000,2857 - 212 - 2931(49.36% R-4.44[-11.95,3.07]) winrate black , white = 52.14% , 47.86% → つよなってるっぽい。36→38でよわなってる可能性ある。

  • V7.74taya-t43

    engine1 = YaneuraOuNNUE_V774taya-t42_1024.exe , eval = Li engine2 = YaneuraOuNNUE_V774taya-t43_1024.exe , eval = Li T2,b1000,166 - 10 - 104(61.48% R81.23[45.56,116.9]) winrate black , white = 57.41% , 42.59%

    → めっちゃよわくなってるのどこが原因かわからん。順番にコピって、うまく動くところまで進めるしかあらへん。

  • V7.74taya-t44 もすこしコピーした。

    engine1 = YaneuraOuNNUE_V774taya-t42_1024.exe , eval = Li engine2 = YaneuraOuNNUE_V774taya-t44_1024.exe , eval = Li T2,b1000,183 - 8 - 129(58.65% R60.74[27.94,93.55]) winrate black , white = 53.53% , 46.47%

  • V7.74taya-t45 もすこしコピーした。

    engine1 = YaneuraOuNNUE_V774taya-t42_1024.exe , eval = Li engine2 = YaneuraOuNNUE_V774taya-t45_1024.exe , eval = Li T2,b1000,93 - 6 - 31(75.0% R190.85[131.87,249.82]) winrate black , white = 61.29% , 38.71% → 中途半端にコピーしたからこじらせたか。

  • V7.74taya-t46 もすこしコピーした。

    engine1 = YaneuraOuNNUE_V774taya-t42_1024.exe , eval = Li engine2 = YaneuraOuNNUE_V774taya-t46_1024.exe , eval = Li T2,b1000,696 - 32 - 482(59.08% R63.82[46.9,80.75]) winrate black , white = 49.92% , 50.08% → 発狂はしてないがまだ弱いな…。 V770とはもともとの差があるからか…。 V770とも比較するか。

  • V7.74taya-t47

	// 置換表の指し手を優遇するコード。
	// depth > -5なら、TT優先。depth <= -5でもcaptureなら優先。
	stage = (pos.in_check() ? EVASION_TT : QSEARCH_TT) +
		!(ttm
			&& (pos.in_check() || depth > DEPTH_QS_RECAPTURES || pos.capture(ttm))
			&& pos.pseudo_legal(ttm));

engine1 = YaneuraOuNNUE_V774taya-t42_1024.exe , eval = Li engine2 = YaneuraOuNNUE_V774taya-t47_1024.exe , eval = Li T2,b1000,2889 - 208 - 2903(49.88% R-0.84[-8.35,6.67]) winrate black , white = 50.98% , 49.02%

  • V7.74taya-t48
    • V7.74taya-t47

    • ⇓単にcapture()にしてみる。

	stage = (pos.in_check() ? EVASION_TT : QSEARCH_TT) +
		!(ttm
			&& (pos.in_check() || pos.capture(ttm))
			&& pos.pseudo_legal(ttm));

engine1 = YaneuraOuNNUE_V774taya-t42_1024.exe , eval = Li engine2 = YaneuraOuNNUE_V774taya-t48_1024.exe , eval = Li T2,b1000,2888 - 198 - 2914(49.78% R-1.56[-9.06,5.95]) winrate black , white = 51.36% , 48.64% → t47,48でどちらがいいかよくわからん。

  • V7.74taya-t49
    • fail lowを起こしたcounter moveにbonus
		int bonus = (depth > 5) + (PvNode || cutNode) + (bestValue < alpha - 113 * depth) + ((ss - 1)->moveCount > 12);
⇓
		int bonus = (depth > 6) + (PvNode || cutNode) + (bestValue < alpha - PARAM_COUNTERMOVE_FAILLOW_MARGIN /*657*/)
				    + ((ss - 1)->moveCount > 10);

engine1 = YaneuraOuNNUE_V774taya-t48_1024.exe , eval = Li engine2 = YaneuraOuNNUE_V774taya-t49_1024.exe , eval = Li T2,b1000,2849 - 216 - 2935(49.26% R-5.17[-12.68,2.35]) winrate black , white = 52.04% , 47.96% → 悪くはなさそうなので良し。

  • V7.74taya-t50
    • V7.74taya-t49から。
    • V7.74taya-t47のコードに変更。
      • この変更するので、強さの細かい比較はしても仕方がないか。
    • NullMoveのコード掃除。
// 256倍されていることに注意。
// 元の値 = 1024 , step = 128
// [PARAM] min:500,max:1500,step:64,interval:1,time_rate:1,fixed
PARAM_DEFINE PARAM_NULL_MOVE_DYNAMIC_ALPHA = 1024;

// 256倍されていることに注意。85なら85/256 = 1/3とほぼ等価。
// 元の値 = 85 , step = 24
// [PARAM] min:50,max:120,step:3,interval:1,time_rate:1,fixed
PARAM_DEFINE PARAM_NULL_MOVE_DYNAMIC_BETA = 85;
  • LMRの周り、大幅に適用順の変更があった。
    • 棋力にはほぼ影響しないはずだが…。

engine1 = YaneuraOuNNUE_V774taya-t49_1024.exe , eval = Li engine2 = YaneuraOuNNUE_V774taya-t50_1024.exe , eval = Li T2,b1000,2704 - 203 - 2903(48.23% R-12.34[-19.97,-4.7]) winrate black , white = 51.4% , 48.6% ⇨ だいぶつよなっとるな…。 → 枝刈りの適用の順序変更が利いてるのか…。 あとは48より47のほうが優れているからか。

  • V7.74taya-t51
    • qsearchのfutilityにpromotionではない条件追加。
      // Futility pruning and moveCount pruning (~10 Elo)
			if (   !givesCheck
				&&  to_sq(move) != prevSq
				&&  futilityBase > VALUE_TB_LOSS_IN_MAX_PLY
				&&  type_of(move) != PROMOTION
				// この最後の条件、入れたほうがいいのか?
				//  → captureとcheckしか生成してないのでどちらでも影響が軽微。
			)

engine1 = YaneuraOuNNUE_V774taya-t50_1024.exe , eval = Li engine2 = YaneuraOuNNUE_V774taya-t51_1024.exe , eval = Li T2,b1000,3004 - 218 - 2878(51.07% R7.44[-0.01,14.9]) winrate black , white = 51.7% , 48.3% ⇨ たぶん悪い。

  • V7.74taya-t52
    • V7.74taya-t50より。
    • movepickerのqsearchのrecaptureのコード掃除。
    • PARAM_FUTILITY_EVAL1,PARAM_FUTILITY_EVAL2追加。
    • ⇓これ追加。
				// If static exchange evaluation is much worse than what is needed to not
				// fall below alpha we can prune this move
				if (futilityBase > alpha && !pos.see_ge(move, (alpha - futilityBase) * 4))
				{
					bestValue = alpha;
					continue;
				}
            // Increase reduction for cut nodes without ttMove (~1 Elo)
            if (!ttMove && cutNode)
                r += 2;
⇓
            // Increase reduction if ttMove is not present (~1 Elo)
            if (!ttMove)
                r += 2;

このt53の変更は影響軽微なので、t50とt53とを比較

engine1 = YaneuraOuNNUE_V774taya-t50_1024.exe , eval = Li engine2 = YaneuraOuNNUE_V774taya-t53_1024.exe , eval = Li T2,b1000,1060 - 70 - 1060(50.0% R-0.0[-12.41,12.41]) winrate black , white = 51.08% , 48.92% → 計測できない差

engine1 = YaneuraOuNNUE_V774taya-t53_1024.exe , eval = Li engine2 = YaneuraOuNNUE_V775a11_1024.exe , eval = Li T2,b1000,2303 - 203 - 2414(48.82% R-8.18[-16.5,0.15]) winrate black , white = 51.39% , 48.61%

→ 本家のほうが強くなったので、たややんバージョンの開発おわり。

============================================================

  • V7.74taya-s2

    • reduction param 21.11に変更
      • 以前の値。これしか考えられへん…。

    engine1 = YaneuraOuNNUE_V774taya-s2_1024.exe , eval = Li engine2 = YaneuraOuNNUE_V774taya-r2_1024.exe , eval = Li T2,b1000,1233 - 103 - 1704(41.98% R-56.2[-66.88,-45.52]) winrate black , white = 51.04% , 48.96% ⇨ あかん。なんか壊してしもとる。taya-r2にrollbackして、かつ、千日手のとこ、 修正して、それでもっと細かく変更を適用していくわ。

  • V7.74taya-s

    • SkillLevel除去

    • Reductionsテーブルの初期化コードをSearch::clear()に移動。

    • yaneuraou-search.cpp、コメントをだいぶコピペした。

      engine1 = YaneuraOuNNUE_V774taya-s_1024.exe , eval = Li engine2 = YaneuraOuNNUE_V774taya-r2_1024.exe , eval = Li T2,b1000,452 - 32 - 626(41.93% R-56.57[-74.2,-38.94]) winrate black , white = 51.48% , 48.52% ⇨ 間違いなく何か壊してるわ。

  • V7.74taya-r

    • movepick.h 丸コピー
      • ProbCutの時のdepth、すでにつこてなかった。
    • movepick.cpp 丸コピー。変更される箇所は以下の箇所。
			m.value = 6 * int(Eval::CapturePieceValue[pos.piece_on(to_sq(m))])
					   + (*captureHistory)(pos.moved_piece_after(m), to_sq(m), type_of(pos.piece_on(to_sq(m))))
					   ;

			m.value = (7 * int(Eval::CapturePieceValuePlusPromote(pos, m))
					   + (*captureHistory)(pos.moved_piece_after(m), to_sq(m), type_of(pos.piece_on(to_sq(m)))))
					  / 16;
			m.value +=	2 * (*continuationHistory[0])(pc,to)
					+     (*continuationHistory[1])(pc,to)
					+     (*continuationHistory[3])(pc,to)
					+     (*continuationHistory[5])(pc,to)
				//	移動元の駒が安い駒で当たりになっている場合、移動させることでそれを回避できるなら価値を上げておく。

			m.value +=  2 * (*continuationHistory[0])(pc,to);
			m.value +=      (*continuationHistory[1])(pc,to);
			m.value +=      (*continuationHistory[2])(pc,to) / 4;
			m.value +=      (*continuationHistory[3])(pc,to);
			m.value +=      (*continuationHistory[5])(pc,to);
				// moveは駒打ちではないからsee()の内部での駒打ちは判定不要だが…。
				return pos.see_ge(*cur, Value(-69 * cur->value / 1024)) ?
						// 損をする捕獲する指し手はあとのほうで試行されるようにendBadCapturesに移動させる
						true : (*endBadCaptures++ = *cur, false);

				// moveは駒打ちではないからsee()の内部での駒打ちは判定不要だが…。
                return pos.see_ge(*cur, Value(-cur->value)) ?
						// 損をする捕獲する指し手はあとのほうで試行されるようにendBadCapturesに移動させる
						true : (*endBadCaptures++ = *cur, false);
V774taya-r2

- yaneuraou-search.cpp
		// -----------------------
		// moves loopに入る前の準備
		// -----------------------

		// continuationHistory[0]  = Counter Move History    : ある指し手が指されたときの応手
		// continuationHistory[1]  = Follow up Move History  : 2手前の自分の指し手の継続手
		// continuationHistory[3]  = Follow up Move History2 : 4手前からの継続手
	const PieceToHistory* contHist[] = { (ss - 1)->continuationHistory	, (ss - 2)->continuationHistory,
										 (ss - 3)->continuationHistory	, (ss - 4)->continuationHistory ,
											nullptr						, (ss - 6)->continuationHistory };

↑の箇所、修正。

engine1 = YaneuraOuNNUE_V774taya_1024.exe , eval = Li
engine2 = YaneuraOuNNUE_V774taya-r2_1024.exe , eval = Li
T3,b2000,498 - 54 - 588(45.86% R-28.86[-46.25,-11.47]) winrate black , white = 53.68% , 46.32%

engine1 = YaneuraOuNNUE_V774taya-q2_1024.exe , eval = Li
engine2 = YaneuraOuNNUE_V774taya-r2_1024.exe , eval = Li
T3,b2000,1203 - 127 - 1170(50.7% R4.83[-6.9,16.56]) winrate black , white = 52.72% , 47.28%
⇨ 計測できない差だが、弱くなってる可能性はあるか…。
  • V7.74taya-q
    • movepick.cpp比較
			else
				// それ以外の指し手に関してはhistoryの値の順番
				m.value =     (*mainHistory)(pos.side_to_move(), from_to(m))
						+ 2 * (pos.moved_piece_after(m), to_sq(m))

↑ここ、壊してた。⇓修正した。

			else
				// それ以外の指し手に関してはhistoryの値の順番
				m.value =     (*mainHistory)(pos.side_to_move(), from_to(m))
						+ 2 * (*continuationHistory[0])(pos.moved_piece_after(m), to_sq(m))
  • q1
			if (pos.capture(m))
				// 捕獲する指し手に関しては簡易SEE + MVV/LVA
				// 被害が小さいように、LVA(価値の低い駒)を動かして取ることを優先されたほうが良いので駒に価値の低い順に番号をつける。そのためのテーブル。
				// ※ LVA = Least Valuable Aggressor。cf.MVV-LVA

				// ここ、moved_piece_before()を用いるのが正しい。
				// そうしておかないと、同じto,fromである角成りと角成らずの2つの指し手がある時、
				// moved_piece_after()だと、角成りの方は、取られた時の損失が多いとみなされてしまい、
				// オーダリング上、後回しになってしまう。

				//m.value = PieceValue[pos.piece_on(to_sq(m))] - Value(type_of(pos.moved_piece(m)))
				//		+ (1 << 28);

				// 上記のStockfishのコードのValue()は関数ではなく単にValue型へcastしているだけ。
				// 駒番号順に価値が低いと考えて(普通は成り駒ではないから)、LVAとしてそれを優先して欲しいという意味。

				m.value = (Value)Eval::CapturePieceValue[pos.piece_on(to_sq(m))]
				        - (Value)(LVA(type_of(pos.moved_piece_before(m))))
			else
				// それ以外の指し手に関してはhistoryの値の順番
				m.value =     (*mainHistory)(pos.side_to_move(), from_to(m))
						  +   2* (*continuationHistory[0])(pos.moved_piece_after(m), to_sq(m))
#if defined(ENABLE_PAWN_HISTORY)
						  +   (*pawnHistory)(pawn_structure(pos), pos.moved_piece_after(m), to_sq(m))
#endif
				;


- q2
			if (pos.capture_or_promotion(m))
				// 捕獲する指し手に関しては簡易SEE + MVV/LVA
				// 被害が小さいように、LVA(価値の低い駒)を動かして取ることを優先されたほうが良いので駒に価値の低い順に番号をつける。そのためのテーブル。
				// ※ LVA = Least Valuable Aggressor。cf.MVV-LVA

				// ここ、moved_piece_before()を用いるのが正しい。
				// そうしておかないと、同じto,fromである角成りと角成らずの2つの指し手がある時、
				// moved_piece_after()だと、角成りの方は、取られた時の損失が多いとみなされてしまい、
				// オーダリング上、後回しになってしまう。

				//m.value = PieceValue[pos.piece_on(to_sq(m))] - Value(type_of(pos.moved_piece(m)))
				//		+ (1 << 28);

				// 上記のStockfishのコードのValue()は関数ではなく単にValue型へcastしているだけ。
				// 駒番号順に価値が低いと考えて(普通は成り駒ではないから)、LVAとしてそれを優先して欲しいという意味。

				m.value = Eval::CapturePieceValuePlusPromote(pos, m)
				        - Value(LVA(type_of(pos.moved_piece_before(m))))
						// ↑ここ、LVAテーブル使わずにPieceValueを64で割るとかできなくもないが、
						//  下手にやると、香と桂にような価値が近い駒に対して優先順位がつけられない。
						//   愚直にLVAテーブル使うべき。
                        + (1 << 28);
                        // ⇑これは、captureの指し手のスコアがそうでない指し手のスコアより
                        //   常に大きくなるようにするための下駄履き。
						// ※ captureの指し手の方がそうでない指し手より稀なので、この下駄履きは、
						//     captureの時にしておく。
			else
				// それ以外の指し手に関してはhistoryの値の順番
				m.value =     (*mainHistory)(pos.side_to_move(), from_to(m))
						  +   (*continuationHistory[0])(pos.moved_piece_after(m), to_sq(m))
#if defined(ENABLE_PAWN_HISTORY)
						  +   (*pawnHistory)(pawn_structure(pos), pos.moved_piece_after(m), to_sq(m))
#endif
				;

⇨ ついでだからelseの時にcontinuationHistoryに2倍しているのも変更しておく。

engine1 = YaneuraOuNNUE_V774taya-q1_1024.exe , eval = Li
engine2 = YaneuraOuNNUE_V774taya-q2_1024.exe , eval = Li
T3,b2000,1134 - 109 - 1117(50.38% R2.62[-9.42,14.67]) winrate black , white = 53.09% , 46.91%

⇨ q2、timeoutで落ちるケースがあるな…。アクセス違反あるんか? ⇨  qsearchで無限ループに入るパターンか。厄介な…。

  • V7.74taya-p

    p1

	// 王手がかかっているなら王手回避のフェーズへ。さもなくばQSEARCHのフェーズへ。
	// 歩の不成、香の2段目への不成、大駒の不成を除外

	stage = (pos.in_check() ? EVASION_TT : QSEARCH_TT) +
		!(ttm
			&& (pos.in_check() || depth > DEPTH_QS_RECAPTURES || to_sq(ttm) == recaptureSquare)
			&& pos.pseudo_legal(ttm));

⇓ p2

	// 王手がかかっているなら王手回避のフェーズへ。さもなくばQSEARCHのフェーズへ。
	stage = (pos.in_check() ? EVASION_TT : QSEARCH_TT) + !(ttm && pos.pseudo_legal(ttm));

	// ⇨ Stockfish 16のコード、ttm(置換表の指し手)は無条件でこのMovePickerが返す1番目の指し手としているが、これだと
	//    TTの指し手だけで千日手になってしまうことがある。これは、将棋ではわりと起こりうる。
	//    対策としては、qsearchで千日手チェックをしたり、SEEが悪いならskipするなど。
	//  ※ ここでStockfish 14のころのように置換表の指し手に条件をつけるのは良くなさげ。(V7.74l3 と V7.74mとの比較)
engine1 = YaneuraOuNNUE_V774taya-p1_1024.exe , eval = Li
engine2 = YaneuraOuNNUE_V774taya-p2_1024.exe , eval = Li
3,b2000,1362 - 135 - 1423(48.9% R-7.61[-18.44,3.22]) winrate black , white = 51.92% , 48.08%

⇨ この修正やるとtimeoutになることがあるなー。そうか、ttmでcapturesじゃない指し手で進めてしまうからか…。 qsearch、むずいな…。+R7ぐらい強くなるのにな…。

  • V7.74taya-o3
    • V7.74taya-o2から
    • movepick.cppでprobcutの時に置換表の指し手がpawn_promotionなら採用してるが、captureにするなら一貫性を保つためにはここcaptureじゃないと駄目。
	// ProbCutにおいて、SEEが与えられたthresholdの値以上の指し手のみ生成する。
	// (置換表の指し手も、この条件を満たさなければならない)
	// 置換表の指し手がないなら、次のstageから開始する。
	stage = PROBCUT_TT + !(ttm  && pos.capture_or_pawn_promotion(ttm)
								&& pos.pseudo_legal(ttm)
								&& pos.see_ge(ttm, threshold));
engine1 = YaneuraOuNNUE_V774taya-l_1024.exe , eval = Li
engine2 = YaneuraOuNNUE_V774taya-o3_1024.exe , eval = Li
T3,b2000,675 - 74 - 721(48.35% R-11.45[-26.75,3.85]) winrate black , white = 53.8% , 46.2%

engine1 = YaneuraOuNNUE_V774taya_1024.exe , eval = Li
engine2 = YaneuraOuNNUE_V774taya-o3_1024.exe , eval = Li
T3,b2000,269 - 27 - 284(48.64% R-9.43[-33.72,14.86]) winrate black , white = 51.72% , 48.28%

⇨ 対局回数少ないので目安程度に。
  • V7.74taya-o2
    • V7.74taya-oから。
    • movepick.cppでcapturesだけ生成してるのにrefutationでpawn_promotion除外してしまって、歩が成れなくなっているのか…。修正。
	case REFUTATION:

		// 直前に置換表の指し手を返しているし、CAPTURES_PRO_PLUSでの指し手も返しているので
		// それらの指し手は除外する。
		// 直前にCAPTURES_PRO_PLUSで生成している指し手を除外
		// pseudo_legalでない指し手以外に歩や大駒の不成なども除外
		if (select<Next>([&]() { return    *cur != MOVE_NONE
										&& !pos.capture(*cur)
										&&  pos.pseudo_legal(*cur); }))
engine1 = YaneuraOuNNUE_V774taya-l_1024.exe , eval = Li
engine2 = YaneuraOuNNUE_V774taya-o2_1024.exe , eval = Li
T3,b2000,489 - 56 - 485(50.21% R1.43[-16.88,19.73]) winrate black , white = 53.39% , 46.61%
  • V7.74taya-o
    • V7.74taya-lから。
    • movepicker.cppでcapturesはcapturesしか生成しないように変更。
		// CAPTURE_INITのあとはこのあと残りの指し手を生成する必要があるので、generate_all_legal_movesがtrueなら、CAPTURE_PRO_PLUSで歩の成らずの指し手も生成する。
		// PROBCUT_INIT、QCAPTURE_INITの時は、このあと残りの指し手を生成しないので歩の成らずを生成しても仕方がない。
#if 0
		if (stage == CAPTURE_INIT)
			endMoves = Search::Limits.generate_all_legal_moves ? generateMoves<CAPTURES_PRO_PLUS_ALL>(pos, cur) : generateMoves<CAPTURES_PRO_PLUS>(pos, cur);
		else if (stage == PROBCUT_INIT)
			endMoves = generateMoves<CAPTURES_PRO_PLUS>(pos, cur);
		else if (stage == QCAPTURE_INIT)
			// qsearchでは歩の成りは不要。駒を取る手だけ生成すれば十分。
			endMoves = generateMoves<CAPTURES>(pos, cur);
#else
			endMoves = generateMoves<CAPTURES>(pos, cur);
#endif
			//endMoves = Search::Limits.generate_all_legal_moves ? generateMoves<NON_CAPTURES_PRO_MINUS_ALL>(pos, cur) : generateMoves<NON_CAPTURES_PRO_MINUS>(pos, cur);
			endMoves = generateMoves<NON_CAPTURES>(pos, cur);
			// ⇨ NON_CAPTURES_ALL作ってなかった。あとで考える。
engine1 = YaneuraOuNNUE_V774taya-l_1024.exe , eval = Li
engine2 = YaneuraOuNNUE_V774taya-o_1024.exe , eval = Li
T3,b2000,169 - 13 - 108(61.01% R77.79[42.64,112.93]) winrate black , white = 50.54% , 49.46%
→ バグっている。o2にて修正。
  • V7.74taya-n
    • movepicker.h
  entry += bonus - entry * abs(bonus) / D;

  entry += (bonus * D - entry * abs(bonus)) / (D * 5 / 4);
に変更してみる。

engine1 = YaneuraOuNNUE_V774taya-l_1024.exe , eval = Li
engine2 = YaneuraOuNNUE_V774taya-n_1024.exe , eval = Li
T2,r300,1993 - 91 - 1936(50.73% R5.04[-4.08,14.16]) winrate black , white = 51.34% , 48.66%
→ やっぱ、これが悪い可能性があるな…。
T3,b2000,649 - 55 - 596(52.13% R14.8[-1.41,31.0]) winrate black , white = 51.89% , 48.11%
⇨ 明らかに悪そう。
  • V7.74taya-m

    • affine_transform.h
      • NNUE_FIX_OVERFLOWをdefine
      • 従来コードと等価なはず。
  • V7.74taya-l

    • V7.74taya-k より

    • movepicker.cpp

      • capturesのsortを全数ソートに
		partial_insertion_sort(cur, endMoves, -3000 * depth);
    // captureの指し手はそんなに数多くないので全数ソートで問題ないし、全数ソートした方が良い。
    partial_insertion_sort(cur, endMoves, std::numeric_limits<int>::min());
- probcutの時は、歩の不成は生成しない
- qcapturesで歩の成りは生成しないように。
		endMoves = Search::Limits.generate_all_legal_moves ? generateMoves<CAPTURES_PRO_PLUS_ALL>(pos, cur) : generateMoves<CAPTURES_PRO_PLUS>(pos, cur);

		// CAPTURE_INITのあとはこのあと残りの指し手を生成する必要があるので、generate_all_legal_movesがtrueなら、CAPTURE_PRO_PLUSで歩の成らずの指し手も生成する。
		// PROBCUT_INIT、QCAPTURE_INITの時は、このあと残りの指し手を生成しないので歩の成らずを生成しても仕方がない。
		if (stage == CAPTURE_INIT)
			endMoves = Search::Limits.generate_all_legal_moves ? generateMoves<CAPTURES_PRO_PLUS_ALL>(pos, cur) : generateMoves<CAPTURES_PRO_PLUS>(pos, cur);
		else if (stage == PROBCUT_INIT)
			endMoves = generateMoves<CAPTURES_PRO_PLUS>(pos, cur);
		else if (stage == QCAPTURE_INIT)
			// qsearchでは歩の成りは不要。駒を取る手だけ生成すれば十分。
			endMoves = generateMoves<CAPTURES>(pos, cur);
⇨ なんかファイルサイズ20KB近く縮んだ。generateMovesどれか減ったからか?
    QUICK_DRAWにしたからか?ようわからん…。あとで調べる。
⇨ quiets_check_allの生成不要になったからか…。そうか…。

engine1 = YaneuraOuNNUE_V774taya_1024.exe , eval = Li
engine2 = YaneuraOuNNUE_V774taya-l_1024.exe , eval = Li
T2,r300,2824 - 122 - 3054(48.04% R-13.6[-21.06,-6.14]) winrate black , white = 51.36% , 48.64%

engine1 = YaneuraOuNNUE_V774taya-k_1024.exe , eval = Li
engine2 = YaneuraOuNNUE_V774taya-l_1024.exe , eval = Li
T2,r300,2966 - 104 - 2930(50.31% R2.12[-5.32,9.56]) winrate black , white = 50.29% , 49.71%
T3,b2000,2003 - 229 - 2068(49.2% R-5.55[-14.5,3.41]) winrate black , white = 53.01% , 46.99%
→ 有意に強いか..
  • V7.74taya-k2
  	partial_super_sort    (cur, endMoves, - 2500 - 3000 * depth);

  	partial_super_sort    (cur, endMoves, - 1500 - 3000 * depth);

こない変更してみるか…。

engine1 = YaneuraOuNNUE_V774taya_1024.exe , eval = Li
engine2 = YaneuraOuNNUE_V774taya-k2_1024.exe , eval = Li
T2,r300,2813 - 123 - 3064(47.86% R-14.85[-22.31,-7.39]) winrate black , white = 50.28% , 49.72%
T3,b2000,2800 - 284 - 2916(48.99% R-7.05[-14.61,0.51]) winrate black , white = 52.31% , 47.69%
→ taya-kよりわずかにいいか?微差なのでよくわからんなー。Stockfishのコードよりは大きい範囲にした方が
    いいと思うので、同じような結果であるならtaya-kの方、採用しとくか…。
  • V7.74taya-k
    • movegen.cpp 丸ごと
      • 棋力に影響しないはず。
    • tt.cpp 丸ごと
      • 棋力に影響しない。
    • position.cpp 丸ごと
      • 棋力に影響しないはず。
    • Makefile 丸ごと
    • config.h 丸ごと
      • super sort使うように変更。 やねうら王側、tournamentモード以下のモードがデフォルトにした。
// トーナメント(大会)用に、対局に不要なものをすべて削ぎ落とす。
#if defined(FOR_TOURNAMENT)
	#undef ASSERT_LV
	#undef EVAL_LEARN
	#undef ENABLE_TEST_CMD
	#undef USE_GLOBAL_OPTIONS
	#undef KEEP_LAST_MOVE

	// SUPER SORT利用する
	#define USE_SUPER_SORT
	// 千日手検出を簡略化する
	#define ENABLE_QUICK_DRAW
#endif
  • search.h Stackのdepth以外丸ごと。
  • movepicker.cpp
    • supersort周りの式を以下のように変更。
#if defined(USE_SUPER_SORT) && defined(USE_AVX2)
			// SuperSortを有効にするとinsertion_sortと結果が異なるのでbenchコマンドの探索node数が変わって困ることがあるので注意。
			partial_super_sort    (cur, endMoves, - 2500 - 3000 * depth);
#else

			// TODO : このへん係数調整したほうが良いのでは…。
			// → sort時間がもったいないのでdepthが浅いときはscoreの悪い指し手を無視するようにしているだけで
			//   sortできるなら全部したほうが良い。
			partial_insertion_sort(cur, endMoves, -3000 * depth);
#endif
engine1 = YaneuraOuNNUE_V774taya_1024.exe , eval = Li
engine2 = YaneuraOuNNUE_V774taya-k_1024.exe , eval = Li
T2,r300,2720 - 121 - 3079(46.9% R-21.54[-29.05,-14.02]) winrate black , white = 50.3% , 49.7%
T3,b2000,2811 - 278 - 2911(49.13% R-6.07[-13.63,1.48]) winrate black , white = 53.57% , 46.43%

⇨ super sort、以前のパラメーターで言うと -1500 - 3000 * depth ぐらいが適切なんかな?
  • V7.74taya-j

    • movepicker.h、棋力に影響しないところだけ適用。

      • entry += と ProbCutでdepthとるのだけ適用せず。
    • movepicker.cpp、history statsの形が変わったのでその変更だけ適用。

    • thread.cpp 丸ごとコピー

      • best threadの選出アルゴリズム変更あった。
    • 探索部、history statsのところ全部修正。

      engine1 = YaneuraOuNNUE_V774taya_1024.exe , eval = Li engine2 = YaneuraOuNNUE_V774taya-j_1024.exe , eval = Li T2,r300,2653 - 98 - 3029(46.69% R-23.02[-30.62,-15.43]) winrate black , white = 50.18% , 49.82% T3,b2000,2542 - 282 - 2556(49.86% R-0.95[-8.96,7.05]) winrate black , white = 53.39% , 46.61% ⇨ 弱くはなってない&バグってはなさそう。

  • V7.74taya-i 結局、⇓こうすることにした。これで直対してみる。

	// pliesFromNullが未初期化になっていないかのチェックのためのassert
	ASSERT_LV3(st->pliesFromNull >= 0);

	// 遡り可能な手数。
	// 最大でも(root以降であっても)16手までしか遡らないことにする。
	// (これ以上遡っても千日手が見つかることが稀)
	// また、root以前にも遡る。こうした方が+R5ぐらい強くなる。

	int end = std::min(16, st->pliesFromNull);
バイナリサイズが違うのなんなんや…。
⇨ UnitTestの分か..

engine1 = YaneuraOuNNUE_V774taya_1024.exe , eval = Li
engine2 = YaneuraOuNNUE_V774taya-i_1024.exe , eval = Li
T3,b2000,1353 - 137 - 1300(51.0% R6.94[-4.15,18.04]) winrate black , white = 51.26% , 48.74%
// 途中経過。負け越してるの気持ち悪いので6000局まで回す。
T3,b2000,1839 - 188 - 1843(49.95% R-0.38[-9.79,9.04]) winrate black , white = 51.58% , 48.42%
// もう少し回したら互角ぐらいやったので、まあ良しとする。
  • V7.74taya-h
    • ENABLE_QUICK_DRAWオン

rootより遡るの自体が良くない気がしてきた。 単にこれでいいのか…。

	// 遡り可能な手数。
	// 最大でも(root以降であっても)max_repetition_ply手(=16)までしか遡らないことにする。
	// (これ以上遡っても千日手が見つかることが稀)
	// またply(rootからの手数)より遡らない。

	int end = std::min(ply, std::min(max_repetition_ply, st->pliesFromNull));
engine1 = YaneuraOuNNUE_V774taya_1024.exe , eval = Li
engine2 = YaneuraOuNNUE_V774taya-h_1024.exe , eval = Li
T3,b2000,1329 - 390 - 1341(49.78% R-1.56[-12.62,9.5]) winrate black , white = 52.92% , 47.08%

engine1 = YaneuraOuNNUE_V771a_1024.exe , eval = Li
engine2 = YaneuraOuNNUE_V774taya-h_1024.exe , eval = Li
T3,b2000,1412 - 467 - 1831(43.54% R-45.14[-55.26,-35.02]) winrate black , white = 53.44% , 46.56%

⇨ 勝率はともかく千日手率が多すぎる。rootより遡らない弊害か。


→ たややん版を見るとis_repetition()となってて16手固定となってる。
 これが案外いいんかも知れんなー。ということは、いまGitHubにあるやつと
 ほぼ同じなんちゃうの…。
  ss->ply増えても16になってるし、わりといい実装なんかも知れん…。
  8手でもええぐらいやけどな…。rootより遡らへんの、やはりあんまええことないんちゃうかな…。
  16手超えの千日手は実質存在しないので、結局、これrootより遡って千日手すべて検出してるのと
  同じ意味なんやな。

結局、V7.74taya-fの⇓この実装でいいんちゃうんかいな…。
	int end = std::min(max_repetition_ply, st->pliesFromNull);
  • V7.74taya-g
    • ENABLE_QUICK_DRAWオン

    • 以下のコード、試してみる。

	// 遡り可能な手数。
	// 最大でも(root以降であっても)max_repetition_ply手(=16)までしか遡らないことにする。
	// (これ以上遡っても千日手が見つかることが稀)
	// rootより遡るのも4手までに制限する。
	// rootよりは遡ったほうがわずかに得なので max(ply, 4)だけは遡る。

	int end = std::min(std::max(ply , 4), max_repetition_ply);
	end = std::min(end, st->pliesFromNull);
engine1 = YaneuraOuNNUE_V771a_1024.exe , eval = Li
engine2 = YaneuraOuNNUE_V774taya-g_1024.exe , eval = Li
T3,b2000,1761 - 617 - 2202(44.44% R-38.82[-47.96,-29.69]) winrate black , white = 53.87% , 46.13%
  • V7.74taya-f
    • ENABLE_QUICK_DRAWオン
	// 遡り可能な手数。
	// 最大でもmax_repetition_ply手(=16)までしか遡らないことにする。
	// rootより遡って、この手数までは調べる。(そうした方が早く千日手を見つけられてわずかに得)
	int end = std::min(max_repetition_ply, st->pliesFromNull);
こうやってroot関係なしに16手までは遡ったほうが良いのでは…。
→ それは無駄なのか…。
rootより4手遡るのは、意味あると思うので、

int end = min( max( ss->ply , 4) , 16 , st->pliesFromNull)
なのは意味あるかもなー。
  • V7.74taya-e

    • ENABLE_QUICK_DRAWがdefineされている時は、V7.70時のコードに戻した。
  • V7.74taya-d

    • ENABLE_QUICK_DRAW導入

    • Position::set_repetition_ply()追加

      if (st->repetition && st->repetition < ply) ⇓ if (st->repetition) こう変更。

      engine1 = YaneuraOuNNUE_V771a_1024.exe , eval = Li engine2 = YaneuraOuNNUE_V774taya-d_1024.exe , eval = Li T3,b2000,1127 - 353 - 1430(44.08% R-41.36[-52.74,-29.99]) winrate black , white = 53.81% , 46.19% → これ、そこまで悪くなくて、結局、V7.70とほぼ等価な動作。

  • V774taya-c

    • nnue_feature_transformer.h
      • typedefをusingに変更しただけなので影響ないはず。
    • evaluate.h
      • CapturePieceValuePlusPromote()を追加しただけなので呼び出してない段階では影響ないはず。
    • config.hの一部
      • VALUE_UNKNOWN_WINとmake_key()はまだ生かしておく。
    • movepick.h
      • 棋力に影響しない範囲で。
    • thread.h
    • thread.cpp 探索開始時のクリア以外のコード
      • best thread選出が変わるかも。

        engine1 = YaneuraOuNNUE_V771a_1024.exe , eval = Li engine2 = YaneuraOuNNUE_V774taya-c_1024.exe , eval = Li T3,b2000,1244 - 145 - 1581(44.04% R-41.64[-52.47,-30.82]) winrate black , white = 53.13% , 46.87%

  • V774taya-b

    • supersort.cpp

    • key128.h

    • benchmark.cpp

    • mate_test_cmd.cpp

    • unit_test.cpp

    • misc.h/cpp

    • thread_win32_osx.h

    • usi.h/cpp

    • usi_option.h

    • movegen.cpp

    • evaluate_bona_piece.cpp

    • tt.h/cpp

    • config.h で USE_SUPER_SORT以外

    • search.hの Stack以外。

    • 探索部でUSI::pv()の呼び出しているところ。 // 以上は棋力に影響しないはず

      engine1 = YaneuraOuNNUE_V771a_1024.exe , eval = Li engine2 = YaneuraOuNNUE_V774taya-b_1024.exe , eval = Li T3,b2000,1139 - 112 - 1379(45.23% R-33.22[-44.65,-21.78]) winrate black , white = 52.18% , 47.82%

      千日手の判定でやはり少し弱くなっている可能性が高い。 StateInfoに変数置くのがいかんのやろな…。コピーのコスト馬鹿にならへん。 以前のコード持ってくることにする。 以前のコード、repPlyまでしか遡らないので、探索浅いうちはこのほうが得なのか…。そうか…。

  • V774taya-a たややんのソースコードに最新版のやねうら王のソースコードをmergeして比較していく。

    • position.h / cpp 丸ごと差し替え。
    • bitboard.h / cpp 丸ごと差し替え。
      • least_significant_square_bb()
    • extra/sfen_packer.cpp 丸ごと差し替え
    • config.h 一部差し替え

    engine1 = YaneuraOuNNUE_V771a_1024.exe , eval = Li engine2 = YaneuraOuNNUE_V774taya-a_1024.exe , eval = Li T2,b1000,1001 - 65 - 1194(45.6% R-30.63[-42.87,-18.39]) winrate black , white = 52.67% , 47.33% T3,b2000,1164 - 138 - 1488(43.89% R-42.66[-53.84,-31.48]) winrate black , white = 52.53% , 47.47% → わずかに弱い気がする。

yaneurao — 今日 04:58
■ 千日手判定の件

rootより遡る場合は、4度目の千日手局面でのみ千日手とすることで、正しく千日手を認識でき、対局中に千日手に突入してもそれを回避する指し手をなるべく探すようになるので、下位のソフトに千日手にされにくくなると予想されます。(千日手を打開して負けることもあるので、同じぐらいの棋力のソフトとではほとんど影響がないです。)

たややんさんのGitHubのやねうら王のソースコードから、以下の4つの 6つのファイルをやねうら王のGitHubのものと入れ替えてもらえれば、上の修正がなされます。

私が計測した限り、棋力的なダウンはほとんどないみたいですが(計測上、有意差なし)、2スレ1手2秒とか極端に短い場合は、探索時に早い段階で千日手と認識できなくて枝刈りで少し損をするのでR10ぐらい下がるかも知れないです。

    
position.h / cpp 丸ごと差し替え。
bitboard.h / cpp 丸ごと差し替え。
extra/sfen_packer.cpp 丸ごと差し替え
config.h 一部差し替え
  • 作業開始
    • たややんGitHubとの比較

      engine1 = YaneuraOuNNUE_V771a_1024.exe , eval = Li engine2 = YaneuraOuNNUE_V774taya_1024.exe , eval = Li T3,b1000,2516 - 222 - 3262(43.54% R-45.11[-52.69,-37.53]) winrate black , white = 51.89% , 48.11% T3,b2000,1384 - 182 - 1714(44.67% R-37.15[-47.47,-26.83]) winrate black , white = 52.19% , 47.81% T3,b4000,753 - 107 - 890(45.83% R-29.04[-43.18,-14.89]) winrate black , white = 53.32% , 46.68%

      // 2秒、USI_Hashを512MB→2GBに変更して再計測

      engine1 = YaneuraOuNNUE_V771a_1024.exe , eval = Li engine2 = YaneuraOuNNUE_V774taya_1024.exe , eval = Li T3,b2000,2153 - 282 - 2925(42.4% R-53.23[-61.35,-45.12]) winrate black , white = 50.96% , 49.04% // ちゃんと強そう.. → 直接対決させる