
										！！！注意！！！

　　このファイルは、やねうらおの開発時のメモです。備忘をかねて実験記録等を残しています。
　　内容の正確性等は保証しませんし、また、書いてある作業予定もやねうら王の公式のアナウンスではないです。
	この文書は、誰かに伝えるために書いているわけでもないので、意味不明なことは多々あるかと思います。
	予めご了承いただければと思います。

	-----------------------------------------------------------------------------------------------


ToDo: 
・探索パラメーターの改良(2016/09/05～2016/09/10)
・技巧のソースコード調べる(2016/09/05～2016/09/10)
・mate3()書く。(2016/09/05～2016/09/10)
・評価関数に特徴追加(2016/09/10～2016/09/15)
・持ち時間制御の改良。(2016/09/10～2016/09/15)
・新やねうら王大定跡の生成(2016/09/20～2016/09/25)
・Stockfishにキャッチアップ(2016/09/25)
・Stockfishのpull req.にキャッチアップ(2016/10/01)
・最終ランニング(2016/10/01～2016/10/06)


・評価値のmin,max,分散を計算して表示したほうがいいな。
　出現回数の平均等も。


■　2016/09/04

・2016Late、g++でコンパイルが通るようにした。
	benchコマンドはg++のほうが3%ぐらい速いようだ。

・
#77
	182_20160829_62_50Gから50億局面生成。前回の182_20160901_74_40Gから追加学習。50億×2周。
		YaneuraOuV365learn150win.exe

#78
		η = 150が大きすぎる可能性…。
		η = 32ぐらいでどうなのか。
		YaneuraOuV365learn32win.exe


■　2016/09/03


・手番評価が合っているのかという問題が..
・手番だけ1/4にするの本当にいいのかどうか…。

	rmse = 0.0810652 , mean_error = 988.444
	rmse = 0.0807737 , mean_error = 988.438

	これだけにしてみる。
		kk_w[sq_bk][sq_wk].add_grad( 0 , g );

		rmse = 0.0812481 , mean_error = 985.498
		rmse = 0.0812475 , mean_error = 985.497
		rmse = 0.0812469 , mean_error = 985.497
	符号は合ってるけど動きが小さすぎ。
	eta2使うのやめたほうがいいかも。
	eta2→etaに変更。

		rmse = 0.0812471 , mean_error = 985.497
		rmse = 0.0812467 , mean_error = 985.497
		rmse = 0.0812457 , mean_error = 985.497
		rmse = 0.0812451 , mean_error = 985.498

	((Weight*)kpp_w_)[get_kpp_index(Inv(sq_wk), k1, l1)].add_grad(0 ,  +g );

		rmse = 0.0809696 , mean_error = 988.293
		rmse = 0.0805326 , mean_error = 988.611
		rmse = 0.0802162 , mean_error = 988.687

	((Weight*)kpp_w_)[get_kpp_index(Inv(sq_wk), k1, l1)].add_grad(0 ,  -g );
		rmse = 0.0825053 , mean_error = 990.759
		rmse = 0.0839705 , mean_error = 994.512
		rmse = 0.0860035 , mean_error = 999.369

	→　符号はさすがに間違ってなかった…が…。



・V3.64aで弱くなった原因調べる。
	→　cm_stats_update()呼び出してなかったのとかが関係しているのかも。
	V3.64cでV3.62より強くなっているならそれでいいや。
	パラメーターに関してはこのあと調整するしな…。

・
	engine1 = YaneuraOuV362.exe , eval = Apery20160824
	engine2 = YaneuraOuV364c.exe , eval = Apery20160824
	T1,r300,2466 - 70 - 2734(47.42% R-17.92)

・学習、教師局面が足りてない可能性はあるわな…。うーむ..。
	depth3で30億さらに生成して、50億で学習回してみるか？

	engine1 = YaneuraOuV362.exe , eval = 182_20160901_74_40G
	engine2 = YaneuraOuV362.exe , eval = 182_20160829_62_50G
	T1,b5000,1474 - 123 - 1543(48.86% R-7.95)

・その前にAperyWCSC26からの学習、一応再度テストしておくか。
	AperyWCSC26からdepth3で生成。5億局面。20160903d3_ap.bin

	#76
		// 5億局面×1周
		engine1 = YaneuraOuV362.exe , eval = 182_20160903_76_05G
		engine2 = YaneuraOuV362.exe , eval = Apery20160505
		T1,b3000,1534 - 77 - 1389(52.48% R17.25)

		// 5億局面×3周
		engine1 = YaneuraOuV362.exe , eval = 182_20160903_76_15G
		engine2 = YaneuraOuV362.exe , eval = Apery20160505
		T1,b3000,1231 - 63 - 1006(55.03% R35.06)

	5億×1周では全然収束してないな…。mini-batchのサイズ大きすぎる可能性はなくはない。
	ともかく強くなっていることはわかった。


■　2016/09/02

・探索部改良
	V3.64a
		Refutation penalty on captures	
		https://github.com/official-stockfish/Stockfish/commit/0b4f6e562b76a7a7fb581ad117927748371fe790

		Reformat stats update
		https://github.com/official-stockfish/Stockfish/commit/3e739f883fb766f965ed434507c9c8fbcf18a855

		Simplify stats update
		https://github.com/official-stockfish/Stockfish/commit/9bd856e28ec93a16a5db78b24f9579c607541def
		
		engine1 = YaneuraOuV362.exe , eval = Apery20160824
		engine2 = YaneuraOuV364a.exe , eval = Apery20160824
		T1,r300,4727 - 162 - 5111(48.05% R-13.57)
		T1,b3000,1524 - 96 - 1380(52.48% R17.24)

		engine1 = YaneuraOuV364a.exe , eval = Apery20160824
		engine2 = YaneuraOuV362.exe , eval = Apery20160824
		T1,b3000,1366 - 94 - 1540(47.01% R-20.83)

		// やばい。長い時間で弱くなっている。原因調べる(´ω｀)
		
	V3.64b
		Make engine ONE_PLY value independent
		https://github.com/official-stockfish/Stockfish/commit/4c5cbb1b14b283679e3e0096b7973c97b75088f3

		Silence some warnings with MSVC 2013
		https://github.com/official-stockfish/Stockfish/commit/0b944c718631cdbdd8fae46eaf96a099f48ad5a4

		Optimize order of a few conditions in search
		https://github.com/official-stockfish/Stockfish/commit/5cffc032da8402df79cf6cba4238b83ff5d29f7e

		Remove condition on killers in history pruning
		https://github.com/official-stockfish/Stockfish/commit/2731bbaf6b4bed23abaae8de5c1fa9f373e30e57

		engine1 = YaneuraOuV364a.exe , eval = Apery20160824
		engine2 = YaneuraOuV364b.exe , eval = Apery20160824
		T1,r300,4898 - 200 - 4902(49.98% R-0.14)
		// この改造では何も壊していない。

	V3.64c
		Tweak probcut threshold
		https://github.com/official-stockfish/Stockfish/commit/6aa9308f08bc76b0e3615dde65de7782a6761fa3

		// これはいい改造の予感。

		Move CheckInfo under StateInfo
		https://github.com/official-stockfish/Stockfish/commit/805afcbf3d5db39c85b759232cfb99ab0a250311
		→　いまごろになってやっとCheckInfoをStateInfoに隠匿するのか。遅すぎ。
		→　これ大改造になるな…。

		Retire CheckInfo
		https://github.com/official-stockfish/Stockfish/commit/1ee2838214fcbadc352fb17c8c6fa1142ae5dcb0


		// これもはや、不要なのか…。うーむ..
		enum CheckInfoUpdate
		{
		  CHECK_INFO_UPDATE_NONE,           // 何もupdateされていない状態
		  CHECK_INFO_UPDATE_ALL,            // 以下の2つともupdate
		  CHECK_INFO_UPDATE_PINNED,         // pinnedの情報だけupdate
		  CHECK_INFO_UPDATE_WITHOUT_PINNED, // pinned以外の情報だけupdate
		};
		→　大改造の予感。

	  // 自分側(手番側)の(敵駒によって)pinされている駒
	  Bitboard pinned;
		→　blockersForKing

	  // 自駒の駒種Xによって敵玉が王手となる升のbitboard
	  Bitboard checkSq[PIECE_WHITE];
		→　checkSquares

	→　大改造になった。
	→　legal_drop()が少し簡単化できた。

	// 与えられた3升が縦横斜めの1直線上にあるか。駒を移動させたときに開き王手になるかどうかを判定するのに使う。
	// 例) 王がsq1, pinされている駒がsq2にあるときに、pinされている駒をsq3に移動させたときにaligned(sq1,sq2,sq3)であれば、
	//  pinされている方向に沿った移動なので開き王手にはならないと判定できる。
	// ただし玉はsq3として、sq1,sq2は同じ側にいるものとする。(玉を挟んでの一直線は一直線とはみなさない)
	inline bool aligned(Square sq1, Square sq2, Square sq3/* is ksq */)
	{
		auto d1 = Effect8::directions_of(sq1, sq2);
		return d1 ? d1 == Effect8::directions_of(sq1, sq3) : false;
	}
	→　これ2回テーブルを引くので言うほど速くない気がしてきた。まあいいか…。

	・これ、元のコードがバグっている可能性が微レ存。
				case DIRECT_U: case DIRECT_D:
					st->checkersBB |= rookEffectFile(from, pieces()) & pieces(Us); break;


				 香
				^玉

				 
				 角
				 香

		こういうときに誤って上の香を足してないか？
		ああ、fromだからいいのか..そうか。

		→　random playerでのテストは通ったが、benchが通らない。
		→　do_null_move()でset_check_info()が要るのか…。うーむ..
		→　bench通った。最適化はあとで考えようか…。

		===========================
		Total time (ms) : 81136
		Nodes searched  : 48509614
		Nodes/second    : 597880

		→　set_check_info()、null_move()のとき処理を分離した。ベンチ通った。

		===========================
		Total time (ms) : 75429
		Nodes searched  : 48509614
		Nodes/second    : 643116

		テスト関連のコード。
			if (st->checkersBB != attackers_to(Us, king_square(~Us)))
			{
				cout << *this << st->checkersBB << attackers_to(Us, king_square(~Us)) << m << endl << prevSt->blockersForKing[~Us];

				Bitboard pinned = prevSt->blockersForKing[~Us] & from;
				if (discovered(from, to, ksq, pinned))
				{
					cout << "DISCOVERED";
				} else {
					cout << prevSt->checkSquares[type_of(moved_after_pc)];
					cout << (prevSt->checkSquares[type_of(moved_after_pc)] & to);
					cout << st->checkersBB;
					st->checkersBB = prevSt->checkSquares[type_of(moved_after_pc)] & to;
					cout << st->checkersBB;
				}
				cout <<  pinned 
					<<
					(pinned & from)               // 2)
					<< !aligned(from, to, ksq); // 3)
				cout << pinned
					<<
					(pinned & from)               // 2)
					<< !aligned(from, to, ksq); // 3)

			}

		engine1 = YaneuraOuV364b.exe , eval = Apery20160824
		engine2 = YaneuraOuV364c.exe , eval = Apery20160824
		T1,b3000,1407 - 97 - 1496(48.47% R-10.65)

		→　これは強くなっているようだが？

	V3.64d forked from V3.64c

					Value futilityValue = futilityBase + (Value)CapturePieceValue[pos.piece_on(to_sq(move))];
		-		//	+ (is_promote(move) ? (Value)ProDiffPieceValue[pos.piece_on(move_from(move))] : VALUE_ZERO);

		これないほうが良いのでは..

			engine1 = YaneuraOuV364c.exe , eval = Apery20160824
			engine2 = YaneuraOuV364d.exe , eval = Apery20160824
			T1,b1000,4947 - 256 - 4797(50.77% R5.35)
			T1,b3000,2416 - 183 - 2401(50.16% R1.08)

		→　そうでもなかった…。


	V3.64e forked from V3.64d
			以下のところ、see()に変更してみる。
				// ToDo: pos.see(move) <= VALUE_ZEROのほうが良い可能性。
				if (futilityBase <= alpha && pos.see_sign(move) <= VALUE_ZERO)
				{
					bestValue = std::max(bestValue, futilityBase);
					continue;
				}

		engine1 = YaneuraOuV364d.exe , eval = Apery20160824
		engine2 = YaneuraOuV364e.exe , eval = Apery20160824
		T1,b1000,4941 - 284 - 4775(50.85% R5.94)
		→　弱くなった？

		engine1 = YaneuraOuV364d.exe , eval = Apery20160824
		engine2 = YaneuraOuV364e.exe , eval = Apery20160824
		T1,b3000,1422 - 121 - 1457(49.39% R-4.22)
		T1,b3000,2404 - 212 - 2384(50.21% R1.45)
			3826-333-3841

	V3.64f forked form V3.64c

		// 除外した指し手をxorしてそのままhash keyに使う。
		// 除外した指し手がないときは、0だから、xorしても0。
		// ただし、hash keyのbit0は手番を入れることになっているのでここはクリアしておく。
		auto posKey = pos.key() ^ Key(excludedMove << 1);

		こうしたほうがいいな。

		tte->eval()要らんのちゃう？
		→　うーん。難しい。

	V3.64g forked form V3.64f

		PARAM_REDUCTION_BY_HISTORYを8000→10000に戻してテスト

			engine1 = YaneuraOuV362.exe , eval = Apery20160824
			engine2 = YaneuraOuV364g.exe , eval = Apery20160824
			T1,b3000,1408 - 92 - 1500(48.42% R-11.0)

		やはり、このへんが肝のようだが…。




■　2016/09/01

・学習のイテレーションを安定して回せる状態にする(～2016/09/03)

・
	#62(182_20160829_62_50G)からdepth3で10,20億局面を生成。182_20160829_62_50Gから追加学習。
	EVAL_LIMIT = VALUE_INFINITE
	目的関数 = LOSS_FUNCTION_IS_WINNING_PERCENTAGE
	//	Weight::eta = 100.0f * (float)pow(0.999f, epoch);

	#69..10億局面 minibatch = 100万局面
	#70..10億局面 minibatch = 500万局面
	#71..10億局面 minibatch = 200万局面
	#72..20億局面 minibatch = 100万局面
	#73..20億局面 minibatch = 100万局面 , ηの減衰なし。η=100
		YaneuraOuV363learn_win.exe
		//	Weight::eta = 100.0f;

	#74..20億局面 minibatch = 100万局面 , ηの減衰なし。η=150
		YaneuraOuV363learn150win.exe
		//  Weight::eta = 150.0f;

	#75..10億局面 minibatch = 100万局面 ただし、depth6で生成した教師局面10億局面
		学習方法は、#74と同じ。
	

	実験結果)
	#69
		engine1 = YaneuraOuV362.exe , eval = 182_20160829_62_50G
		engine2 = YaneuraOuV362.exe , eval = 182_20160829_69_20G
		T1,r300,4888 - 156 - 4956(49.65% R-2.4)
		T1,b3000,1470 - 100 - 1430(50.69% R4.79)
		// 元のバージョンより弱い可能性が。よくわからない。

		engine1 = YaneuraOuV362.exe , eval = 182_20160829_69_10G
		engine2 = YaneuraOuV362.exe , eval = 182_20160829_69_20G
		T1,b3000,1434 - 102 - 1464(49.48% R-3.6)

		// 10Gではまだ収束していない可能性がある。
		// rmse自体はまだ下がり続けている。
		// きちんと棋力が伸びなくなる限界まで回さないと雑巾が絞りにくいのでは。
		// →　η、減衰しないほうと比較実験などをする。

		#69のrmse推移
		rmse = 0.070048 , mean_error = 985.541  //  0億
		rmse = 0.0691731 , mean_error = 988.378 // 10億
		rmse = 0.0689261 , mean_error = 989.072 // 20億

		#73のrmse推移
		rmse = 0.0701574 , mean_error = 984.905 //  0億
		rmse = 0.0689784 , mean_error = 989.425 // 10億
		rmse = 0.0686712 , mean_error = 990.957 // 20億
		rmse = 0.0678776 , mean_error = 991.066 // 30億

		// →　#73の10億時点で#69の20億ぐらいの感じか。


		// Aperyとの比較

		engine1 = YaneuraOuV362.exe , eval = 182_20160829_69_20G
		engine2 = YaneuraOuV362.exe , eval = Apery20160824
		T1,b3000,1431 - 37 - 1532(48.3% R-11.85)

	#70
		engine1 = YaneuraOuV362.exe , eval = 182_20160829_62_50G
		engine2 = YaneuraOuV362.exe , eval = 182_20160829_70_20G
		T1,r300,4912 - 151 - 4937(49.87% R-0.88)
		T1,b3000,1480 - 95 - 1425(50.95% R6.58) // 収束していない。前バージョンより少し弱い。

		// 10Gと20Gとの比較

		engine1 = YaneuraOuV362.exe , eval = 182_20160829_70_10G
		engine2 = YaneuraOuV362.exe , eval = 182_20160829_70_20G
		T1,b3000,1416 - 111 - 1473(49.01% R-6.86)

	#71
		// Aperyと
		engine1 = YaneuraOuV362.exe , eval = 182_20160829_71_20G
		engine2 = YaneuraOuV362.exe , eval = Apery20160824
		T1,r300,5082 - 79 - 4839(51.22% R8.51)

		engine1 = YaneuraOuV362.exe , eval = 182_20160829_62_50G
		engine2 = YaneuraOuV362.exe , eval = 182_20160829_71_20G
		T1,b3000,1544 - 110 - 1346(53.43% R23.84) // 収束してない。前バージョンよりR23も弱い

	#72
		// #69と#72との比較

		engine1 = YaneuraOuV362.exe , eval = 182_20160829_69_20G
		engine2 = YaneuraOuV362.exe , eval = 182_20160901_72_20G
		T1,r300,4921 - 147 - 4932(49.94% R-0.39)
		T1,b3000,1447 - 93 - 1460(49.78% R-1.55)

		// →　教師、10億局面と20億局面とで差がほぼ無いかも…。

		engine1 = YaneuraOuV362.exe , eval = 182_20160829_69_20G
		engine2 = YaneuraOuV362.exe , eval = 182_20160901_72_40G
		T1,r300,5024 - 135 - 4841(50.93% R6.45)
		T1,b3000,1472 - 112 - 1416(50.97% R6.74)

		// →　むしろ弱くなってるような…？		

		engine1 = YaneuraOuV362.exe , eval = 182_20160901_72_40G
		engine2 = YaneuraOuV362.exe , eval = Apery20160824
		T1,b3000,1407 - 33 - 1560(47.42% R-17.93)

		// →　弱くなってるような？

	#73

		// #69,#73の比較
		engine1 = YaneuraOuV362.exe , eval = 182_20160829_69_20G
		engine2 = YaneuraOuV362.exe , eval = 182_20160901_73_20G
		T1,r300,4909 - 153 - 4938(49.85% R-1.02)
		T1,b3000,1432 - 102 - 1466(49.41% R-4.08)
		T1,b3000,1419 - 95 - 1486(48.85% R-8.01)

		// η、減衰しないほうがよさげ。

		// Aperyとの比較

		engine1 = YaneuraOuV362.exe , eval = 182_20160901_73_50G
		engine2 = YaneuraOuV362.exe , eval = Apery20160824
		T1,b3000,2391 - 68 - 2541(48.48% R-10.57)

	#74

		// #69と#74との比較

		engine1 = YaneuraOuV362.exe , eval = 182_20160829_69_20G
		engine2 = YaneuraOuV362.exe , eval = 182_20160901_74_20G
		T1,r300,4872 - 141 - 4987(49.42% R-4.05)
		T1,b3000,1437 - 99 - 1464(49.53% R-3.23)

		// #73と#74との比較

		engine1 = YaneuraOuV362.exe , eval = 182_20160901_73_20G
		engine2 = YaneuraOuV362.exe , eval = 182_20160901_74_20G
		T1,b3000,1972 - 118 - 1930(50.54% R3.74)
		// →　大差なし？

		engine1 = YaneuraOuV362.exe , eval = 182_20160901_73_50G
		engine2 = YaneuraOuV362.exe , eval = 182_20160901_74_40G
		T1,b3000,2256 - 153 - 2311(49.4% R-4.18)
		// #74のほうが優れていると言えそう。

		// 20Gと40Gとの比較

		engine1 = YaneuraOuV362.exe , eval = 182_20160901_74_20G
		engine2 = YaneuraOuV362.exe , eval = 182_20160901_74_40G
		T1,b3000,2386 - 173 - 2441(49.43% R-3.96)

		// #74ですら20Gでは収束していないっぽい。
		// 40G回さないと駄目か…。

	#75

		engine1 = YaneuraOuV362.exe , eval = 182_20160829_69_20G
		engine2 = YaneuraOuV362.exe , eval = 182_20160901_75_10G
		T1,b3000,1587 - 97 - 1506(51.31% R9.1)
		// → 収束が十分でなさげ。弱い。

		engine1 = YaneuraOuV362.exe , eval = 182_20160829_62_50G
		engine2 = YaneuraOuV362.exe , eval = 182_20160901_75_20G
		T1,b3000,772 - 51 - 727(51.5% R10.43)
		T1,b3000,2447 - 156 - 2397(50.52% R3.59)
		// → 20G時点でも元の評価関数より強くなっているかも謎。

		// #74との比較
		engine1 = YaneuraOuV362.exe , eval = 182_20160901_74_40G
		engine2 = YaneuraOuV362.exe , eval = 182_20160901_75_30G
		T1,r300,4935 - 135 - 4930(50.03% R0.18)
		T1,b3000,2426 - 162 - 2392(50.35% R2.45)
		→　depth3の教師と変わらないなら、depth6意味ないことになるが…。
		
		// Aperyとの比較

		engine1 = YaneuraOuV362.exe , eval = 182_20160901_75_10G
		engine2 = YaneuraOuV362.exe , eval = Apery20160824
		T1,b3000,1862 - 64 - 1994(48.29% R-11.9)

		engine1 = YaneuraOuV362.exe , eval = 182_20160901_75_20G
		engine2 = YaneuraOuV362.exe , eval = Apery20160824
		T1,r300,4826 - 79 - 4495(51.78% R12.34)
		T1,b3000,466 - 6 - 508(47.84% R-14.99) // 対局数少なめ

		engine1 = YaneuraOuV362.exe , eval = 182_20160901_75_30G
		engine2 = YaneuraOuV362.exe , eval = Apery20160824
		T1,r300,5100 - 83 - 4817(51.43% R9.92)
		T1,b3000,2393 - 81 - 2526(48.65% R-9.4)

	・mini batchサイズの変更は明らかに弱い。収束が十分でないのだろう。
		十分に時間をかけた場合、どちらが良いかはよくわからない。
		#71のほうがmini batchサイズが小さいのに、#70のほうが勝率が良さそうであるが、
		単に値が動いていないから前のバージョンからあまり弱くなっていないだけかも。

	・depth6で教師局面を生成したほう、収束が遅いように思う。
		教師が元のものからかけ離れているからか？
		depth3と大差ないならdepth3で回したほうが良いのではないか？


■　2016/08/31


・mini-batchサイズの違いによる学習の差を計測してみる実験。
	100万と500万とで比較。

・10億をflowで生成するJenkinsのJob書いた。

		// build number
		def bn = build.getEnvironment(listener).get('BUILD_NUMBER')  

		// parallel number
		def pn = params["PARA_NUM"].toInteger()

		def builds = []
		for(int i=0;i<pn;++i)
		{
		  // ここでjにコピーして、これをclosureに束縛させる。
		  int j=i
		  builds.add( { -> build("yanejob/教師局面ファイル生成flow",SFEN_FILENAME:"ALN_"+bn+"_" + j.toString() +".bin",
								 DEPTH: params["DEPTH"], LOOP_MAX: params["SFEN_LOOP"] , EVAL_DIR : params["EVAL_DIR"] , EVAL_LIMIT : "32001") })
		}
		parallel(builds)  

・depth3で生成するの、イテレーションが早くまわるように見えて、その後の強くなったかどうかの検証で
　こんなに時間かかると何やってるかわからんな…。


■　2016/08/30

・pythonスクリプトに、自己対局のときに評価値つきの棋譜を残す機能追加。
	→　さらに評価値も出力させるように変更。


■　2016/08/29

・
	教師a)
	182_20160828_56_10G(182_20160824よりわずかに強い？)でdepth3で10億局面生成。
	→　194.bin 195.bin 196.bin 197.bin

	教師b)
	Apery20160824からdepth3で10億局面生成
	→　198.bin 199.bin 200.bin 201.bin

	千日手、優等・劣等局面の判定なしで教師局面を生成。

	学習局面数
	10G..10億局面×1周
	20G..10億局面×2周
	30G..10億局面×3周

	EVAL_LIMIT = VALUE_INFINITE
	目的関数 = LOSS_FUNCTION_IS_WINNING_PERCENTAGE
	
	#62
		182_20160828_56_10Gから追加学習。教師a)
		YaneuraOuV361learn999win.exe

	#63 比較実験
		Apery20160824から追加学習。教師b)
		YaneuraOuV361learn999win.exe

	#64
		182_20160828_56_10Gから追加学習。教師b)
		YaneuraOuV361learn999win.exe

	#65 比較実験
		Apery20160824から追加学習。教師b)
		YaneuraOuV361learn999win.exe

	#66 比較実験
		#63で10億×5周させたものから追加学習。教師b)
		YaneuraOuV361learn999win.exe

	戦績)
	#62
		engine1 = YaneuraOuV362.exe , eval = 182_20160824
		engine2 = YaneuraOuV362.exe , eval = 182_20160829_62_10G
		play_time = r300 ,  T1,r300,4834 - 136 - 5030(49.01% R-6.9)

		engine1 = YaneuraOuV362.exe , eval = 182_20160824
		engine2 = YaneuraOuV362.exe , eval = 182_20160829_62_20G
		play_time = r300 ,  T1,r300,4892 - 132 - 4976(49.57% R-2.96)

		engine1 = YaneuraOuV362.exe , eval = 182_20160824
		engine2 = YaneuraOuV362.exe , eval = 182_20160829_62_30G
		play_time = r300 ,  T1,r300,4878 - 136 - 4986(49.45% R-3.8)

		engine1 = YaneuraOuV362.exe , eval = 182_20160824
		engine2 = YaneuraOuV362.exe , eval = 182_20160829_62_40G
		play_time = r300 ,  T1,r300,4897 - 138 - 4965(49.66% R-2.4)

		engine1 = YaneuraOuV362.exe , eval = 182_20160824
		engine2 = YaneuraOuV362.exe , eval = 182_20160829_62_50G
		play_time = r300 ,  T1,r300,4842 - 128 - 5030(49.05% R-6.62)

		// Aperyとの比較

		engine1 = YaneuraOuV362.exe , eval = 182_20160829_62_40G
		engine2 = YaneuraOuV362.exe , eval = Apery20160824
		play_time = r300 ,  T1,r300,5200 - 96 - 4704(52.5% R17.41)

		engine1 = YaneuraOuV362.exe , eval = 182_20160829_62_40G
		engine2 = YaneuraOuV362.exe , eval = Apery20160824
		play_time = b1000 ,  T1,b1000,2445 - 63 - 2492(49.52% R-3.31)

		engine1 = YaneuraOuV362.exe , eval = 182_20160829_62_50G
		engine2 = YaneuraOuV362.exe , eval = Apery20160824
		r300 ,  T1,r300,5154 - 82 - 4764(51.97% R13.67)
		b1000 ,  T1,b1000,2446 - 62 - 2492(49.53% R-3.24)
		T1,b3000,1426 - 54 - 1520(48.4% R-11.09)
		→ 長い持ち時間で勝敗が逆転しているが、前バージョンよりはAperyに対する勝率が上がっていると言えそう。

		// #56と62との比較

		engine1 = YaneuraOuV362.exe , eval = 182_20160828_56_10G
		engine2 = YaneuraOuV362.exe , eval = 182_20160829_62_10G
		T1,b1000,2400 - 113 - 2487(49.11% R-6.19)

	#63
		engine1 = YaneuraOuV362.exe , eval = 182_20160824
		engine2 = YaneuraOuV362.exe , eval = 182_20160829_63_10G
		play_time = r300 ,  T1,r300,4541 - 105 - 5354(45.89% R-28.61)

		engine1 = YaneuraOuV362.exe , eval = 182_20160824
		engine2 = YaneuraOuV362.exe , eval = 182_20160829_63_20G
		play_time = r300 ,  T1,r300,4641 - 96 - 5263(46.86% R-21.85)

		engine1 = YaneuraOuV362.exe , eval = 182_20160824
		engine2 = YaneuraOuV362.exe , eval = 182_20160829_63_30G
		play_time = r300 ,  T1,r300,4526 - 94 - 5380(45.69% R-30.03)

		engine1 = YaneuraOuV362.exe , eval = 182_20160824
		engine2 = YaneuraOuV362.exe , eval = 182_20160829_63_40G
		play_time = r300 ,  T1,r300,4651 - 93 - 5256(46.95% R-21.24)

		engine1 = YaneuraOuV362.exe , eval = 182_20160824
		engine2 = YaneuraOuV362.exe , eval = 182_20160829_63_50G
		play_time = r300 ,  T1,r300,4690 - 83 - 5227(47.29% R-18.83)

		// Aperyとの比較

		engine1 = YaneuraOuV362.exe , eval = 182_20160829_63_10G
		engine2 = YaneuraOuV362.exe , eval = Apery20160824
		play_time = r300 ,  T1,r300,5529 - 123 - 4348(55.98% R41.74)
		play_time = b1000 ,  T1,b1000,2645 - 97 - 2258(53.95% R27.48)

		engine1 = YaneuraOuV362.exe , eval = 182_20160829_63_20G
		engine2 = YaneuraOuV362.exe , eval = Apery20160824
		play_time = b1000 ,  T1,b1000,2665 - 94 - 2241(54.32% R30.1)

		engine1 = YaneuraOuV362.exe , eval = 182_20160829_63_40G
		engine2 = YaneuraOuV362.exe , eval = Apery20160824
		play_time = b1000 ,  T1,b1000,2692 - 66 - 2242(54.56% R31.78)

		engine1 = YaneuraOuV362.exe , eval = 182_20160829_63_50G
		engine2 = YaneuraOuV362.exe , eval = Apery20160824
		play_time = r300 ,  T1,r300,5468 - 111 - 4421(55.29% R36.92)
		play_time = b1000 ,  T1,b1000,2678 - 91 - 2231(54.55% R31.72)
		play_time = b5000 ,  T1,b5000,998 - 49 - 953(51.15% R8.02)
		play_time = b10000 ,  T1,b10000,983 - 69 - 948(50.91% R6.3)
		→　長い持ち時間だと差が縮まる傾向にある。

	#64
		engine1 = YaneuraOuV362.exe , eval = 182_20160824
		engine2 = YaneuraOuV362.exe , eval = 182_20160829_64_10G
		T1,r300,4845 - 153 - 5002(49.2% R-5.54)

		engine1 = YaneuraOuV362.exe , eval = 182_20160824
		engine2 = YaneuraOuV362.exe , eval = 182_20160829_64_20G
		T1,r300,4873 - 125 - 5002(49.35% R-4.54)

		// Aperyとの比較
		engine1 = YaneuraOuV362.exe , eval = 182_20160829_64_20G
		engine2 = YaneuraOuV362.exe , eval = Apery20160824
		T1,b3000,1409 - 70 - 1521(48.09% R-13.29)
		T1,b5000,968 - 32 - 1000(49.19% R-5.65)


	#65
		engine1 = YaneuraOuV362.exe , eval = 182_20160824
		engine2 = YaneuraOuV362.exe , eval = 182_20160829_65_10G
		T1,r300,4493 - 95 - 5412(45.36% R-32.33)

		engine1 = YaneuraOuV362.exe , eval = 182_20160824
		engine2 = YaneuraOuV362.exe , eval = 182_20160829_65_20G
		T1,r300,4568 - 129 - 5303(46.28% R-25.92)

		// Aperyとの比較

		engine1 = YaneuraOuV362.exe , eval = 182_20160829_65_20G
		engine2 = YaneuraOuV362.exe , eval = Apery20160824
		T1,b5000,998 - 62 - 940(51.5% R10.4)

	#66
		engine1 = YaneuraOuV362.exe , eval = 182_20160824
		engine2 = YaneuraOuV362.exe , eval = 182_20160829_66_10G
		T1,r300,4538 - 104 - 5358(45.86% R-28.86)

		engine1 = YaneuraOuV362.exe , eval = 182_20160824
		engine2 = YaneuraOuV362.exe , eval = 182_20160829_66_20G
		T1,r300,4554 - 101 - 5345(46.0% R-27.82)

	#62と#64、#64と#65、#65と#66の比較

		engine1 = YaneuraOuV362.exe , eval = 182_20160829_62_50G
		engine2 = YaneuraOuV362.exe , eval = 182_20160829_64_10G
		T1,b3000,1091 - 84 - 1215(47.31% R-18.7)

		engine1 = YaneuraOuV362.exe , eval = 182_20160829_64_10G
		engine2 = YaneuraOuV362.exe , eval = 182_20160829_65_10G
		T1,r300,4506 - 89 - 5405(45.46% R-31.6)
		T1,b1000,2229 - 78 - 2693(45.29% R-32.85)
		T1,b5000,663 - 28 - 859(43.56% R-44.99)

		engine1 = YaneuraOuV362.exe , eval = 182_20160829_65_20G
		engine2 = YaneuraOuV362.exe , eval = 182_20160829_66_20G
		T1,b1000,2441 - 119 - 2440(50.01% R0.07)

		// Aperyとの比較
				
		engine1 = YaneuraOuV362.exe , eval = 182_20160829_66_20G
		engine2 = YaneuraOuV362.exe , eval = Apery20160824
		T1,b5000,1031 - 47 - 922(52.79% R19.41)

	182_20160828_56_10Gの強さを示す予備データ) 
		長い持ち時間ではApery20160824より-R10程度弱いようだ。(短い時間では勝っていたのに…。)

		engine1 = YaneuraOuV360.exe , eval = 182_20160824
		engine2 = YaneuraOuV360.exe , eval = 182_20160828_56_10G
		play_time = b1000 ,  T1,b1000,2450 - 105 - 2445(50.05% R0.35)

		engine1 = YaneuraOuV360.exe , eval = 182_20160824
		engine2 = YaneuraOuV360.exe , eval = 182_20160828_56_10G
		play_time = b3000 ,  T1,b3000,949 - 65 - 986(49.04% R-6.64)

		engine1 = YaneuraOuV360.exe , eval = Apery20160824
		engine2 = YaneuraOuV360.exe , eval = 182_20160828_56_10G
		play_time = b1000 ,  T1,b1000,2516 - 81 - 2403(51.15% R7.98)

		engine1 = YaneuraOuV360.exe , eval = Apery20160824
		engine2 = YaneuraOuV360.exe , eval = 182_20160828_56_10G
		play_time = b3000 ,  T1,b3000,1510 - 46 - 1444(51.12% R7.76)

		engine1 = YaneuraOuV360.exe , eval = Apery20160824
		engine2 = YaneuraOuV360.exe , eval = 182_20160828_56_10G
		T1,b6000,747 - 32 - 701(51.59% R11.04)

	結論)
		・0.3秒対局において、#63は元の評価関数から強くなった(Apery20160824に+R40であることからも明らか)。
		・0.3秒対局においても、#62は元の評価関数からほとんど強くならない。(雑巾絞れない現象)
		・Aperyの評価関数は終盤の特徴因子に適切な点数がついていなくて、そこに適切な点数がついたがために
		若干強くなったのだと考えられる。
		・この手法、10億局面学習した時点で棋力的にはおおよそ収束していると見てよさそう。
		・短い持ち時間の棋譜を確認したが、すぐに終盤に突入するので終盤の特徴に加点されていると
		勝率が上がるのも無理はなさげ。(長い持ち時間ではこのような加点はむしろマイナスになることが多い)
		・Apery20160824からdepth3で生成した教師から学習させたのに、#64は元の教師より-R30ぐらい弱い。
		　元が弱いからだが、異なる評価関数からではあまりうまく学習できていない印象。
		・#65は、Aperyより弱い評価関数でdepth3で生成した教師から学習したのに、元の評価関数より強くなっている。
		　終盤の特徴が何らか強化されたからだろうか？
		
		検証) depth3の教師から雑巾が絞れているか？
			#56と#62との比較から、元の評価関数より強いので絞れていると言えそう。
			(終盤が強化されただけかも知れない)
			depth3で教師生成→学習を繰り返してみるのはアリかも知れない。
			
		検証) 異なる評価関数であっても、強いほうの教師から学習させたほうが良いか？
			#62→#64で少し強くなっているようではある。
			教師を超える強さにはなっていないことから、異なる評価関数の教師による学習は
			あまりよろしくないのではないかと思う。
		
			Aperyの評価関数に対して別の評価関数を教師にして学習させた#63は元のAperyの評価関数より
		　強くなっているように見えたが、その後、Aperyを教師にして学習させた#63→#66は、結局は#65と
		　同じ強さであったことから、#63は終盤が強化されていただけの可能性がある。

		・教師を生成した評価関数が違うとよろしくないというのは真実っぽい。
			目的関数が交差エントロピーでやるとまた違うのかも知れないが…。



・Apery20160824からdepth3で10億局面生成。


・depth3 , EVAL_LIMIT=VALUE_INFINITEである場合、1億局面の生成に1:40:00


・教師局面生成時に千日手局面に突入したらその対局を終了するように変更。

#if 1
		// 何らかの千日手局面に突入したので局面生成を終了する。
		auto draw_type = pos.is_repetition();
		if (draw_type != REPETITION_NONE)
			break;
#endif


・思ったほど戦績よくないな…。ともかく、これでdepth3で作った教師で学習回す。



■　2016/08/28

・eta2修正後。

	#49 ... YANE_SGD_UPDATE、交差エントロピー , Weight::eta = 32.0f * (float)pow(0.998f, epoch);
		// YaneuraOuV361learn998.exe
		// EVAL_LIMIT = 20000(11億局面) + 2000(8億局面)

	#50 ... YANE_SGD_UPDATE、交差エントロピー , Weight::eta = 100.0f * (float)pow(0.997f, epoch);
		// YaneuraOuV361learn997.exe
		// EVAL_LIMIT = 20000(11億局面) + 2000(8億局面)

	#51 ... #50と同じだが、EVAL_LIMTE = 20000のみ9億局面
		// YaneuraOuV361learn997.exe

	#52 ... #49と同じだが、EVAL_LIMIT =  20000(2億局面) + 2000(8億局面)
		// YaneuraOuV361learn998.exe

	#56 ... #51と同じだがLOSS_FUNCTION_IS_WINNING_PERCENTAGE
	#57 ... %52と同じだがLOSS_FUNCTION_IS_WINNING_PERCENTAGE
		//	Weight::eta = 100.0f * (float)pow(0.999f, epoch);
		//	YaneuraOuV360learn999win.exe

	※　07G = 0.7Gの意味
	07G ...  7億局面
	10G ... 10億局面
	20G ... 20億局面
	30G ... 30億局面
	…

	engine1 = YaneuraOuV360.exe , eval = 182_20160824

	# 49

	engine2 = YaneuraOuV360.exe , eval = 182_20160828_49_07G
	play_time = r300 ,  T1,r300,4899 - 148 - 4953(49.73% R-1.9) //　η低めで前のが平均化された影響？
	play_time = b1000 ,  T1,b1000,1480 - 73 - 1447(50.56% R3.92)

	engine2 = YaneuraOuV360.exe , eval = 182_20160828_49_13G
	play_time = r300 ,  T1,r300,4997 - 133 - 4870(50.64% R4.47)
	play_time = b1000 ,  T1,b1000,1495 - 46 - 1459(50.61% R4.23)

	engine2 = YaneuraOuV360.exe , eval = 182_20160828_49_30G
	play_time = r300 ,  T1,r300,5000 - 143 - 4857(50.73% R5.04)

	engine2 = YaneuraOuV360.exe , eval = 182_20160828_49_40G
	play_time = r300 ,  T1,r300,5017 - 138 - 4845(50.87% R6.06)

	engine2 = YaneuraOuV360.exe , eval = 182_20160828_51_50G
	play_time = r300 ,  T1,r300,4991 - 118 - 4891(50.51% R3.52)

	engine2 = YaneuraOuV360.exe , eval = 182_20160828_49_60G
	play_time = r300 ,  T1,r300,5008 - 147 - 4845(50.83% R5.75)


	# 50

	engine2 = YaneuraOuV360.exe , eval = 182_20160828_50_07G
	play_time = r300 ,  T1,r300,5075 - 147 - 4778(51.51% R10.48)
	play_time = b1000 ,  T1,b1000,1530 - 50 - 1420(51.86% R12.96)

	engine2 = YaneuraOuV360.exe , eval = 182_20160828_50_13G
	play_time = r300 ,  T1,r300,4984 - 131 - 4885(50.5% R3.49)
	play_time = b1000 ,  T1,b1000,1548 - 50 - 1402(52.47% R17.21)
	
	engine2 = YaneuraOuV360.exe , eval = 182_20160828_50_30G
	play_time = r300 ,  T1,r300,5122 - 123 - 4755(51.86% R12.92)


	#51

	engine2 = YaneuraOuV360.exe , eval = 182_20160828_51_10G
	play_time = r300 ,  T1,r300,5041 - 124 - 4835(51.04% R7.25)

	engine2 = YaneuraOuV360.exe , eval = 182_20160828_51_20G
	play_time = r300 ,  T1,r300,4985 - 131 - 4884(50.51% R3.56)

	engine2 = YaneuraOuV360.exe , eval = 182_20160828_51_30G
	play_time = r300 ,  T1,r300,5061 - 123 - 4816(51.24% R8.62)

	engine2 = YaneuraOuV360.exe , eval = 182_20160828_51_40G
	play_time = r300 ,  T1,r300,5090 - 134 - 4776(51.59% R11.06)

	engine2 = YaneuraOuV360.exe , eval = 182_20160828_51_50G
	play_time = r300 ,  T1,r300,4991 - 118 - 4891(50.51% R3.52)

	#52

	engine2 = YaneuraOuV360.exe , eval = 182_20160828_52_10G
	play_time = r300 ,  T1,r300,5154 - 126 - 4720(52.2% R15.28)

	engine2 = YaneuraOuV360.exe , eval = 182_20160828_52_20G
	play_time = r300 ,  T1,r300,5164 - 141 - 4695(52.38% R16.54)

	engine2 = YaneuraOuV360.exe , eval = 182_20160828_52_30G
	play_time = r300 ,  T1,r300,5134 - 123 - 4743(51.98% R13.76)

	engine2 = YaneuraOuV360.exe , eval = 182_20160828_52_40G
	play_time = r300 ,  T1,r300,5224 - 123 - 4653(52.89% R20.11)

	engine2 = YaneuraOuV360.exe , eval = 182_20160828_52_50G
	play_time = r300 ,  T1,r300,5039 - 143 - 4818(51.12% R7.79)


	// 目的関数 = 勝率の関数
	#56
	engine2 = YaneuraOuV360.exe , eval = 182_20160828_56_10G
	play_time = r300 ,  T1,r300,4831 - 143 - 5026(49.01% R-6.87)

	engine2 = YaneuraOuV360.exe , eval = 182_20160828_56_20G
	play_time = r300 ,  T1,r300,4876 - 159 - 4965(49.55% R-3.14)

	engine2 = YaneuraOuV360.exe , eval = 182_20160828_56_30G
	play_time = r300 ,  T1,r300,4993 - 146 - 4861(50.67% R4.65)

	engine2 = YaneuraOuV360.exe , eval = 182_20160828_56_40G
	play_time = r300 ,  T1,r300,4917 - 154 - 4929(49.94% R-0.42)
	
	engine2 = YaneuraOuV360.exe , eval = 182_20160828_56_50G
	play_time = r300 ,  T1,r300,4969 - 139 - 4892(50.39% R2.71)

	
	#57
	engine2 = YaneuraOuV360.exe , eval = 182_20160828_57_10G
	play_time = r300 ,  T1,r300,4953 - 153 - 4894(50.3% R2.08)

	engine2 = YaneuraOuV360.exe , eval = 182_20160828_57_20G
	play_time = r300 ,  T1,r300,5056 - 140 - 4804(51.28% R8.88)

	engine2 = YaneuraOuV360.exe , eval = 182_20160828_57_30G
	play_time = r300 ,  T1,r300,5037 - 142 - 4821(51.1% R7.61)

	engine2 = YaneuraOuV360.exe , eval = 182_20160828_57_40G
	play_time = r300 ,  T1,r300,5088 - 157 - 4755(51.69% R11.76)

	engine2 = YaneuraOuV360.exe , eval = 182_20160828_57_50G
	play_time = r300 ,  T1,r300,5075 - 141 - 4784(51.48% R10.26)


	#56と#57の比較
	engine1 = YaneuraOuV360.exe , eval = 182_20160828_56_30G
	engine2 = YaneuraOuV360.exe , eval = 182_20160828_57_30G
	play_time = r300 ,  T1,r300,5028 - 152 - 4820(51.06% R7.34)


	・#49と#50、#51と#52の結果、また、#56と#57の結果から、EVAL_LIMITは2000より20000が良いと結論できる。
	・#56がベストであったことから、勝率の関数のほうが交差エントロピーよりよい目的関数であると言える。
	

・
	Weight::eta = 3.2f;
	→　YaneuraOuV360learnSGD.exe

	これで19億局面から学習させてみる。
	19億×3周とかで。12時間。
	19億×5周で20時間。


	Weight::eta = 100.0f;
	→　YaneuraOuV360learnSGD100.exe


	よく考えたら、η=300.0fで、EVAL_LIMIT=20000だと、
	自分が0と評価している局面が+10000だったりすると、
	差が10000ぐらいあって、一度しか出現しない特徴因子だと
	そのときに10000×300.0fとかされて、明らかにオーバーフローするような気が…。
	s32で受けて制限かけてるから大丈夫なのか？うーん..
	∇ ≫ 100とかに対して制限かけたほうがいいかもな…。

	+	// あまりきつい勾配を持っているとめったに出現しない特徴因子がおかしくなるので制約を課す
	+	delta_grad = max(delta_grad, -100.0);
	+	delta_grad = min(delta_grad,  100.0);

	+	g = { eta * g[0] / count, eta2 * g[1] / count };

		// あまり大きいと発散しかねないので移動量に制約を課す。
	+	SET_A_LIMIT_TO(g, -64.0f, 64.0f);

	・バグ発見！
		eta2、constにしてて、global変数参照してた…。0になってたのか…。そうか…。

	もう一度、SGDで以下の条件で実験。

		// 1億で0.8倍、10億で0.13倍。
		Weight::eta = 100.0f * (float)pow(0.998f, epoch);


■　2016/08/27

・hyperopt入れる
	//	pipがないならget-pip.pyをdownloadしてから
	> c:/python27/python.exe get-pip.py

	//	pipのupgrade
	> c:/python27/python.exe -m pip install -U pip

	//  pipを用いたhyperoptのインストール
	> c:/python27/Scripts/pip install hyperopt
	> c:/python27/Scripts/pip install numpy
	> c:/python27/Scripts/pip install pymongo
	> c:/python27/Scripts/pip install networkx
	> c:/python27/Scripts/pip install scipy

	scipyでインストールうまくいかない

	http://www.lfd.uci.edu/~gohlke/pythonlibs/
		scipy-0.18.0-cp27-cp27m-win_amd64.whl
		numpy-1.11.1+mkl-cp27-cp27m-win_amd64.whl
	を落としてきて

	> c:/python27/Scripts/pip install scipy-0.18.0-cp27-cp27m-win_amd64.whl
	> c:/python27/Scripts/pip install numpy-1.11.1+mkl-cp27-cp27m-win_amd64.whl

	MKLがIntelのMath Kernel Libraryらしい。


	hyperopt、そこそこ優秀なような気がしてきた。

		#coding:utf-8

		from hyperopt import fmin, tpe, hp, rand
		import random

		count = 0

		def function(args):
			a,b,c,d = args
		#	print ("x={0},y={1},z={2},a={3},b={4},c={5},d={6}".format(x,y,z,a,b,c,d))

			global count
			count += 1
			if (count % 100)==0:
				print count

			r = random.randint(0,100)
			return \
				abs(a-30)*1 + abs(b-40)*1 + abs(c-50)*1 + abs(d-60)*1+ r

		space = [
				  hp.quniform('a', 0, 100 , 1)
				, hp.quniform('b', 0, 100 , 1)
				, hp.quniform('c', 0, 100 , 1)
				, hp.quniform('d', 0, 100 , 1)
				]

		best = fmin(function,space,algo=tpe.suggest,max_evals=500)
		print "best = " , best

・EVAL_LIMIT = 2000にして7億局面生成

	L1正則化と勾配の出てない特徴をupdateしないように変更。

		#if defined(USE_YANE_SGD_UPDATE)
					// 出現頻度が低い特徴は勾配がでたらめである可能性があるのでこれでupdateするのはやめる。
					if (count < 15000)
					{
						count = 0;
						goto FINISH;
					}
		#endif

		#if defined(USE_YANE_SGD_UPDATE)
					// ゼロ方向に少し引っ張る(L1正則化的な何か)
					w[0] -= (w[0]>0 ? 1 : -1)*0.1;
					w[1] -= (w[1]>0 ? 1 : -1)*0.1;
		#endif

		YaneuraOuV360learn998L1.exe
		→　発散した。


		// 0方向に引張るのを真っ先にするべきか？
		#if defined(USE_YANE_SGD_UPDATE)
					// ゼロ方向に少し引っ張る(L1正則化的な何か)
					w[0] -= (w[0]>0 ? 1 : -1)*0.1;
					w[1] -= (w[1]>0 ? 1 : -1)*0.1;
		#endif
			if (g[0] == 0 && g[1] == 0)
				return false;
			→　これでも発散するわ。

#if defined(USE_YANE_SGD_UPDATE)
			// ゼロ方向に少し引っ張る(L1正則化的な何か)
			w[0] -= (w[0]>0 ? 1 : -1)*0.01f;
			w[1] -= (w[1]>0 ? 1 : -1)*0.01f;

			// 出現頻度が低い特徴は勾配がでたらめである可能性があるのでこれでupdateするのはやめる。
			if (count < 15000)
			{
				count = 0;
				goto FINISH;
			}
#endif
		→　これでも発散ぎみ

#if defined(USE_YANE_SGD_UPDATE)
			// ゼロ方向に少し引っ張る(L1正則化的な何か)
			//w[0] -= (w[0]>0 ? 1 : -1)*0.01f;
			//w[1] -= (w[1]>0 ? 1 : -1)*0.01f;

			// 出現頻度が低い特徴は勾配がでたらめである可能性があるのでこれでupdateするのはやめる。
			if (count < 5000)
			{
				count = 0;
				goto FINISH;
			}
#endif
		こう変える。

		YaneuraOuV360learn998L1V3.exe
		・9億×2周 #43
		rmse = 0.0936463 , mean_error = 206.853
		rmse = 0.0925597 , mean_error = 203.518

			engine1 = YaneuraOuV360.exe , eval = 182_20160824
			engine2 = YaneuraOuV360.exe , eval = 182_20160827_43
			play_time = r300 ,  T1,r300,4991 - 139 - 4870(50.61% R4.26)
			play_time = b1000 ,  T1,b1000,1531 - 68 - 1401(52.22% R15.41)


		#define RESET_TO_ZERO_VECTOR
		有効に。

		>	Weight::eta = 300.0f * (float)pow(0.997f, epoch);
		YaneuraOuV360learn997L1V3ZERO.exe

		・9億×2周 #45
		rmse = 0.191646 , mean_error = 449.053
		rmse = 0.14841 , mean_error = 336.394
		あまり下がってないな…。



・EVAL_LIMIT = 2000にして7億局面生成

	教師生成1億局面(40HT) 2:28:00


	] YANE_SGD_UPDATE、交差エントロピー , Weight::eta = 32.0f * (float)pow(0.999f, epoch);
		YaneuraOuV360learn.exe

	・7億×1周 #39
		rmse = 0.0935364 , mean_error = 206.479
		rmse = 0.0919638 , mean_error = 202.336
		play_time = r300 ,  T1,r300,5087 - 156 - 4757(51.68% R11.65)

	] YANE_SGD_UPDATE、交差エントロピー , Weight::eta = 100.0f * (float)pow(0.998f, epoch);
		YaneuraOuV360learn998.exe

	・7億×1周 #37
		rmse = 0.0934595 , mean_error = 206.156
		rmse = 0.090139 , mean_error = 198.62
		play_time = r300 ,  T1,r300,5233 - 127 - 4640(53.0% R20.89)
		play_time = b1000 ,  T1,b1000,1586 - 67 - 1347(54.07% R28.37)


	] YANE_SGD_UPDATE、交差エントロピー , Weight::eta = 300.0f * (float)pow(0.997f, epoch);
		YaneuraOuV360learn997.exe

	・7億×1周 #36
		rmse = 0.0932377 , mean_error = 205.695
		→　速攻発散した。

	] YANE_SGD_UPDATE、目的関数 : 勝率 , Weight::eta = 100.0f * (float)pow(0.998f, epoch);

		YaneuraOuV360learn998win.exe

	・7億×1周 #38
		rmse = 0.0936112 , mean_error = 206.773
		rmse = 0.0916344 , mean_error = 201.542
		play_time = r300 ,  T1,r300,5094 - 148 - 4758(51.71% R11.85)
		play_time = b1000 ,  T1,b1000,1472 - 65 - 1463(50.15% R1.07)

		//
		engine1 = YaneuraOuV360.exe , eval = 182_20160827_37
		engine2 = YaneuraOuV360.exe , eval = Apery20160824
		play_time = r300 ,  T1,r300,4899 - 86 - 5015(49.41% R-4.07)


■　2016/08/26


・182_20160824からdepth6で生成した棋譜に対して
	182_20160824 (Apery20160824より+R10程度)
	からの追加学習。

	rmse,mean_errorの表記は開始時と終了時。

	] YANE_SGD_UPDATE、交差エントロピー , Weight::eta = 32.0f * (float)pow(0.999f, epoch);

	・3億×5周  #22
		rmse = 0.0868215 , mean_error = 350.269
		rmse = 0.0856406 , mean_error = 347.075
		play_time = r300 ,  T1,r300,4891 - 147 - 4962(49.64% R-2.5)

	・3億×10周 #23
		rmse = 0.0868182 , mean_error = 350.228
		rmse = 0.0851735 , mean_error = 345.941
		play_time = r300 ,  T1,r300,4976 - 117 - 4907(50.35% R2.43)

	・6億×2周  #24
		rmse = 0.0868157 , mean_error = 350.247
		rmse = 0.0858546 , mean_error = 347.404
		play_time = r300 ,  T1,r300,4974 - 155 - 4871(50.52% R3.64)

	・6億×5周  #25
		rmse = 0.0868167 , mean_error = 350.22
		rmse = 0.0855211 , mean_error = 346.433
		play_time = r300 ,  T1,r300,4991 - 155 - 4854(50.7% R4.84)

	・9億×2周  #26
		rmse = 0.086842 , mean_error = 350.231
		rmse = 0.085832 , mean_error = 347.25
		play_time = r300 ,  T1,r300,4956 - 156 - 4888(50.35% R2.4)

	・9億×3周  #27
		rmse = 0.0868449 , mean_error = 350.251
		rmse = 0.0858532 , mean_error = 347.141
		play_time = r300 ,  T1,r300,4911 - 146 - 4943(49.84% R-1.13)

		// 22と27との比較
		engine1 = YaneuraOuV360.exe , eval = 182_20160826_22
		engine2 = YaneuraOuV360.exe , eval = 182_20160826_27
		play_time = r300 ,  T1,r300,4996 - 161 - 4843(50.78% R5.4)

		// 27と31との比較
		engine1 = YaneuraOuV360.exe , eval = 182_20160826_27
		engine2 = YaneuraOuV360.exe , eval = 182_20160826_31
		play_time = b1000 ,  T1,b1000,2488 - 125 - 2387(51.04% R7.2)

	] YANE_SGD_UPDATE、交差エントロピー , Weight::eta = 100.0f * (float)pow(0.998f, epoch);

		// 1億で0.8倍、10億で0.13倍。

		YaneuraOuV360learn998.exe

	・3億×2周  #28  182_20160826_28
		rmse = 0.0868901 , mean_error = 350.49
		rmse = 0.0834686 , mean_error = 340.779
		play_time = r300 ,  T1,r300,5067 - 134 - 4799(51.36% R9.44)

	・3億×3周  #29  182_20160826_29
		rmse = 0.0866145 , mean_error = 349.971
		rmse = 0.0827457 , mean_error = 338.772
		play_time = r300 ,  T1,r300,5073 - 149 - 4778(51.5% R10.41)

	・6億×2周  #30
		rmse = 0.0868749 , mean_error = 350.514
		rmse = 0.0850343 , mean_error = 342.688
		play_time = r300 ,  T1,r300,5072 - 152 - 4776(51.5% R10.45)

	・9億×2周  #31
		rmse = 0.0871074 , mean_error = 351.39
		rmse = 0.0844194 , mean_error = 341.205
		play_time = r300 ,  T1,r300,5008 - 156 - 4836(50.87% R6.07)
		play_time = b1000 ,  T1,b1000,2551 - 110 - 2339(52.17% R15.07)

	もやってみる。

	] YANE_SGD_UPDATE、交差エントロピー , Weight::eta = 300.0f * (float)pow(0.997f, epoch);

		// 1億で0.74倍、10億で0.05倍。
		YaneuraOuV360learn997.exe

	・3億×2周  #34
		rmse = 0.0870329 , mean_error = 351.028
		rmse = 0.0835192 , mean_error = 338.577
		play_time = r300 ,  T1,r300,5116 - 133 - 4751(51.85% R12.86)

	・9億

		rmse = 0.0864173 , mean_error = 349.797

	  10億時点  #35 , 182_20160826_35_1G
		rmse = 0.0830257 , mean_error = 335.504
		play_time = r300 ,  T1,r300,5116 - 129 - 4755(51.83% R12.71)

	  20億時点  #35 , 182_20160826_35_2G
		rmse = 0.0830441 , mean_error = 335.392
		play_time = r300 ,  T1,r300,5120 - 129 - 4751(51.87% R12.99)

	  30億時点  #35
		rmse = 0.0830468 , mean_error = 335.376

	  40億時点  #35
		rmse = 0.0830471 , mean_error = 335.372

	  45億時点  #35  , 182_20160826_35_5G
		rmse = 0.0830469 , mean_error = 335.372
		play_time = r300 ,  T1,r300,4965 - 154 - 4881(50.43% R2.96)
		T1,b1000,2206 - 81 - 2073(51.55% R10.8)


		engine1 = YaneuraOuV360.exe , eval = 182_20160826_27
		engine2 = YaneuraOuV360.exe , eval = 182_20160826_35_1G
		play_time = r300 ,  T1,r300,5034 - 132 - 4834(51.01% R7.04)

		engine1 = YaneuraOuV360.exe , eval = 182_20160826_35_1G
		engine2 = YaneuraOuV360.exe , eval = 182_20160826_35_2G
		play_time = r300 ,  T1,r300,4915 - 152 - 4933(49.91% R-0.64)


	交差エントロピーがいけない気もする..。

	] YANE_SGD_UPDATE、目的関数 : 勝率 , Weight::eta = 100.0f * (float)pow(0.998f, epoch);

		YaneuraOuV360learn998win.exe

	・6億×2周  #32
		rmse = 0.086859 , mean_error = 350.391
		rmse = 0.0854933 , mean_error = 349.878
		play_time = r300 ,  T1,r300,4962 - 135 - 4903(50.3% R2.08)

	・9億×3周  #33
		rmse = 0.0868654 , mean_error = 350.474
		rmse = 0.0857386 , mean_error = 350.528
		play_time = r300 ,  T1,r300,5031 - 144 - 4825(51.05% R7.26)



■　2016/08/25


  depth6 1億局面生成 6:00:00×8並列
  8億×4周=32局面からの学習 6:00:00
  --------------------------------
  合計)  12:00:00

  明日、起きてから異なる条件で学習させて比較しよう…。


・自己対局の定跡差し替え
	records2016_10818.sfen

	engine1 = YaneuraOuV360.exe , eval = 182_20160824
	engine2 = YaneuraOuV360.exe , eval = Apery20160824
	play_time = r300 ,  T1,r300,517 - 12 - 471(52.33% R16.19)


・Apery新。

	engine1 = YaneuraOuV360.exe , eval = 182_20160824
	engine2 = YaneuraOuV360.exe , eval = Apery20160824
	play_time = r300 ,  T1,r300,5078 - 91 - 4831(51.25% R8.66)

	engine1 = YaneuraOuV360.exe , eval = Apery20160821
	engine2 = YaneuraOuV360.exe , eval = Apery20160824
	play_time = r300 ,  T1,r300,4908 - 123 - 4969(49.69% R-2.15)

	engine1 = YaneuraOuV360.exe , eval = 182_20160824
	engine2 = YaneuraOuV360.exe , eval = Apery20160824
	play_time = b1000 ,  T1,b1000,2513 - 59 - 2428(50.86% R5.98)



・jenkinsのworkflowを理解する。
	depth3 , 10億局面の生成 = 14.5時間(40HT)
					+ ファイルコピー(15分ほど)
	10億×3周               =  6  時間

	1iteration = 21時間程度

	10億局面の生成自体は、4並列なら3.625時間で済むので
	10時間ぐらいで1iterationが回せるようになる。
	(あまり速くなってないか？)

	10億×3周がもったいないのか？
	SGDの学習率調整して、2周ぐらいで済むようにするべきか？
	うーん。よくわからん…。

	てかdepth6でも1日2周ぐらい回るのでは…。
	よくわからんので10億×2周に設定して1日回しておく。

	8時間ぐらいで1 iteration回るから、明日には
	これで強くなるのかどうかがわかる。
	→　強くならんかった…。

	2周が足りないのか何なのか…。

		engine1 = YaneuraOuV360.exe , eval = 183_LOOP_20160825a
		engine2 = YaneuraOuV360.exe , eval = Apery20160824
		play_time = r300 ,  T1,r300,5081 - 94 - 4825(51.29% R8.98)

		engine1 = YaneuraOuV360.exe , eval = 183_LOOP_20160825a
		engine2 = YaneuraOuV360.exe , eval = 183_LOOP
		play_time = r300 ,  T1,r300,4924 - 148 - 4928(49.98% R-0.14)

		engine1 = YaneuraOuV360.exe , eval = Apery20160824
		engine2 = YaneuraOuV360.exe , eval = 183_LOOP_20160825b
		play_time = r300 ,  T1,r300,4986 - 99 - 4915(50.36% R2.49)

		engine1 = YaneuraOuV360.exe , eval = 182_20160824
		engine2 = YaneuraOuV360.exe , eval = 183_LOOP_20160825b
		play_time = r300 ,  T1,r300,5134 - 141 - 4725(52.07% R14.42)



・Jenkinsのgroovyで並列ビルドできた。

	while(true)
	{
	  // build number
	  def bn = build.getEnvironment(listener).get('BUILD_NUMBER')  
  
	  // parallel number
	  def pn = 8

	  parallel(
		{ build("yanejob/教師局面ファイル生成flow", SFEN_FILENAME:"ALN_"+bn+"_0", DEPTH: params["DEPTH"], LOOP_MAX: params["SFEN_LOOP"] , EVAL_DIR : params["EVAL_DIR"] , EVAL_LIMIT : 20000) },
		{ build("yanejob/教師局面ファイル生成flow", SFEN_FILENAME:"ALN_"+bn+"_1", DEPTH: params["DEPTH"], LOOP_MAX: params["SFEN_LOOP"] , EVAL_DIR : params["EVAL_DIR"] , EVAL_LIMIT : 20000) },
		{ build("yanejob/教師局面ファイル生成flow", SFEN_FILENAME:"ALN_"+bn+"_2", DEPTH: params["DEPTH"], LOOP_MAX: params["SFEN_LOOP"] , EVAL_DIR : params["EVAL_DIR"] , EVAL_LIMIT : 20000) },
		{ build("yanejob/教師局面ファイル生成flow", SFEN_FILENAME:"ALN_"+bn+"_3", DEPTH: params["DEPTH"], LOOP_MAX: params["SFEN_LOOP"] , EVAL_DIR : params["EVAL_DIR"] , EVAL_LIMIT : 20000) },
		{ build("yanejob/教師局面ファイル生成flow", SFEN_FILENAME:"ALN_"+bn+"_4", DEPTH: params["DEPTH"], LOOP_MAX: params["SFEN_LOOP"] , EVAL_DIR : params["EVAL_DIR"] , EVAL_LIMIT : 20000) },
		{ build("yanejob/教師局面ファイル生成flow", SFEN_FILENAME:"ALN_"+bn+"_5", DEPTH: params["DEPTH"], LOOP_MAX: params["SFEN_LOOP"] , EVAL_DIR : params["EVAL_DIR"] , EVAL_LIMIT : 20000) },
		{ build("yanejob/教師局面ファイル生成flow", SFEN_FILENAME:"ALN_"+bn+"_6", DEPTH: params["DEPTH"], LOOP_MAX: params["SFEN_LOOP"] , EVAL_DIR : params["EVAL_DIR"] , EVAL_LIMIT : 20000) },
		{ build("yanejob/教師局面ファイル生成flow", SFEN_FILENAME:"ALN_"+bn+"_7", DEPTH: params["DEPTH"], LOOP_MAX: params["SFEN_LOOP"] , EVAL_DIR : params["EVAL_DIR"] , EVAL_LIMIT : 20000) },
	  )

	  def files = ""
	  for(int i=0;i<pn;++i)
  		files += "ALN_" + bn + "_" + i.toString() + ".bin "
  
	  build("yanejob/教師局面からの学習flow", KIF_FILES: files , LEARN_LOOP_MAX : params["LEARN_LOOP_MAX"] , EVAL_DIR : params["EVAL_DIR"] )
	}

	↓書き換え

		  def tasks = [:]
		  for(int i=0;i<pn;++i)
		  {
			def task_tag = "task-aln-"+i.toString()
			// def task_args = [SFEN_FILENAME:"ALN_"+bn+ "_" +i.toString(),DEPTH:params["DEPTH"],LOOP_MAX:params["SFEN_LOOP"],EVAL_DIR:params["EVAL_DIR"],EVAL_LIMIT:"20000"]

			def task_args = [new StringParameterValue("SFEN_FILENAME","ALN_"+bn+ "_" +i.toString()),
						new StringParameterValue("DEPTH", params["DEPTH"]),
						new StringParameterValue("LOOP_MAX",params["SFEN_LOOP"]),
						new StringParameterValue("EVAL_DIR",params["EVAL_DIR"]),
						new StringParameterValue("EVAL_LIMIT", "20000")]
        
			tasks[task_tag] = { task_tag : {  build job : "yanejob/教師局面ファイル生成flow", parameters : task_args }}
		  }
		  parallel tasks

		古いサンプルはこれで動くのになぁ…仕様変わったのか…。

		// こうか？


		while(true)
		{
		  // build number
		  def bn = build.getEnvironment(listener).get('BUILD_NUMBER')  
  
		  // parallel number
		  def pn = params["PARA_NUM"].toInteger()

		  def builds = []
		  for(int i=0;i<pn;++i)
		  {
			// ここでjにコピーして、これをclosureに束縛させる。
			int j=i
			builds.add( { -> build("yanejob/教師局面ファイル生成flow",SFEN_FILENAME:"ALN_"+bn+"_" + j.toString() +".bin",
								DEPTH: params["DEPTH"], LOOP_MAX: params["SFEN_LOOP"] , EVAL_DIR : params["EVAL_DIR"] , EVAL_LIMIT : "20000") })
		  }
		  parallel(builds)  
    
		  def files = ""
		  for(int i=0;i<pn;++i)
  			files += "ALN_" + bn + "_" + i.toString() + ".bin "
    
		  build("yanejob/教師局面からの学習flow", KIF_FILES: files , LEARN_LOOP_MAX : params["LEARN_LOOP_MAX"] , EVAL_DIR : params["EVAL_DIR"] )
		}




■　2016/08/24

・無限学習

	engine1 = YaneuraOuV360.exe , eval = 180_20160824 // depth3 , 3億のイテレーション*6
	engine2 = YaneuraOuV360.exe , eval = 182_20160824 // depth3 , 10億のイテレーション*1
	T1,r300,749 - 14 - 897(45.5% R-31.32)

	engine1 = YaneuraOuV360.exe , eval = 180_20160824 // depth3 , 3億のイテレーション*6
	engine2 = YaneuraOuV360.exe , eval = 181_20160824 // depth6 , 3億のイテレーション*1
	T1,r300,719 - 23 - 938(43.39% R-46.19)

	engine1 = YaneuraOuV360.exe , eval = 181_20160824
	engine2 = YaneuraOuV360.exe , eval = 182_20160824
	play_time = r300 ,  T1,r300,4827 - 116 - 5057(48.84% R-8.09)

	engine1 = YaneuraOuV360.exe , eval = 181_20160824
	engine2 = YaneuraOuV360.exe , eval = Apery20160821
	play_time = r300 ,  T1,r300,5066 - 80 - 4854(51.07% R7.43)

	engine1 = YaneuraOuV360.exe , eval = 182_20160824
	engine2 = YaneuraOuV360.exe , eval = Apery20160821
	play_time = r300 ,  T1,r300,5102 - 76 - 4822(51.41% R9.81)

	engine1 = YaneuraOuV360.exe , eval = 179_0080G_V5_E30
	engine2 = YaneuraOuV360.exe , eval = 182_20160824
	play_time = r300 ,  T1,r300,4877 - 140 - 4983(49.46% R-3.74)

	engine1 = YaneuraOuV360.exe , eval = 179_0080G_V5_E30
	engine2 = YaneuraOuV360.exe , eval = 181_20160824
	play_time = r300 ,  T1,r300,4913 - 123 - 4964(49.74% R-1.79)

	engine1 = YaneuraOuV360.exe , eval = Apery20160821
	engine2 = YaneuraOuV360.exe , eval = 182_20160824
	play_time = b1000 ,  T1,b1000,1480 - 17 - 1503(49.61% R-2.68)

	3億局面はいずれにせよ、よくないということがわかった。
	もう1イテレーション回して結果を観測する。

・ppt実験

	engine1 = YaneuraOuV360.exe , eval = Apery20160821
	engine2 = YaneuraOuV360_ppt2.exe , eval = Apery20160821
	play_time = r300 ,  T1,r300,4870 - 111 - 5019(49.25% R-5.24)

	うーむ。わからん…。
	
	値をダンプしてみたところ、手番があるときの手駒の価値を補整するような値に
	なってる気がする。

	これ自体は、駒割り自体に手番の価値があるべきような気はする。
	しかし2枚目の歩、3枚目の歩…などのように手駒の価値が変動するので難しい。
	いずれにせよ、意味があるということのようだ。

	というか、PPHは本当に駄目なアイデアなのだろうか…。
	KPHTとか。
	KPP + KPHT駄目なんかな…。

	PPP + PPTとどっちがいいかだな…。
	PPPで7.812GB必要。
	2バイト + 勾配の計算用のfloat(4) + カウント用変数(4) = 10
	つまり、7.812GBの5倍がSGDのために必要だな。さすがに足りないのか。
	3角配列使って1/4にはなるのか。うーん..メモリ的には足りるのか。
	強くなるかどうかは不明だが…。
	さすがに重いような気がしてきた。1枚駒captureするとき、
	39*38回×4の計算が必要なのか…。そうか…。captureがなくてもこの半分か。
	
	早く決断せねば…。

・自己対戦フレームワーク、エンジン起動後、10秒ぐらい待ったほうが良いのでは。
	→　以下のように修正した

	# 初回のreadyokに対するwait
	initial_waits = [True]*threads*2

				if ("readyok" in line) and (states[i] == "wait_for_readyok"):

					# 初回のみこの応答に対して1秒待つことにより、
					# プロセスの初期化タイミングが重複しないようにする。
					if initial_waits[i]:
						initial_waits[i] = False
						time.sleep(1)



■　2016/08/23

・手駒に対する手番って関係ないのでは？

		YaneuraOuV360no_ht.exe
#if 1
			// KPPTの手駒は手番必要ないのではないかを検証するためのコード
			for (BonaPiece p1 = BONA_PIECE_ZERO; p1 < fe_hand_end; ++p1)
				for (BonaPiece p2 = BONA_PIECE_ZERO; p2 < fe_end; ++p2)
				{
					for (auto sq : SQ)
					{
						kpp[sq][p1][p2][1] = 0;
						kpp[sq][p2][p1][1] = 0;
					}
				}
#endif
		T1,r300,340 - 15 - 825(29.18% R-153.99)
		あれ？弱すぎない？
		そうでもないか。

		これ置換表共有してて、共有メモリ壊したりしてないか？
		うむむ..??

		学習のときには置換表共有してないから大丈夫か…。
		棋譜生成のときは？

		evalshareしてると危ないな…。うーむ..そんな可能性があるのか…。
		実験用はversionナンバー変更しないといかんな…。

		もっかい360_pptの実験。
		→　この実験結果は正しいようだ。なんなんこれ…。
	

・自動無限学習
		engine1 = YaneuraOuV360.exe , eval = Apery20160821
		engine2 = YaneuraOuV360.exe , eval = 179_0081G_V6
		play_time = r300 ,  T1,r300,4899 - 78 - 5023(49.38% R-4.34)
		play_time = b1000 ,  T1,b1000,1458 - 34 - 1508(49.16% R-5.86)

		engine1 = YaneuraOuV360.exe , eval = 179_0080G_V5_E30
		engine2 = YaneuraOuV360.exe , eval = 179_0081G_V6
		play_time = r300 ,  T1,r300,5046 - 131 - 4823(51.13% R7.85)

		engine1 = YaneuraOuV360.exe , eval = Apery20160821
		engine2 = YaneuraOuV360.exe , eval = 179_0082G_V6
		play_time = r300 ,  T1,r300,2485 - 41 - 2474(50.11% R0.77)

		engine1 = YaneuraOuV360.exe , eval = 179_0080G_V5_E30
		engine2 = YaneuraOuV360.exe , eval = 179_0082G_V6
		T1,r300,2721 - 59 - 2410(53.03% R21.08)

		engine1 = YaneuraOuV360.exe , eval = Apery20160821
		engine2 = YaneuraOuV360.exe , eval = 179_0082G_V6
		T1,b1000,1709 - 29 - 1682(50.4% R2.77)

		engine1 = YaneuraOuV360.exe , eval = 179_0082G_V6
		engine2 = YaneuraOuV360.exe , eval = 179_0080G_V5_E30
		T1,b1000,1719 - 74 - 1967(46.64% R-23.41)

		engine1 = YaneuraOuV360.exe , eval = Apery20160821
		engine2 = YaneuraOuV360.exe , eval = 179_0090G_V6_180
		play_time = r300 ,  T1,r300,5139 - 84 - 4777(51.83% R12.69)

		engine1 = YaneuraOuV360.exe , eval = Apery20160821
		engine2 = YaneuraOuV360.exe , eval = 179_0090G_V6_180
		play_time = b1000 ,  T1,b1000,2708 - 64 - 2228(54.86% R33.89)


		depth3、3億局面は甘すぎであったか…。


・魔女と持ち時間制で比較。
	t300000 だと魔女がタイムオーバー
	t600000 だとpythonスクリプトのtime outに引っかかる。
	スクリプト修正するか…。

	-			and time.time() - go_times[i] >= 60:
	+			and time.time() - go_times[i] >= (300 if "t" in opt2 else 60):

		engine1 = YaneuraOuV360.exe , eval = Apery20160821
		engine2 = SM_V110/SILENT_MAJORITY_AVX2_x64.exe , eval = Apery20160821
		T1,t900000,196 - 5 - 39(83.4% R280.48)

	それを除いても、魔女勝たないな。魔女側、持ち時間制御がApery由来だからか…。
	inc time設定で回すか…。もういいか..

		t900000 i10000
	これで回しておく。これで駄目ならもう知らん。

		engine1 = YaneuraOuV360.exe , eval = Apery20160821
		engine2 = SM_V110/SILENT_MAJORITY_AVX2_x64.exe , eval = Apery20160821
		play_time = t900000/i10000 ,  T1,t900000/i10000,474 - 70 - 456(50.97% R6.73)

	互角以上なので持ち時間制御においてもやねうら王のほうが優れている。


・無限自動学習

  depth3 3億局面生成 3:15:00
  3億×5周=15局面からの学習 2:50:00
  --------------------------------
  合計)  6:00:00

  →　棋譜生成、workflowにして3～4並列化すれば4時間ぐらいで1回回るのだが…。
	あとで考えよう。jenkinsのworkflow、こなれてなくて、難しそう…。


・2倍の思考時間テスト
			option.append("go btime REST_TIME wtime REST_TIME byoyomi " + str(byoyomi * (i+1)))

		engine1 = YaneuraOuV360.exe , eval = Apery20160821
		engine2 = YaneuraOuV360.exe , eval = Apery20160821
		play_time = b1000 ,  t1,b1000,216 - 16 - 768(21.95% R-220.36)

	R200ぐらい差があるんだな。凄い。
	
	KPPTに2割ぐらい使ってるから、20%改善するとnpsは1.25倍。

	2倍でR210だとすると..
	1.25倍でlog(1.25,2)*210 = R67.6up

	KKPTとKPPTとの差はR100程度として、PPTにするとR30ぐらい改善するかも知れないから
	R70ぐらいの差。

	ほぼ同じなのか…。なんだこれ。ほぼ同じならなおすほどのこともないのか…。
	しかしPPTでR50ぐらい上がると逆転するのだが…。そんなに上がらないか..うーん..

	KPPTのうちの、PPTだけにするために
		PPT = ΣKKPT/n
	みたいに平均化したもので勝率どれくらいになるのか見るといいか。

		// KPPTをPPTで代替えできないかを検証するためのコード
		// KPPTの値を平均化してPPTとして代入する。

		for (BonaPiece p1 = BONA_PIECE_ZERO; p1 < fe_end; ++p1)
			for (BonaPiece p2 = BONA_PIECE_ZERO; p2 < fe_end; ++p2)
			{
				int sum = 0;
				for (auto sq : SQ)
					sum += kpp[sq][p1][p2][1];

				int z = sum / SQ_NB;

				for (auto sq : SQ)
					kpp[sq][p1][p2][1] = z;
			}

		→	YaneuraOuV360_ppt.exe

		engine1 = YaneuraOuV360.exe , eval = Apery20160821
		engine2 = YaneuraOuV360_ppt.exe , eval = Apery20160821
		play_time = r300 ,  t1,r300,4836 - 142 - 5022(49.06% R-6.56)

		engine1 = YaneuraOuV360.exe , eval = Apery20160821
		engine2 = YaneuraOuV360_ppt.exe , eval = Apery20160821
		play_time = b1000 ,  t1,b1000,1480 - 53 - 1467(50.22% R1.53)

		やはりそうか！KPPTみたいなものは意味のない概念だったんだ。
		当たりかどうかはPPTを見れば十分なわけで…。
		いやはや…。

		ということは、R50ぐらい上がるのか…。これは儲け儲け。
		evaluate_kppt_prime.h/cpp追加するか…。
		これは凄い発見かも知れん。


・自己対戦から糞定跡を取り除く。

	コマンド追加。
	> makebook from_sfen_to_sfen book_in.sfen book_out.sfen eval -100 100 moves 24 depth 18

	定跡ファイルの精査用。(自己対戦時の精度を上げるためのもの)

	sfenファイルbook_in.sfenを読み込み、
	depth18で24手目の局面を探索して、評価値が[-100,100]に収まっていなければ除外。
	最終的に残ったものをbook_out.sfenとして書き出す。

	→　良くない気がしてきた。やねうら大定跡から持ってきたほうが簡単なような…。
		最初がsfenになるの気持ち悪いのか？
		うーん、難しいなぁ…。
		やねうら大定跡と比較して局面出力すればいいのかも？
		test exambookコマンド追加しておく。

	→　できた。
		records2016_10000.sfen
		評価値 [-100,100]
		moves = 24
		records = 11207

	これに伴い、pythonのスクリプト変更。
	ランダムに読むのではなく11207までは1周回す。
	→　差し替えた。

・自己対戦の結果表示、Stockfishに倣ったほうがいいかも知れん。
	https://github.com/glinscott/fishtest/wiki/Creating-my-first-test
	STC = Short time control (10+0.1)
	LTC = Long time control (60+0.6)
	SPRT(x,y) = SPRT test with elo0 = x and elo1 = y
	http://chess-sprt-calc.azurewebsites.net/

	→　倣うほどのものでもなさげなのでまあいいや。

・無限自動学習スクリプト(新)
	:loop
	start /NODE %EXECUTOR_NUMBER% /B /WAIT /D %YANEHOME% %YANEHOME%\exe\YaneuraOuV360.exe evaldir eval/%EVAL_DIR% , threads %HT_CORES% , hash 4096 , gensfen depth %DEPTH% loop %GEN_LOOP_MAX% eval_limit %EVAL_LIMIT% file %WORKSPACE%\AL%BUILD_NUMBER%.bin , quit
	start /NODE %EXECUTOR_NUMBER% /B /WAIT move %WORKSPACE%\AL%BUILD_NUMBER%.bin %YANEHOME%\gen_sfen\
	start /NODE %EXECUTOR_NUMBER% /B /WAIT /D %YANEHOME% %YANEHOME%\exe\YaneuraOuV360learn_once30.exe evaldir eval/%EVAL_DIR% , evalsavedir %YANEHOME%\eval/%EVAL_DIR% , threads %HT_CORES% , hash 4096 , evalshare false , learn loop %LEARN_LOOP_MAX% dir %YANEHOME%\gen_sfen AL%BUILD_NUMBER%.bin , quit
	goto loop

	numa指定してmoveしてるのに、もう片方のnumaがCPU資源もらえてない。なにこれ..
	DMA転送に起因する何かか？


■　2016/08/22


・KKPTの実験
	YaneuraOuV360kkpt

		engine1 = YaneuraOuV360.exe , eval = Apery20160821
		engine2 = YaneuraOuV360kkpt.exe , eval = Apery20160821
		t1,r300,644 - 16 - 380(62.89% R91.64)
		t1,b1000,221 - 4 - 125(63.87% R98.99)
		R100ぐらいの負けか。学習しなおしてみるか。

		engine1 = YaneuraOuV360.exe , eval = Apery20160505
		engine2 = YaneuraOuV360kkpt.exe , eval = Apery20160821
		play_time = b1000 ,  t1,b1000,1240 - 27 - 1733(41.71% R-58.15)

		それでもApery20160505よりはR60近く強いのか。


	YaneuraOuV360learn_once30kkpt

		engine1 = YaneuraOuV360.exe , eval = Apery20160821
		engine2 = YaneuraOuV360.exe , eval = 179_0080G_V5_E30KKPT
		t1,r300,4577 - 80 - 3133(59.36% R65.85)
		t1,b1000,1555 - 27 - 968(61.63% R82.34)

		これだけ差があるとKKPTにするとR30ぐらい損する気が。
		ついでに1秒-2秒,5-10秒のr差、求めておいたほうがいいかも。


		engine1 = YaneuraOuV360kkpt.exe , eval = Apery20160821
		engine2 = YaneuraOuV360.exe , eval = 179_0080G_V5_E30KKPT
		play_time = r300 ,  t1,r300,4938 - 86 - 4976(49.81% R-1.33)

		engine1 = YaneuraOuV360kkpt.exe , eval = 179_0080G_V5_E3
		engine2 = YaneuraOuV360.exe , eval = 179_0080G_V5_E30KKPT
		t1,r300,1680 - 43 - 1657(50.34% R2.39)

		engine1 = YaneuraOuV360.exe , eval = Apery20160821
		engine2 = YaneuraOuV360.exe , eval = 179_0080G_V5_E30
		t1,b1000,616 - 14 - 660(48.28% R-11.99)

		KKPT用に学習しなおしても元のからKPPT=0にしたものと強さがほぼ変わらん。


・SGDのη、低すぎるような気が。

		// epoch == 100(1億局面)で0.9倍。10億で0.3倍みたいな。
		Weight::eta = 3.2f;
		↓
		Weight::eta = 10.0f * pow(0.999,epoch);

		// ↑比較↓

		YaneuraOuV360learn_once30
		Weight::eta = 30.0f * pow(0.999,epoch);

		mean error上がってって話にならん。
		rmseは下がってるんだけどな…。うーん。

		Weight::eta = 3.2f * pow(0.999,epoch);
		Weight::eta = 30.0f * pow(0.999,epoch);
		// この２つで学習回して、結果を比較するのがいいな。

	YaneuraOuV360learn_once3 
		rmse = 0.0911691 , mean_error = 345.41 
		rmse = 0.0902648 , mean_error = 345.825 // 12億局面 = 179_0080G_V5_E3
	YaneuraOuV360learn_once30
		rmse = 0.0880975 , mean_error = 347.994 // 12億局面 = 179_0080G_V5_E30
	YaneuraOuV360learn_once30kkpt
		rmse = 0.0976883 , mean_error = 357.362
		rmse = 0.094295 , mean_error = 362.943  // 12億局面 = 179_0080G_V5_E30KKPT

		engine1 = YaneuraOuV360.exe , eval = Apery20160821
		engine2 = YaneuraOuV360.exe , eval = 179_0080G_V5_E3
		play_time = r300 ,  t1,r300,4900 - 103 - 4997(49.51% R-3.41)
		play_time = b1000 ,  t1,b1000,1513 - 45 - 1442(51.2% R8.35)

		engine1 = YaneuraOuV360.exe , eval = Apery20160821
		engine2 = YaneuraOuV360.exe , eval = 179_0080G_V5_E30
		play_time = r300 ,  t1,r300,4846 - 110 - 5044(49.0% R-6.96)

		engine1 = YaneuraOuV360.exe , eval = 179_0080G_V5_E3
		engine2 = YaneuraOuV360.exe , eval = 179_0080G_V5_E30
		t1,b1000,1436 - 55 - 1469(49.43% R-3.95)

	→　E30のほうが強いっぽい。E20のほうがrmseの下がりが大きいので、こちらが強いというのは妥当性がある。
		YANE_SGD_UPDATEではeta = 32.0fをデフォルトに変更する。
			Weight::eta = 32.0f * (float)pow(0.999f, epoch);
		mini-batch sizeもっと小さくしたいのだが、update()を並列化していないので難しいな…。うーん。


・3時間で棋譜生成、3時間学習にするには…。3時間だとdepth 3でも3億局面しか…。
	3億局面、そこまで少なくない気もするけども..。
	学習は100億=24時間ぐらい。
	3時間で3億局面×4周ぐらい回すと？

		depth 3 , 1.5時間 1億
		depth 4 , 2.5時間 1億
		depth 5 , 
		depth 6 , 4.3時間 1億
		…

	Jenkinsのワークフローで何とかしたほうがいいような…。

・eval、上書きするモードが必要なような..
	→　追加した。

	engine1 = YaneuraOuV360.exe , eval = 179_0070G_V5
	engine2 = YaneuraOuV360.exe , eval = Apery20160821
	t1,r300,2335 - 48 - 2377(49.55% R-3.1)


	engine1 = YaneuraOuV360.exe , eval = 179_0068G_V5
	engine2 = YaneuraOuV360.exe , eval = 179_0070G_V5
	t1,r300,3963 - 112 - 3955(50.05% R0.35)
	t1,b1000,1079 - 41 - 1120(49.07% R-6.48)
	検知できない差。


・Apery新バイナリ
	engine1 = YaneuraOuV360.exe , eval = Apery20160815
	engine2 = YaneuraOuV360.exe , eval = Apery20160821
	play_time = b1000 ,  t1,b1000,1459 - 65 - 1476(49.71% R-2.01)
	play_time = r300 ,  t1,r300,4840 - 129 - 5031(49.03% R-6.72)


■　2016/08/21

・V3.60 = V3.59h

		engine1 = gikou_win_20160606/gikou.exe , eval = dummy
		engine2 = YaneuraOuV359h , eval = Apery20160815
		t2 , b6000 , 373 - 7 - 500(42.73% R-50.9)

		engine1 = SM_V110/SILENT_MAJORITY_AVX2_x64.exe , eval = Apery20160815
		engine2 = YaneuraOuV359h , eval = Apery20160815
		t4 , b6000 , 249 - 29 - 242(50.71% R4.95)

		engine1 = gikou_win_20160606/gikou.exe , eval = dummy
		engine2 = SM_V110/SILENT_MAJORITY_AVX2_x64.exe , eval = Apery20160815
		t2,b6000,150 - 9 - 161(48.23% R-12.29)

		魔女は技巧に対してあまり勝率が良くない感。

・depth8 ×1億局面から。
	・開始時
		rmse = 0.0889041 , mean_error = 443.663

		3億局面経過
		engine1 = YaneuraOuV360.exe , eval = 179_0060G_V4
		engine2 = YaneuraOuV360.exe , eval = 179_0061G_V5
		play_time = R200 ,  t1,R200,4954 - 167 - 4879(50.38% R2.65)

		engine1 = YaneuraOuV360.exe , eval = Apery20160815
		engine2 = YaneuraOuV360.exe , eval = 179_0061G_V5
		t1,R200,3697 - 75 - 3618(50.54% R3.75)

		検知できるレベルの差を生まないということか。
		ここなしか、Aperyには近づいているのか？
		わからん。以前の評価関数でR200でやったデータがなかった(´ω｀)

		50億局面
		engine1 = YaneuraOuV360.exe , eval = 179_0060G_V4
		engine2 = YaneuraOuV360.exe , eval = 179_0065G_V5
		play_time = b1000 ,  t1,b1000,1466 - 68 - 1466(50.0% R-0.0)

		engine1 = YaneuraOuV360.exe , eval = 179_0063G_V5
		engine2 = YaneuraOuV360.exe , eval = 179_0065G_V5
		play_time = r200 ,  t1,r200,5060 - 123 - 4817(51.23% R8.55)
		play_time = b1000 ,  t1,b1000,995 - 42 - 963(50.82% R5.68)

		engine1 = YaneuraOuV360.exe , eval = Apery20160815
		engine2 = YaneuraOuV360.exe , eval = 179_0065G_V5
		play_time = r200 ,  t1,r200,4896 - 90 - 5014(49.4% R-4.14)
		t1,r300,1258 - 19 - 1293(49.31% R-4.77)
		play_time = b1000 ,  t1,b1000,1027 - 22 - 951(51.92% R13.36)
		play_time = b5000 ,  t1,b5000,513 - 18 - 469(52.24% R15.58)

		engine1 = YaneuraOuV360.exe , eval = 179_0060G_V4
		engine2 = YaneuraOuV360.exe , eval = 179_0068G_V5
		play_time = r300 ,  t1,r300,4885 - 135 - 4980(49.52% R-3.35)

		engine1 = YaneuraOuV360.exe , eval = Apery20160815
		engine2 = YaneuraOuV360.exe , eval = 179_0068G_V5
		play_time = b5000 ,  t1,b5000,487 - 16 - 497(49.49% R-3.53)



■　2016/08/20

・やねうら王のエンジンオプションで1パラメーターだけ好きに変更できるようにするか？
	いやー、、パラメーター名 + 値をいくらでも書けばいいのでは.
		FUTILITY_MARGIN:50:RAZOR_MARGIN:70:...
	みたいな？なんかダサい気もする。よくわからない。
	せっかく自動調整出来るのにいまさら手動とか意味わからん…。
	paramファイル、固定なのがよくない気がする。これフォルダ変えれるようにして別のところに配置するか。
	そして、5秒1000局で回すか…。うーん…。それするなら並列化したい気もするんだよな…。
	しんどいか…。逆に並列化しないなら、フォルダ位置変えられる必要ないのでは…。
	結局、python側で調整すればいいのか…そうか…。
	この実装、2,3時間かかりそうなのであとでやろう。
	そして、いま調整しても、Stockfish側の進化で再調整が必要になる可能性が…。
	コード書くだけ書いて、futility等、簡単なところの調整だけにするか。まずは。


・自己対戦フレームワーク、time outの処理追加する。
	→　追加した。

・新自己対戦フレームワークを探索パラメーターの自動調整に対応させたほうがいいかも知れない…が、1手5秒とかだと
	1パラメーター調整にどれだけかかることやら…。1手1秒だとまたおかしいことになりかねないし…。うーん。
	あまりいまのパラメーターから動かすとStockfishの今後の枝刈りとの相性が悪くなる可能性もあるし…。困るなぁ…。

	V3.59a
		// 捕獲から逃れる指し手はreduction量を減らす。
		これ有効にしてみよう。

			engine1 = YaneuraOuV357e.exe , eval = Apery20160815
			engine2 = YaneuraOuV359a.exe , eval = Apery20160815
			play_time = b1000 ,  1446 - 51 - 1503(49.03% R-6.72)

			engine1 = YaneuraOuV357e.exe , eval = Apery20160815
			engine2 = YaneuraOuV359a.exe , eval = Apery20160815
			play_time = b3000 ,  487 - 21 - 492(49.74% R-1.77)

		よくわからんが入れたほうがいいっぽい…。そうなのか…。


	V3.59b forked from 3.59a
		静止探索の1手詰め、長い持ち時間でも入れたほうがいいのか？

			engine1 = YaneuraOuV359a.exe , eval = Apery20160815
			engine2 = YaneuraOuV359b.exe , eval = Apery20160815
			play_time = b1000 ,  1631 - 55 - 1314(55.38% R37.54)

			engine1 = YaneuraOuV359a.exe , eval = Apery20160815
			engine2 = YaneuraOuV359b.exe , eval = Apery20160815
			play_time = b6000 ,  538 - 23 - 439(55.07% R35.33)


	V3.59c forked from V3.59a
		通常探索の1手詰め、入れないと？

		engine1 = YaneuraOuV359a.exe , eval = Apery20160815
		engine2 = YaneuraOuV359c.exe , eval = Apery20160815
		play_time = b1000 ,  1471 - 57 - 1472(49.98% R-0.12)

		engine1 = YaneuraOuV359a.exe , eval = Apery20160815
		engine2 = YaneuraOuV359c.exe , eval = Apery20160815
		play_time = b3000 ,  522 - 30 - 448(53.81% R26.56)

		入れたほうがよさ気ではある。
		残り探索深さがある程度ないと詰みを見つけたときのリターンが少ない気はする。
		PVかどうかとか、残りdepthに応じて変えたほうが良いのかも..


	V3.59d forked from V3.59a
		・捕獲から逃れる指し手、あり
		・tempo、なしに
		→　これで魔女と対局させておく。

		以前のデータ。
		// 4 threads
		engine1 = YaneuraOuV357b.exe , eval = Apery20160815
		engine2 = SM_V110/SILENT_MAJORITY_AVX2_x64.exe , eval = Apery20160815
		342 - 47 - 311(52.37% R16.51)


		// 4 threads
		b1000 , 1127 - 79 - 1114(50.29% R2.02)

		engine1 = YaneuraOuV359d , eval = Apery20160815
		engine2 = gikou_win_20160606/gikou.exe , eval = Apery20160815
		play_time = b3000 ,  494 - 4 - 502(49.6% R-2.79)

		短い時間ではあまり勝ってない。

		engine1 = YaneuraOuV359d , eval = Apery20160815
		engine2 = gikou_win_20160606/gikou.exe , eval = Apery20160815
		2 threads
		b6000 , 359 - 5 - 256(58.37% R58.74)

		技巧には相性いいみたい。

		engine1 = YaneuraOuV359d , eval = Apery20160815
		engine2 = SM_V110/SILENT_MAJORITY_AVX2_x64.exe , eval = Apery20160815
		b5000 , 220 - 28 - 202(52.13% R14.83)

		魔女にはいまひとつ。

	V3.59e forked from V3.59d
		Use predicted depth for history pruning
		https://github.com/official-stockfish/Stockfish/commit/7396c08b795191d954528d687e84d7ff6dbe7a3b

		engine1 = YaneuraOuV359d , eval = Apery20160815
		engine2 = YaneuraOuV359e , eval = Apery20160815
		play_time = b1000 ,  1438 - 55 - 1507(48.83% R-8.14)


	V3.59f forked from V3.59e
		通常探索の1手詰め判定、変更したほうが良いのでは…。
	-		if (!RootNode && !ttHit && depth > ONE_PLY && !InCheck)
	+		if (!RootNode && !ttHit && !InCheck)

		b1000,	632 - 22 - 626(50.24% R1.66)
		b3000,  142 - 3 - 115(55.25% R36.64)
		b5000,  228 - 17 - 225(50.33% R2.3)

		engine1 = YaneuraOuV359e , eval = Apery20160815
		engine2 = YaneuraOuV359f , eval = Apery20160815
		play_time = b3000 ,  934 - 58 - 1008(48.09% R-13.25)

		検知できる程度の差にならないな…。たぶんdepth > ONE_PLYの条件は外したほうがいいのだろうけど。外すか。

	V3.59g forked from V3.59e

		逆にdepth > 2*ONE_PLYぐらいのほうがいいかも。
	-		if (!RootNode && !ttHit && depth > ONE_PLY && !InCheck)
	+		if (!RootNode && !ttHit && depth > ONE_PLY*2 && !InCheck)
	
		engine1 = YaneuraOuV359e , eval = Apery20160815
		engine2 = YaneuraOuV359g , eval = Apery20160815
		play_time = r500 ,  1522 - 35 - 1443(51.33% R9.26)

		engine1 = YaneuraOuV359e , eval = Apery20160815
		engine2 = YaneuraOuV359g , eval = Apery20160815
		play_time = b3000 ,  495 - 23 - 482(50.67% R4.62)

		engine1 = YaneuraOuV359e , eval = Apery20160815
		engine2 = YaneuraOuV359g , eval = Apery20160815
		play_time = b6000 ,  485 - 37 - 478(50.36% R2.53)

		よくなさげ。

	V3.59h forked from V3.59f
		Simplify IID
		https://github.com/official-stockfish/Stockfish/commit/5596492f6ed72ebc52a4d0f65bed483568e48918

		→　IIDは、置換表が逼迫しない限り関係ないのでこのまま受け入れておく。

		Do LMR on captures
		https://github.com/official-stockfish/Stockfish/commit/8493c8c6b8da07a454adcaa160af8e8aa3d6b525

		engine1 = YaneuraOuV359f , eval = Apery20160815
		engine2 = YaneuraOuV359h , eval = Apery20160815
		play_time = r300 ,  2350 - 62 - 2588(47.59% R-16.76)

		engine1 = YaneuraOuV359f , eval = Apery20160815
		engine2 = YaneuraOuV359h , eval = Apery20160815
		play_time = b1000 ,  2435 - 102 - 2463(49.71% R-1.99)

		engine1 = YaneuraOuV359f , eval = Apery20160815
		engine2 = YaneuraOuV359h , eval = Apery20160815
		play_time = b3000 ,  481 - 14 - 505(48.78% R-8.46)

		計測できる差ではなさげだが、まあいいか。


	V3.59i forked from V3.59h
		captureOrPawnPromotion、単にcaptureOrPromotionにすると本当に駄目なのか？

		-			bool captureOrPawnPromotion = pos.capture_or_pawn_promotion(move);
		+			bool captureOrPawnPromotion = pos.capture_or_promotion(move);

			play_time = r300 ,  2626 - 73 - 2301(53.3% R22.95)
			play_time = b1000 , 1191 - 49 - 1010(54.11% R28.64)

			→　駄目のようだ。

	V3.59j forked from V3.59h

		歩の成りを角、飛車の成りにまで拡大するとオーダリング性能は落ちるのだろうか？

		-	bool captureOrPawnPromotion = pos.capture_or_pawn_promotion(move);
		+	bool captureOrPawnPromotion = pos.capture_or_valuable_promotion(move);

			play_time = r300 ,  2566 - 76 - 2358(52.11% R14.69)
			play_time = b1000 , 311 - 9 - 280(52.62% R18.24)

			→　駄目のようだ。

	V3.59k forked from V3.59h

		// captureのみに絞ったほうが良い可能性
		-	bool captureOrPawnPromotion = pos.capture_or_pawn_promotion(move);
		+	bool captureOrPawnPromotion = pos.capture(move);

		play_time = r300 ,  2449 - 76 - 2475(49.74% R-1.83)
		play_time = b1000 ,  2447 - 82 - 2471(49.76% R-1.7)
		play_time = b3000 ,  989 - 44 - 967(50.56% R3.91)

		// 成りがこんなに低いなら歩の捕獲をcaptureから除外しても良さそうなもんだけどな…。


・局面、depth 8で1億作るのどれくらいかかるんだろうか…。
	40HTで40万局面10分ぐらい？10*250=2500分でいけるのか。4並列で625分。ふーん…。
	いま見た感じ、もうちょっと早く済みそう。360分ぐらいでいけそう。
	
	
■　2016/08/19

・Jenkinsの最後に終了したJobがどれだかわからない問題、
　終了するときに空のファイルを共有フォルダに作るとかすべきか？そんな原始的な…。


・探索部もう少し突っ込んで改良する。
	作業、2016-late-searchのほうでやるか…。

		V3.57
		move_picker		
		capturesで歩の成り、考慮しないほうが良い？
				m.value =// (pawn_promo ? (Value)(Eval::ProDiffPieceValue[PAWN]) : VALUE_ZERO)
			//      +

			engine1 = YaneuraOuV356a.exe , eval = Apery20160815
			engine2 = YaneuraOuV357.exe , eval = Apery20160815
			play_time = r300 ,  4828 - 121 - 5051(48.87% R-7.84)
			b1000 , 2989 - 134 - 3047(49.52% R-3.34)

		V3.57a
		evasionでLVAはやらないほうがよさげ？
			m.value = (Value)Eval::CapturePieceValue[pos.piece_on(move_to(m))]
			//	- Value(LVA(type_of(pos.moved_piece_before(m))))
				+ HistoryStats::Max;
			→　Stockfishでも似たことはやっているのでやったほうがよさげ。
				Aperyと魔女が何故やってないのかは知らないが…。

				engine1 = YaneuraOuV356a.exe , eval = Apery20160815
				engine2 = YaneuraOuV357a.exe , eval = Apery20160815
				r300 , 2091 - 56 - 1633(56.15% R42.95)
				b1000, 1414 - 45 - 1111(56.0% R41.89)

			→　外すとめっさ弱くなる。マジっぽい。なんでなの？ここ以外に何かいじった？
				ちょっと尋常じゃない。そんなに変わるほうがおかしいと思うのだが…。

		V3.57b
		BadCaptureの処遇は？
			  QUIETS,                       // CAPTURES_PRO_PLUSで生成しなかった指し手を生成して、一つずつ返す。SEE値の悪い手は後回し。
			  BAD_CAPTURES,                 // 捕獲する悪い指し手(SEE < 0 の指し手だが、将棋においてそこまで悪い手とは限らない)
			こうすると？(V3.58の改造+この改造)

			engine1 = YaneuraOuV356a.exe , eval = Apery20160815
			engine2 = YaneuraOuV357b.exe , eval = Apery20160815
			r300 ,  2585 - 62 - 2993(46.34% R-25.46)

			engine1 = YaneuraOuV356a.exe , eval = Apery20160815
			engine2 = YaneuraOuV357b.exe , eval = Apery20160815
			b1000 , 1051 - 43 - 1256(45.56% R-30.95)

			engine1 = YaneuraOuV357.exe , eval = Apery20160815
			engine2 = YaneuraOuV357b.exe , eval = Apery20160815
			2759 - 66 - 3095(47.13% R-19.96)

			engine1 = YaneuraOuV357b.exe , eval = Apery20160815
			engine2 = SM_V110/SILENT_MAJORITY_AVX2_x64.exe , eval = Apery20160815
			b2000 , 226 - 15 - 199(53.18% R22.1)

	この処理、やはり+1が正しい気がする。
	-	  (ss - 2)->counterMoves->update(prevPc, prevSq, -bonus - 2 * (depth + ONE_PLY) / ONE_PLY - 1);
	+	  (ss - 2)->counterMoves->update(prevPc, prevSq, -bonus - 2 * (depth + 1) / ONE_PLY - 1);

	Searchの、movetimeとかponderとかの変数が一箇所に書いてあるの、行を分けないとIntelliSenseが機能しない。
	なおしておく。

	Search::search_endの説明が間違ってる気がする。消す。
	  // この値がマイナスのときは、startTimeFromPonderhit - (search_end) >= now() になったら停止。


・気になるのであとで調べる。
	https://twitter.com/merom686/status/765463718146641920
	 merom686 > 魔女でたまに35000くらいの謎点数が表示されるのって、静止探索の枝刈りの条件が futilityBase >  -ScoreInfinite  で（-ScoreKnownWinではなくて）、負けを読み切った局面でもfutilityBaseでスコアを更新するから？
	https://twitter.com/merom686/status/765464617417977856
	merom686 > 35000くらいの大きい数になるのは、ScoreMateInMaxPlyより少し小さい数をセンチポーン補正で1割くらい大きく表示してるから。

	→　やねうら王の実装で正しい気がしてきた。
	念のため、qsearchの以下のところをVALUE_INFINITEに書き換えて試してみる。
			V3.57c
				&&  futilityBase > -VALUE_KNOWN_WIN)

			engine1 = YaneuraOuV357b.exe , eval = Apery20160815
			engine2 = YaneuraOuV357c.exe , eval = Apery20160815
			r300 , 4463 - 107 - 4480(49.9% R-0.66)

			1万局で計測できるレベルの差を生まない。StockfishもVALUE_KNOWN_WINだし元のままでいいや。
			こんなところいまさら書き換えると置換表のassertで引っかかりかねん。


・自己対戦の結果を安定させるために、互角の局面集みたいなのを作ったほうが良いかも。
　やねうら大定跡を用いるという手もあるか…。
	　→　0.2秒以上なら問題なさそうなのでまあいいや。

・同種のソフトと対局させても強くなっているとは言えないところがアレだな…。技巧とも対局させていくべきか…。

	V3.57d forked from V3.57b
		null_moveのあと、2 * Tempoで手番の価値を計算しているところ、evaluate()に変更して本当に弱くなるのか？
		search()のほう変更して様子見。

			engine1 = YaneuraOuV357b.exe , eval = Apery20160815
			engine2 = YaneuraOuV357d.exe , eval = Apery20160815
			play_time = r200 ,  1512 - 45 - 1443(51.17% R8.11)

			engine1 = YaneuraOuV357b.exe , eval = Apery20160815
			engine2 = YaneuraOuV357d.exe , eval = Apery20160815
			play_time = b1000 ,  1464 - 53 - 1483(49.68% R-2.24)

			b3000 , 935 - 63 - 972(49.03% R-6.74)

			engine1 = YaneuraOuV357b.exe , eval = Apery20160815
			engine2 = YaneuraOuV357d.exe , eval = Apery20160815
			play_time = b5000 ,  468 - 32 - 500(48.35% R-11.49)

			長い持ち時間ではそうでもなさげ？うむむ？

	V3.57e forked from V3.57d
			qsearch()のほうも同様にTempo消して、1秒、5秒で回しておく。

			b1000 , 586 - 11 - 583(50.13% R0.89)


・R300とr300との違い
		engine1 = YaneuraOuV356a.exe , eval = 179_0054G_V4
		engine2 = YaneuraOuV356a.exe , eval = 179_0060G_V4
		play_time = R200 ,  4828 - 160 - 5012(49.07% R-6.5)
		play_time = R300 ,  4864 - 159 - 4977(49.43% R-3.99)
		play_time = r300 ,  4821 - 103 - 5076(48.71% R-8.95)
		play_time = R500 ,  4849 - 187 - 4964(49.41% R-4.07)

		あまり変わらないか…。そうか…。


■　2016/08/18

・SSEなしのときにBitboardの>>=演算子の実装が間違っていたの修正。(ai5さん、thanks！)

・置換表サイズによる強さの違いを計測しておく。
		hash size      :  [16, 256]
		engine1 = YaneuraOuV356a.exe , eval = Apery20160815
		engine2 = YaneuraOuV356a.exe , eval = Apery20160815

		1497 - 46 - 1497(50.0% R-0.0)

		変わらず…。ふーん..。
		8スレッド×10秒だと80倍は必要だから16Mが最適値だとしたらその80倍で1280MBほどないといけないのでは。
		逆に16MBをいくらに縮めると弱くなるのかそっちのほうが大事かも。

		hash size      :  [16, 256]
		play_time = b3000 , 1688 - 96 - 1676(50.18% R1.24)
		3秒でも変わらず。そうなのか…。


		hash size      :  [1, 16]
		engine1 = YaneuraOuV356a.exe , eval = Apery20160815
		engine2 = YaneuraOuV356a.exe , eval = Apery20160815
		play_time = b1000 ,  492 - 15 - 493(49.95% R-0.35)

		hash size      :  [2, 16]
		engine1 = YaneuraOuV356a.exe , eval = Apery20160815
		engine2 = YaneuraOuV356a.exe , eval = Apery20160815
		play_time = b1000 ,  472 - 23 - 505(48.31% R-11.74)

		1MB、CPU cacheに載るのでむしろ強くなる可能性が微レ存。
		まあいいや。hash sizeの変更で強弱はほぼ変わらないということか。
		256MBより大きくても良いのかは謎だが…。


・技巧、自己対戦フレームワークでうまく動くようになったので1,3,5秒でAperyのバイナリと対戦。
	threads = 2

		engine1 = YaneuraOuV356a.exe , eval = Apery20160815
		engine2 = gikou_win_20160606/gikou.exe , eval = dummy
		play_time = b1000 ,  465 - 7 - 528(46.83% R-22.07)

		engine1 = YaneuraOuV356a.exe , eval = Apery20160815
		engine2 = gikou_win_20160606/gikou.exe , eval = dummy
		play_time = b3000 ,  546 - 9 - 445(55.1% R35.53)

		短い時間では技巧有利だが、長い時間では逆転する模様。
		長い時間においては、やねうら王+Apery20160815で技巧を上回っていると言えると思う。


・技巧と長い時間で対局させてチューニング
	→　ソースコードを修正してビルドしなおす必要あり。
	→　いや、そうでもないな。pythonの自己対戦フレームワーク、バイナリでreadline()しているのが問題なのか…。
	→　そうでもなさげ。技巧側、printfで出力しているのをcoutで出力するように修正してビルドしなおしてみる。


	Popenのときに universal_newlines=Trueを指定するように修正。

		- proc = subprocess.Popen(cmds[i & 1] , shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE , stdin = subprocess.PIPE)
		+ proc = subprocess.Popen(cmds[i & 1] , shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE , stdin = subprocess.PIPE , universal_newlines=True)

		-	for line in iter(proc.stdout.readline, b''):
		+	for line in iter(proc.stdout.readline):

	→　Invalid argument…うむむ？

・技巧のほう、printfをcoutを使うように修正。

	修正案)

		synced_printf.h

		#include <iostream>
		#include <utility>

		/**
		 * 排他制御された、printf()関数です.
		 */
		#if 0
		#define SYNCED_PRINTF(...) { \
		  g_synced_printf_mutex.lock();      \
		  std::printf(__VA_ARGS__);  \
		  g_synced_printf_mutex.unlock(); }
		#else

		//	This is a termination condition to stop that template being infinitely recursive
		inline void SYNCED_PRINTF(){}

		template<typename First, typename ...Rest>
		void SYNCED_PRINTF(First && first, Rest && ...rest)
		{
		  g_synced_printf_mutex.lock();
		  std::cout << std::forward<First>(first);
		  SYNCED_PRINTF(rest...);
		  std::cout << std::endl;
		  g_synced_printf_mutex.unlock();
		}
		#endif
		↓
		あかん。printfの%sを利用してるところがある…。
		こう書き換える。

		#include <iostream>
		#define SYNCED_PRINTF(...) { \
		  g_synced_printf_mutex.lock();    \
		  char _BUF[4096];                 \
		  std::sprintf(_BUF,__VA_ARGS__);  \
		  std::cout << _BUF;               \
		  g_synced_printf_mutex.unlock(); }
		 
		→　pythonの自己対戦フレームワークでうまく対局できるようになった。
		原因はよくわからないが、printf()をcoutに変更すれば直るということで間違いなさげ。
		printf()、バッファリングしないことが仇になっているのかも。
		coutはendlか何かがあるまではバッファリングするのだろうし。

		Jenkinsのjob化したときにjobのキャンセルに対して、技巧のプロセスが残る。
		うーん…。標準入力のpollingの仕方の問題だとは思うけど、嫌らしいなぁ…。
		40プロセスもタスクマネージャーから終了させるのはしんどい。

		やねうら王の場合、こう待機しているが、技巧はこれをやっていないからEOFが来ても終了しないのでは…。
		  if (!getline(cin, cmd)) // 入力が来るかEOFがくるまでここで待機する。
			cmd = "quit";
		ああ、わかった。
		OnQuitCommandEntered()が呼ばれないのか。これバグだな。

			-		  for (std::string line; std::getline(std::cin, line) ; ) {

			+		  for (std::string line; ; ) {
			+			if (!std::getline(std::cin, line))
			+				line = "quit";

		こうすべき？

		ReceiveCommands()のほうか。

			-	  for (std::string command;std::getline(std::cin, command);) {

			+	  for (std::string command; ;) {
			+		if (!std::getline(std::cin, command))
			+			command = "quit";

		よし、これでうまく動いた。出村さんに報告しておく。

		→　しておいた。

			https://github.com/gikou-official/Gikou/issues/5
			ReceiveCommands()なのですが、readline()の返し値を見てforループを抜ける構造になっていますが、このときquit処理をしないのでプロセスが終了しないです。Windows環境でCtrl+Z、Linux環境でCtrl+Dが送られてきたときにreadline()から抜けるのですが、このときにプロセスが残って困ります。あるいは、Pythonなどからsubprocessとして起動したときに、親側が死んだときにsubprocess側にはEOFが送られてくるのですが、このときreadline()の返し値は0になるので、このときに正常に終了しないとプロセスが残って困るのです。

			修正案として、getlineの返し値を見て、"quit"コマンドが送られてきたと解釈するのがお手軽だと思います。
			  for (std::string command; ;) {
				if (!std::getline(std::cin, command))
					command = "quit";

			よろしくお願い致します。

		→　よし、自己対戦フレームワークの終了に伴い、技巧が正しく終了するようになった。


■　2016/08/17

・30億局面、1 iteration by SGD
	まだ下がりそう。30億局面、1 iterationでは足りないのか…。そうか…。3,4回は回したほうが良いのかも…。

	179_0045G_V4
	ちょっと比べてみる。

		engine1 = YaneuraOuV356a.exe , eval = Apery20160812
		engine2 = YaneuraOuV356a.exe , eval = 179_0045G_V4
		play_time = r200 ,  496 - 7 - 497(49.95% R-0.35)

		engine1 = YaneuraOuV356a.exe , eval = Apery20160812
		engine2 = YaneuraOuV356a.exe , eval = 179_0045G_V4
		play_time = b1000 ,  575 - 11 - 414(58.14% R57.07)

		engine1 = YaneuraOuV356a.exe , eval = Apery20160812
		engine2 = YaneuraOuV356a.exe , eval = 179_0045G_V4
		play_time = b5000 ,  548 - 17 - 435(55.75% R40.12)

	まだ負けてるか。もう少し回さないと。

		engine1 = YaneuraOuV356a.exe , eval = 179_0042G_V3
		engine2 = YaneuraOuV356a.exe , eval = 179_0045G_V4
		play_time = b1000 ,  408 - 8 - 584(41.13% R-62.3)

		engine1 = YaneuraOuV356a.exe , eval = 179_0042G_V3
		engine2 = YaneuraOuV356a.exe , eval = 179_0045G_V4
		play_time = b5000 ,  371 - 17 - 612(37.74% R-86.95)

	前のところからはずいぶん強くなってるのにな…。

	179_0047G_V4

		30億×2
			rmse = 0.0956222 , mean_error = 384.207
			..all works..done!!
			save_eval() finished. folder = \\WS2012_860C_YAN\yanehome\eval\learn_9/6

		engine1 = YaneuraOuV356a.exe , eval = Apery20160812
		engine2 = YaneuraOuV356a.exe , eval = 179_0047G_V4
		play_time = b1000 ,  504 - 10 - 486(50.91% R6.32)

		engine1 = YaneuraOuV356a.exe , eval = Apery20160812
		engine2 = YaneuraOuV356a.exe , eval = 179_0047G_V4
		play_time = b1000 ,  502 - 13 - 485(50.86% R5.98)

		engine1 = YaneuraOuV356a.exe , eval = 179_0045G_V4
		engine2 = YaneuraOuV356a.exe , eval = 179_0047G_V4
		play_time = b1000 ,  489 - 13 - 498(49.54% R-3.17)

		ほぼ互角っぽい。まだサチっていないなら、もう60億ほど回したほうがいいな…。

		engine1 = YaneuraOuV356a.exe , eval = 179_0054G_V4
		engine2 = YaneuraOuV356a.exe , eval = haku20160729
		play_time = b1000 ,  531 - 5 - 464(53.37% R23.43)

		engine1 = YaneuraOuV356a.exe , eval = Apery20160815
		engine2 = YaneuraOuV356a.exe , eval = 179_0047G_V4
		play_time = b1000 ,  525 - 6 - 469(52.82% R19.59)

		まだ最新版には負けているのか。

		engine1 = YaneuraOuV356a.exe , eval = Apery20160505
		engine2 = YaneuraOuV356a.exe , eval = 179_0047G_V4
		play_time = b1000 ,  327 - 7 - 666(32.93% R-123.57)
		play_time = b2000 ,  340 - 7 - 653(34.24% R-113.37)

	179_0054G_V4
		さらに30億×2
			rmse = 0.0936538 , mean_error = 365.137
			7537930000 sfens , at Wed Aug 17 19:10:42 2016

				engine1 = YaneuraOuV356a.exe , eval = 179_0054G_V4
				engine2 = YaneuraOuV356a.exe , eval = Apery20160812

				r300 , 680 - 7 - 613(52.59% R18.02)

				engine1 = YaneuraOuV356a.exe , eval = 179_0054G_V4
				engine2 = YaneuraOuV356a.exe , eval = Apery20160815
				b3000 , 419 - 18 - 473(46.97% R-21.06)

	179_0060G_V4
		さらに30億×2
			rmse = 0.092966 , mean_error = 359.047

				engine1 = YaneuraOuV356a.exe , eval = 179_0054G_V4
				engine2 = YaneuraOuV356a.exe , eval = 179_0060G_V4
				play_time = R100 ,  4953 - 126 - 4921(50.16% R1.13)

				engine1 = YaneuraOuV356a.exe , eval = 179_0054G_V4
				engine2 = YaneuraOuV356a.exe , eval = 179_0060G_V4
				play_time = R200 ,  4828 - 160 - 5012(49.07% R-6.5)

				engine1 = YaneuraOuV356a.exe , eval = 179_0054G_V4
				engine2 = YaneuraOuV356a.exe , eval = 179_0060G_V4
				play_time = b1000 ,  471 - 21 - 508(48.11% R-13.14)

		R100だと差が見えないか。R100駄目だな…。R200以上だな。

				engine1 = YaneuraOuV356a.exe , eval = Apery20160815
				engine2 = YaneuraOuV356a.exe , eval = 179_0060G_V4
				play_time = r100 ,  4610 - 74 - 5316(46.44% R-24.75)

				engine1 = YaneuraOuV356a.exe , eval = Apery20160815
				engine2 = YaneuraOuV356a.exe , eval = 179_0060G_V4
				play_time = R100 ,  4713 - 81 - 5206(47.51% R-17.28)

				engine1 = YaneuraOuV356a.exe , eval = Apery20160815
				engine2 = YaneuraOuV356a.exe , eval = 179_0060G_V4
				play_time = b1000 ,  506 - 10 - 484(51.11% R7.72)

				engine1 = YaneuraOuV356a.exe , eval = Apery20160815
				engine2 = YaneuraOuV356a.exe , eval = 179_0060G_V4
				play_time = b3000 ,  518 - 11 - 471(52.38% R16.52)

		まだAperyにこの評価関数は負けているのか。

・魔女と

	engine1 = YaneuraOuV356a.exe , eval = Apery20160815
	engine2 = SM_V110/SILENT_MAJORITY_AVX2_x64.exe , eval = Apery20160815
	engine_threads = 4
	play_time = b1000 ,  488 - 29 - 483(50.26% R1.79)
	play_time = b3000 ,  481 - 42 - 477(50.21% R1.45)
	play_time = b5000 ,  138 - 18 - 124(52.67% R18.58)
	play_time = b5000 ,  178 - 18 - 164(52.05% R14.23)
	play_time = b10000 ,  373 - 69 - 348(51.73% R12.05)
	play_time = b15000 ,  244 - 35 - 291(45.61% R-30.6)
	
	互角ぐらいと見て良いのでは。15秒で負け越したのが少し気分が悪いが、これ、計算資源的に現実的には計測できない。


・新自己対戦フレームワークでHTありにて計測

	engine1 = YaneuraOuV356a.exe , eval = Apery20160505
	engine2 = YaneuraOuV356a.exe , eval = Apery20160803
	play_time = r100 ,  4423 - 73 - 5504(44.56% R-37.98)

	engine1 = YaneuraOuV356a.exe , eval = Apery20160505
	engine2 = YaneuraOuV356a.exe , eval = Apery20160815
	play_time = b2000 ,  391 - 10 - 599(39.49% R-74.1)

	engine1 = YaneuraOuV356a.exe , eval = Apery20160505
	engine2 = YaneuraOuV356a.exe , eval = Apery20160815
	play_time = b5000 ,  288 - 7 - 705(29.0% R-155.52)

	engine1 = YaneuraOuV356a.exe , eval = Apery20160812
	engine2 = YaneuraOuV356a.exe , eval = Apery20160815
	play_time = r300 ,  4736 - 130 - 5134(47.98% R-14.02)

	engine1 = YaneuraOuV356a.exe , eval = Apery20160730
	engine2 = YaneuraOuV356a.exe , eval = Apery20160803
	play_time = r100 ,  4676 - 86 - 5238(47.17% R-19.72)
	やはり、Aperyの0730→0803は強くなっていたのか。そうか…。

・技巧も自己対戦フレームワークで対局できるようにする。
	engine_threadsも自己対戦フレームワークで指定できるように。
	jenkinsのjobも修正。

	> start /B /WAIT /NODE %EXECUTOR_NUMBER% c:/python27/python.exe %YANEHOME%\script\engine_invoker2.py %YANEHOME% %ENGINE1% %EVAL1%  %ENGINE2% %EVAL2% %HT_CORES% %LOOP% %EXECUTOR_NUMBER% %ENGINE_THREADS% { %TIMES% }

	→　修正した。

	→　技巧、標準出力が細切れでやってくる。なんぞこれ。わけがわからん…。

	[7]>info depth
	[7]>10 se
	[7]>ldepth 10 time 32 nodes 25423 nps 794468 hashfull 999 score cp 120 multipv 1 pv 2b4d
	[7]>4i5h 6a5b 5g5f
	[7]>5d6e 4f5e 4d2b 5e6d 5a4a 5f5e

	技巧のソースコード見て、修正してビルドしなおすか…。
	

・魔女と長い時間で対局させてチューニング
・魔女を自己対戦フレームワークで動作させる。
	→　たぶん動くようになった。
	engine_threads 4でぶん回しておく。2秒,5秒で1000回。
	→　評価関数バイナリの最初の読み込みにめっさ時間かかる…。
	→　動作自体は無事動いてくれている模様。



・前回の30億局面をもとに学習を回しておく。

		Options[EvalDir] = eval/179_0042G_V3
		Options[EvalSaveDir] = \\WS2012_860C_YAN\yanehome\eval\learn_9
		Options[Threads] = 40
		Options[Hash] = 4096
		Options[EvalShare] = false
		learn from 146.bin , 147.bin , 149.bin , learn , dir = \\WS2012_860C_YAN\yanehome\learn_sfen , loop = 2

		Gradient Method : SGD
		Loss Function   : CROSS_ENTOROPY
		mini-batch size : 1000000
		init..info string use non-shared eval_memory.
		init done.

		open filename = \\WS2012_860C_YAN\yanehome\learn_sfen/146.bin 
		70000 sfens , at Tue Aug 16 10:53:36 2016

		rmse = 0.110197 , mean_error = 452.911
		…

・isreadyが連続対局のときやサーバー対局のときに毎回送られてくることは保証されているのか？
	USIプロトコルでは、
		>  対局開始前に送ります。
	とあるな…。

	将棋所では連続対局のときに
		isready
		usinewgame
	の両方を送ってくるようだ。

	だとしたら、usinewgameが要らない子なような…。
	Stockfishのほうは、いつの間にか、ucinewgameのほうでSearchの初期化をやるように修正されてる。うーむ..。
	まあいいや。usinewgame使わないほうが、手でコマンド送るときに楽なのでこれで初期化するのはやらないようにしよう。
	
	将棋所でのサーバー対局でも同様の動作かテストしておく。
	isreadyコマンドはfloodgateのサーバー側から送られてくるようだ。
	だとしたら対局ごとにisreadyが送られてくるかどうかはサーバー側依存なのでは…。


■　2016/08/16


・無教師から学習させていたものがそれなりの強さになったようだ。これを育てていく。

・あー、別のプロセッサグループのほうで確保している共有メモリ上の評価関数バイナリにアクセスしてnps下がる問題があるのか…。
	弱くなるのは、これかも知れん…。この問題、回避できるか考えるか…。
	Numa指定しているので、これで回避するか。
	→　そうした。

		auto dir_name = (string)Options["EvalDir"] + "Numa" + (string)Options["EngineNuma"];


・新Apery評価関数

		engine1 = YaneuraOuV356.exe , eval = Apery20160812
		engine2 = YaneuraOuV356.exe , eval = Apery20160815
		play_time = R100 ,  459 - 9 - 532(46.32% R-25.64)

		engine1 = YaneuraOuV355c.exe , eval = Apery20160812
		engine2 = YaneuraOuV355c.exe , eval = Apery20160815
		play_time = r100 ,  4608 - 88 - 5304(46.49% R-24.44)

・
	pythonの自己対戦スクリプトでこのモードを使うオプション追加。
	R100と指定したときにnodes as timeモードでgo rtimeすればいい。

・npmsec(nodes time)実装。

	StockfishのこのコードだとavailableNodesマイナスになるな…。

		if (Limits.npmsec)
			Time.availableNodes += Limits.inc[us] - Threads.nodes_searched();

			↓正しい

		if (Limits.npmsec)
			Time.availableNodes = std::max(Time.availableNodes + Limits.inc[us] - Threads.nodes_searched() , (s64)0);

	→　うまく動くようになった。

		nodestime 600
		bookfile no_book
		threads 1
		isready
		go btime 0 wtime 0 byoyomi 10000


・棋譜生成中に一回落ちたようだ。まだ何かバグがあるのか？

	王がいないのに駒を入れ替えようとしている気がする。修正。

	-	  if (rand(5) == 0 && !pos.in_check())
	+	  if (rand(5) == 0 && !pos.in_check() && pos.pieces(pos.side_to_move()).pop_count() >= 6)

	→　局面生成、盤上に王が1枚しかないときに盤上の2駒を交換しようとするバグ修正。

・結論的には論理コア数で対局させている部分が勝率が偏る原因なのかも。

V3.55d
・勝率が偏る何らかのバグがあるのではなかろうか。
	・試合ごとに100%先後入れ替えを行うコードに変更。

	・node timeを使うようにして実験して結果を比較する。
	rtime 100、探索ノード数、えらくバラけるのな…。計測する。

	r800でこんなにノード数がばらけるのか…。
		[0]>[0]:nodes = 20363864
		[1]>[1]:nodes = 20744891
		[2]>[2]:nodes = 21874493
		[3]>[3]:nodes = 21750293
		[4]>[4]:nodes = 22399119
		[5]>[5]:nodes = 21734169
		[6]>[6]:nodes = 21752231
		[7]>[7]:nodes = 21675186
		[8]>[8]:nodes = 21572781
		[9]>[9]:nodes = 21487627
		[10]>[10]:nodes = 20881973
		[11]>[11]:nodes = 20663296
		[12]>[12]:nodes = 22916210
		[13]>[13]:nodes = 22998869
		[14]>[14]:nodes = 26664840
		[15]>[15]:nodes = 26381428
		[16]>[16]:nodes = 24247710
		[17]>[17]:nodes = 24819605
		[18]>[18]:nodes = 21067147
		[19]>[19]:nodes = 21018924
		[20]>[20]:nodes = 23893265
		[21]>[21]:nodes = 24507673
		[22]>[22]:nodes = 21255278
		[23]>[23]:nodes = 20963676
		[24]>[24]:nodes = 20965547
		[25]>[25]:nodes = 21068620
		[26]>[26]:nodes = 22536674
		[27]>[27]:nodes = 22111534
		[28]>[28]:nodes = 22879069
		[29]>[29]:nodes = 22788974
		[30]>[30]:nodes = 21381039
		[31]>[31]:nodes = 21017634
		[32]>[32]:nodes = 21315693
		[33]>[33]:nodes = 21722500
		[34]>[34]:nodes = 26349641
		[35]>[35]:nodes = 26164092
		[36]>[36]:nodes = 20930819
		[37]>[37]:nodes = 20491492
		[38]>[38]:nodes = 19211609
		[39]>[39]:nodes = 18682395
		[40]>[40]:nodes = 27855861
		[41]>[41]:nodes = 27651489
		[42]>[42]:nodes = 21556602
		[43]>[43]:nodes = 21282200
		[44]>[44]:nodes = 22478077
		[45]>[45]:nodes = 22968655
		[46]>[46]:nodes = 20460481
		[47]>[47]:nodes = 19843664
		[48]>[48]:nodes = 20870773
		[49]>[49]:nodes = 20785280
		[50]>[50]:nodes = 23068323
		[51]>[51]:nodes = 23565440
		[52]>[52]:nodes = 21320920
		[53]>[53]:nodes = 21161635
		[54]>[54]:nodes = 21115954
		[55]>[55]:nodes = 20995289
		[56]>[56]:nodes = 21724263
		[57]>[57]:nodes = 21012110
		[58]>[58]:nodes = 23672782
		[59]>[59]:nodes = 22954859
		[60]>[60]:nodes = 15097775
		[61]>[61]:nodes = 15073528
		[62]>[62]:nodes = 29348011
		[63]>[63]:nodes = 28035943
		[64]>[64]:nodes = 22817543
		[65]>[65]:nodes = 22589792
		[66]>[66]:nodes = 28242065
		[67]>[67]:nodes = 27440958
		[68]>[68]:nodes = 21412728
		[69]>[69]:nodes = 20802815
		[70]>[70]:nodes = 27630030
		[71]>[71]:nodes = 27063267
		[72]>[72]:nodes = 17403381
		[73]>[73]:nodes = 17323907
		[74]>[74]:nodes = 16034151
		[75]>[75]:nodes = 15697004
		[76]>[76]:nodes = 22112309
		[77]>[77]:nodes = 21364827
		[78]>[78]:nodes = 22952334
		[79]>[79]:nodes = 22628834

		15097775 - 27630030 : 1.83倍の差

		→　物理コア数の対局に変更してみると？

		[0]>[0]:nodes = 72778726
		[1]>[1]:nodes = 71657256
		[2]>[2]:nodes = 64666496
		[3]>[3]:nodes = 63066345
		[4]>[4]:nodes = 71414765
		[5]>[5]:nodes = 73613827
		[6]>[6]:nodes = 56565616
		[7]>[7]:nodes = 58077844
		[8]>[8]:nodes = 68926843
		[9]>[9]:nodes = 69559993
		[10]>[10]:nodes = 74962515
		[11]>[11]:nodes = 74549508
		[12]>[12]:nodes = 70282782
		[13]>[13]:nodes = 68744785
		[14]>[14]:nodes = 60240593
		[15]>[15]:nodes = 61250890
		[16]>[16]:nodes = 68752998
		[17]>[17]:nodes = 69279530
		[18]>[18]:nodes = 68655945
		[19]>[19]:nodes = 66190164
		[20]>[20]:nodes = 57567300
		[21]>[21]:nodes = 56114884
		[22]>[22]:nodes = 54486533
		[23]>[23]:nodes = 52976596
		[24]>[24]:nodes = 66878126
		[25]>[25]:nodes = 68354855
		[26]>[26]:nodes = 72467258
		[27]>[27]:nodes = 72728019
		[28]>[28]:nodes = 68099646
		[29]>[29]:nodes = 67738500
		[30]>[30]:nodes = 68910429
		[31]>[31]:nodes = 68203175
		[32]>[32]:nodes = 59719500
		[33]>[33]:nodes = 59823454
		[34]>[34]:nodes = 66506641
		[35]>[35]:nodes = 65057131
		[36]>[36]:nodes = 76214742
		[37]>[37]:nodes = 77401322
		[38]>[38]:nodes = 69462037
		[39]>[39]:nodes = 69251546

		56565616 vs 77401322 : 1.36倍の差。少しマシ。

		// 対局は物理コア数にしたほうが安定するようだ。

		Core i7 4771 HT8 vs PT4

		[0]>[0]:nodes = 3711650
		[1]>[1]:nodes = 3594807
		[2]>[2]:nodes = 3527019
		[3]>[3]:nodes = 3314408
		[4]>[4]:nodes = 3838580
		[5]>[5]:nodes = 3751745
		[6]>[6]:nodes = 4198603
		[7]>[7]:nodes = 4204947
		[8]>[8]:nodes = 3484324
		[9]>[9]:nodes = 3575383
		[10]>[10]:nodes = 4398044
		[11]>[11]:nodes = 4328146
		[12]>[12]:nodes = 3596432
		[13]>[13]:nodes = 3609833
		[14]>[14]:nodes = 2979575
		[15]>[15]:nodes = 2809125

		[0]>[0]:nodes = 10579514
		[1]>[1]:nodes = 10800451
		[2]>[2]:nodes = 9133548
		[3]>[3]:nodes = 8892816
		[4]>[4]:nodes = 9813755
		[5]>[5]:nodes = 9812529
		[6]>[6]:nodes = 11102674
		[7]>[7]:nodes = 10892339

V3.55c
	・2698bがおかしいとしたら評価関数の破壊はされていないわけだから、起動時からおかしいことになるのだが、
	原因が思いつかない。起動時にすべておかしいということは、評価関数を共有していて、ネットワークからの
	評価関数の読み込みに失敗している可能性が高いが、それを検知することは簡単には出来ない。
	CreateしたときにのみevalのCheckSumの値を表示するか？
	→　そんなことをせずともnodetimeにして結果が一致すれば、2698b、悪くないことになるのだが。
	ときどきメモリが破損するとしたらそうでもないか。Createに対してなんとかするか。うむむ…。
	"DISPLAY"の文字が含まれているときはpythonスクリプトのほうで表示することにするか。
	→　2698b、やはりそんな問題ではなさげなのだが…。
	
		check_sum = 28137038

		engine1 = YaneuraOuV353.exe , eval = Apery20160812
		engine2 = YaneuraOuV355c.exe , eval = Apery20160812
		play_time = r500 ,  434 - 20 - 546(44.29% R-39.88)

		engine1 = YaneuraOuV353.exe , eval = Apery20160812
		engine2 = YaneuraOuV355c.exe , eval = Apery20160812
		play_time = r500 ,  420 - 13 - 567(42.55% R-52.13)

		engine1 = YaneuraOuV353.exe , eval = Apery20160812
		engine2 = YaneuraOuV355c.exe , eval = Apery20160812
		play_time = r500 ,  425 - 13 - 562(43.06% R-48.54)

		engine1 = YaneuraOuV353.exe , eval = Apery20160812
		engine2 = YaneuraOuV355c.exe , eval = Apery20160812
		play_time = r500 ,  430 - 10 - 560(43.43% R-45.89)

		engine1 = YaneuraOuV353.exe , eval = Apery20160812
		engine2 = YaneuraOuV355c.exe , eval = Apery20160812
		play_time = r500 ,  445 - 12 - 543(45.04% R-34.58)

		engine1 = YaneuraOuV353.exe , eval = Apery20160812
		engine2 = YaneuraOuV355c.exe , eval = Apery20160812
		play_time = r500 ,  458 - 13 - 529(46.4% R-25.04)

		engine1 = YaneuraOuV353.exe , eval = Apery20160812
		engine2 = YaneuraOuV355c.exe , eval = Apery20160812
		play_time = r600 ,  423 - 16 - 561(42.99% R-49.05)

		engine1 = YaneuraOuV353.exe , eval = Apery20160812
		engine2 = YaneuraOuV355c.exe , eval = Apery20160812
		play_time = r700 ,  473 - 11 - 516(47.83% R-15.12)

		engine1 = YaneuraOuV353.exe , eval = Apery20160812
		engine2 = YaneuraOuV355c.exe , eval = Apery20160812
		play_time = r800 ,  420 - 11 - 569(42.47% R-52.75)



V3.55b

・深いdepthでの枝刈り
	cf. https://github.com/official-stockfish/Stockfish/commit/714329dbdc3c32af6e899c85409935dc3b6d799c
			  // 次の子nodeにおいて浅い深さになる場合、負のSSE値を持つ指し手の枝刈り
			  if (predictedDepth < PARAM_FUTILITY_AT_PARENT_NODE_SEE_DEPTH * ONE_PLY && pos.see_sign(move) < VALUE_ZERO)
				  continue;

				  ↓

			  // 浅いdepthで負のSSE値を持つ指し手と、深いdepthで減少する閾値を下回る指し手の枝刈り
			  if (predictedDepth < 8 * ONE_PLY)
			  {
				  Value see_v = predictedDepth < PARAM_FUTILITY_AT_PARENT_NODE_SEE_DEPTH * ONE_PLY ? VALUE_ZERO
					  : -PawnValue * 2 * Value(predictedDepth - 3 * ONE_PLY);

				  if (pos.see_sign(move) < see_v)
					  continue;
			  }

		engine1 = YaneuraOuV355a.exe , eval = Apery20160812
		engine2 = YaneuraOuV355b.exe , eval = Apery20160812
		play_time = r100 ,  5571 - 83 - 4346(56.18% R43.14)

		→　この枝刈り、長い持ち時間で効果がある可能性も…。

		b2000 , 3987 - 151 - 3112(56.16% R43.04)

		→　そうでもないような？

		engine1 = YaneuraOuV353.exe , eval = Apery20160812
		engine2 = YaneuraOuV355b.exe , eval = Apery20160812
		3735 - 144 - 3411(52.27% R15.76)

		トータルで弱くなってしまった…。

V3.55a
・depth 1でのnull pruning追加。
	cf. https://github.com/official-stockfish/Stockfish/commit/f2f3a06a1acfa14b3054bfd73d6c3966c326a7cc

・NMP(null move pruning)をstaticEvalの値に応じて段階的に適用する。
	cf. https://github.com/official-stockfish/Stockfish/commit/76971d8acba4af1896cf94e1278f69ae2084d45d
	cf.	https://github.com/official-stockfish/Stockfish/commit/ade3bb9a4e774aa9b760235f3b0ee42e0a0420d9

		+        && (ss->staticEval >= beta - 35 * (depth / ONE_PLY - 6) || depth >= 13 * ONE_PLY)


		engine1 = YaneuraOuV355.exe , eval = Apery20160812
		engine2 = YaneuraOuV355a.exe , eval = Apery20160812
		play_time = r100 ,  4019 - 94 - 5887(40.57% R-66.31)

		engine1 = YaneuraOuV355.exe , eval = Apery20160812
		engine2 = YaneuraOuV355a.exe , eval = Apery20160812
		play_time = b2000 ,  1003 - 38 - 959(51.12% R7.79)

		短い時間では効果があるが、長い時間だと効果不明。

V3.55
・ColorFromTo historyを追加。
	cf.
		Use Color-From-To history stats to help sort moves
		https://github.com/official-stockfish/Stockfish/commit/b3525fa9ea88e230a38d72351826cbc16c282938

	・from_sq()追加。
	・FromToStats導入。
		→　これを打ち駒を考慮するように拡張。

		ASSERT_LV3(f < SQ_NB_PLUS1 + 7);
		if (f >= SQ_NB_PLUS1 + 7)
			std::cout << (int)f << " " << from_sq(m);


		engine1 = YaneuraOuV354.exe , eval = Apery20160812
		engine2 = YaneuraOuV355.exe , eval = Apery20160812
		play_time = r100 ,  4916 - 67 - 5017(49.49% R-3.53)
		わずかに強くはなっている模様。

		play_time = r500 ,  864 - 36 - 1370(38.68% R-80.08) : 2698b何かおかしいのでは…。
		？　異常値

		b2000 , 3821 - 157 - 4012(48.78% R-8.47)

		engine1 = YaneuraOuV355.exe , eval = Apery20160812
		engine2 = YaneuraOuV354.exe , eval = Apery20160812
		play_time = r500 ,  4970 - 125 - 4905(50.33% R2.29)

V3.54
・futility margin変更
	cf. https://github.com/official-stockfish/Stockfish/commit/85924db496af2fb8d70b6c89b17fc8541339ca19

	-  Value futility_margin(Depth d) { return Value(200 * d); }
	+  Value futility_margin(Depth d) { return Value(150 * d); }

		　PARAM_FUTILITY_MARGIN_ALPHA を200→150に。

           if (   predictedDepth < 7 * ONE_PLY
	-              && ss->staticEval + futility_margin(predictedDepth) + 256 <= alpha)
 	+              && ss->staticEval + 256 + 200 * predictedDepth / ONE_PLY <= alpha)

		engine1 = YaneuraOuV353.exe , eval = Apery20160812
		engine2 = YaneuraOuV354.exe , eval = Apery20160812
		play_time = r100 ,  4602 - 73 - 5325(46.36% R-25.35)
		play_time = b1000 , 1211 - 26 - 1423(45.98% R-28.02)


■　2016/08/15

・pythonフレームワークによる自己対戦

	Apery20160505      vs Apery20160505 ,  r100 , 5008 - 83 - 4899(50.55% R3.82)

	Apery20160505      vs haku20160729  ,  r100 , 3518 - 75 - 6397(35.48% R-103.87)
	haku20160729no_ave vs haku20160729  ,  r100 , 4956 - 95 - 4939(50.09% R0.6)
	haku20160729       vs Apery20160812 , b2000 , 1032 - 31 - 1507(40.65% R-65.77)
	Apery20160505      vs haku20160729  , b2000 ,  952 - 33 - 1625(36.94% R-92.89)

	Apery20160812      vs haku20160729  ,  r100 , 5227 - 52 - 4711(52.6% R18.06)

	Apery20160812      vs Apery20160810 ,  r100 , 5014 - 71 - 4905(50.55% R3.82)
	Apery20160810      vs Apery20160812 , b2000 ,  1041 - 35 - 1194(46.58% R-23.82)

	Apery20160731      vs Apery20160810 ,  r100 , 5996 - 56 - 3938(60.36% R73.03)   ※3
	Apery20160731      vs Apery20160810 ,  r500 ,  2100 - 34 - 2016(51.02% R7.09)   ※3
	Apery20160731      vs Apery20160810 , b2000 ,  1128 - 25 - 1247(47.49% R-17.42) ※3
	Apery20160810      vs Apery20160731 , b2000 ,  1284 - 17 - 1139(52.99% R20.82)  ※3

	Apery20160505      vs Apery20160812 ,  r100 , 4282 - 52 - 5656(43.09% R-48.35)  ※2
	Apery20160505      vs Apery20160812 , b2000 ,  935 - 30 - 1905(32.92% R-123.63)
	Apery20160505      vs Apery20160812 , b2000 ,  960 - 31 - 1979(32.66% R-125.67)

	Apery20160812      vs 179_0042G_V3  ,  r100 ,  5369 - 39 - 4592(53.9% R27.16)
	Apery20160812      vs 179_0042G_V3  , b2000 ,   707 - 12 - 441(61.59% R81.99)

	Apery20160505(non shared memory) vs Apery20160505(shared memory) , r100 thread4 , 4086 - 104 - 4000(50.53% R3.7)
	

	haku20160729       = finalize時の平均化あり
	haku20160729no_ave = finalize時の平均化なし
	r100 = rtime 100
	b2000 = byoyomi 2000 (ただしNetworkDelay2 = 500)

	※1 共有メモリを使用することによる勝率低下はなさげ。
	※2 以前の自己対戦フレームワークと勝率はさほど違いはなさげ。
	※3 短い時間では正確にでなさげ。Stockfish7では短い時間では枝刈りの性質が長い時間と違うのでは。

・isready()のときのメモリチェックのコード追加。
	→　追加した。



■　2016/08/14

・pythonによる連続自己対戦フレームワーク(仮)
	→　script/engine_invoker2.py追加。

	pythonのsubprocessだとreadがblockingする。Windowsだとこれを回避するのすごく難しい。
	無駄なthread作りたくないというのに…。

		# Non-blocking read on a subprocess.PIPE in python
		# http://stackoverflow.com/questions/375427/non-blocking-read-on-a-subprocess-pipe-in-python
	
		fcntl indeed doesn't work on Windows

		http://code.activestate.com/recipes/440554-module-to-allow-asynchronous-subprocess-use-on-win/

		The portable way: letting the main thread block
		https://repolinux.wordpress.com/2012/10/09/non-blocking-read-from-stdin-in-python/#windows

	ああ、なんとかなった感じ。

		# process is not done, wait a bit and check again.
		time.sleep(0)

	このsleep(0)を入れると1000対局超えたあたりからCPU負荷率が下がっていく。
	OSのスレッドスケジューラーに絡む何かかも。

	pythonのスクリプト側で定跡と時間制御を実装して、もう少し原因を調べてみる。

	sleep(1)で反応ないの、sleep()の単位が1秒だからか…。そうか..
	CPU負荷率下がるの、isreadyとかで待機待ちになっているっぽい？
	→　対局スクリプトにfile loggingの機能追加。ログを精査する。

	gameoverの変数名がgameoveに脱字してて、それゆえdrawのときにフラグが
	適切にセットされていなかった。なんぞ、このバグ…。

	→　pythonで変数宣言強制できたほうが良いのでは…。まあいいや。

	pythonスクリプトに定跡と時間制御実装して、動作テストしよう。

[1]<position startpos moves 2g2f 3c3d 7g7f 8c8d 6g6f 8d8e 8h7g 3a3b 4i5h 7a6b 3i4h 5a4b 5h6g 6a5b 2f2e 4b3a 7i7h 7c7d 2e2d 2c2d 2h2d 2b3c 2d2h P*2d 5i6h 3b2c 6h7i 4a3b 5g5f 9c9d 3g3f 6c6d 2i3g 6b6c 4h5g 8a7c 5g4f 4c4d P*2e 2d2e 1g1f 1c1d 3f3e 3c5a 2h2e 5b4c 2e2f P*2d 7g6h 3d3e 4f3e P*3d 3e2d 2c2d 2f2d 5a2d 6h2d 8e8f 8g8f R*2h 2d6h S*5h
[1]<go btime 5000 wtime 5000 byoyomi 3000
[1]>info nodes 3541614 time 6010
[1]>bestmove 6i5h ponder 2h5h+
	時間余ってる？あれれ？

position startpos moves 2g2f 3c3d 7g7f 8c8d 6g6f 8d8e 8h7g 3a3b 4i5h 7a6b 3i4h 5a4b 5h6g 6a5b 2f2e 4b3a 7i7h 7c7d 2e2d 2c2d 2h2d 2b3c 2d2h P*2d 5i6h 3b2c 6h7i 4a3b 5g5f 9c9d 3g3f 6c6d 2i3g 6b6c 4h5g 8a7c 5g4f 4c4d P*2e 2d2e 1g1f 1c1d 3f3e 3c5a 2h2e 5b4c 2e2f P*2d 7g6h 3d3e 4f3e P*3d 3e2d 2c2d 2f2d 5a2d 6h2d 8e8f 8g8f R*2h 2d6h S*5h
go btime 5000 wtime 5000 byoyomi 3000
→　合ってる気がする…。NetworkDelay絡みか？



■　2016/08/09

Position::is_mated()でstalemateを、玉以外に自駒がいない状態と定義してあるのは間違い。
以下の局面図で、81の銀は動かせるが、動かすと51の飛車に素ぬかれる。
なのでstalemateの判定の仕方は、これではまずく、王手がかかっていないときも
合法手が1つ以上あるかをテストする必要がある。

 玉 銀 □ □^飛^金 □^桂 □
 歩 歩^金 □ □^歩^桂^歩^香
 □ □^と^歩 □^玉□ □ □
 □ □ □^龍^歩 □^金^銀□
 □ □^圭□ □^香□ □^歩
 □^銀 □ □ □ □^歩 □ □
 □^銀^馬 □ □ □ □ □ □
 □ □ □ □ □ □ □ □ □
 □ □ □^杏 □ □ □^馬 □

 ゆえに以下のコードは、破棄。

  // a. 王手している駒がない
  // b. stalemateではない
  // ならば、この時点で不詰めが証明される。
  // b.のstatemateは、c. 玉以外いなくて、d. 手駒がない、かつ、e. 玉の行き場所すべてに相手の利きがある
  // ことがその条件であるが、c.かつd.であることだけここでは調べて、e.は実際の指し手生成で調べることにする。
  // (stalemate自体レアケースなのでそこを高速化してもあまり意味がない)
  // if (a && b) return false;
  // → if (a && !(c && d && e)) return false; // b = !(c && d && e) より
  // → if (a && !(c && d)) return false;      // eはこのあと判定する
  // → if (a && (!c || !d)) return false;     // ドモルガンの法則より
  auto Us = sideToMove;
  if (!st->checkersBB && (hand[Us] != HAND_ZERO || pieces(Us) != Bitboard(king_square(Us))))
    return false;



■　2016/08/05

・自己対戦サーバーで、メッセージをtrapする仕組みを入れるか。
　んー、それにしてもCPU負荷が100%でもないのに探索できないというのはありえないような気もするのだが…。

・メモリ共有、40HTで読み込み中に別のスレッドが壊す/使いはじめるということはあるか?
　　→　読み込み終わるまでmutexで囲われてる…。mutexとmemory mapped fileの解放順序は…問題ないと思う。

・hash size 24MBでシミュレーションしてみる。
	→　table[x & clusterCount]だから配列からはみ出ることがありえないな…。

・評価関数のメモリ、readonlyに出来るか試す。
	→　難しそう。

・局面生成してみる。
	depth 5で20万局面20秒(HT40) 2億局面 = 2万秒
	3PCでも24時間(86400秒)で8億局面×3PC×dual = 50億局面ぐらい生成できるのか。
	depth 5が現実解かも知れない。25億局面ほど生成して追加学習させて強くなるかテストしよう。

	4PC、1000Wのコンセントでギリギリいけそう。
	250(2698)+250(2698)+300(2698)+120(4771) = 920W
	HDDとかプリンター酷使したら落ちたりして…。
	別系統から1000W取ってきて、このあとの2PCと、2698ひとつはそちらから取ろう。
	

■　2016/08/04

・自己対戦の戦績がアテにならんのを何とかする
	・Hash sizeを変えた場合、勝率にどれくらい影響があるのかを調査。
		hash 16MB、32byteで3局面だから、1.5M局面、入るはずなのだが、これで足りないのか？
		0.1秒で埋め尽くされるとは考えにくいのだが…。

		hash 128MBで比較してみる。
		#	f.write("setoption name Hash value 16\n")
			f.write("setoption name Hash value 128\n")

	・0.1秒だと、スレッド負荷が100%にならないという問題はあるようだ。
		→　指し手を返す部分などがあるから、仕方ないか…。

	・local-game-server、エラーをきちんとトラップするように。
		→　local-game-serverというより、python側のスクリプトの問題か？

+			if "Error" in line:
+				print line

		→　エラーはトラップされるようになった。よしよし。

	・pythonからlocal-game-serverをinvokeしているときに途中で結果を返すことは出来るのか？

	pollしてればいいのか…。

		retcode = proc.poll()
		if retcode is not None: # Process finished.
					running_procs.remove(proc)
		print proc.stdout.read()

		→　できた。

	・評価関数の読み込みに失敗したときにexitしているのに負けているのは何なのかを調査
		→　local-game-server、おかしいのでは…。
			local-game-server、もっとみなおす。
		→　わかった。評価関数読み込みに失敗するが、shared memoryは有効になっていて、
		　それを別のプロセスが共有したあと、元のプロセスは終了するのか…。なんぞこれ…。
		
	・評価関数の読み込みに失敗した、駒得だけの評価関数のはずの思考エンジンに負けているのは何なのか
		→　local-game-serverに棋譜を出力させてチェック

			lose,startpos moves 3i3h 8c8d 2g2f 3c3d 6i7h 8d8e 7g7f 8e8f 8g8f 8b8f 2f2e 4a3b 2e2d 2c2d 2h2d 8f7f 8h2b+ 3a2b B*7g 2b2c 2d2c+ 3b2c 7g1a+ P*8h 1a8h P*2h 8h9h 7f7d L*7f 7d4d S*5e 4d9d P*2d 2c2d P*7d 2h2i+ 7d7c+ N*8f 7c6c 8f9h+ 7f7a+ B*9e 8i7g 6a7a P*7b 7a8b P*8c 8b8c 9g9f 9e8f 9i9h R*9i 6c5c 8f7g+ 5i4h P*5b 5e6f 7g7h S*4b 5a6a 7i7h 9i7i+ 7h7g L*7d B*6c 5b5c 3h2i 7d7g+ 4b5c+ G*6b 7b7a+ 6a7a 5c6b 7a6b 6c8a+ 7g6g N*6e 7i8h P*6h 8h6h 4h3i P*7b P*2h 6g6f P*6i 6h6i G*5i 6i8i N*7e N*6g 5i5h B*7f 7e8c+ 8i8c G*8b 8c8i 8a7b 6b5b 7b9d 9c9d R*2b B*4b 2b2a+ 7f6e 2a9a N*5e L*5f 6f5f 5g5f S*6i 5h4h 4b6d L*6f 5e4g 3i3h N*2f 3h4g S*4f 4g3f 4f3g+ 4h3g L*3e 3f4g 3e3g+ 4g5g S*4f 5g6h 8i7h
			lose,startpos moves 5g5f 7a6b 7g7f 5c5d 7i6h 5a4b 3i4h 3c3d 6h7g 3a3b 5i6h 4b3a 6h7h 7c7d 2g2f 6c6d 2f2e 8a7c 9g9f 2b3c 7h7i 1c1d 4i5h 1d1e 2h2f 7c8e 7g6f 6d6e 6f6e 3c8h+ 7i8h B*4d 6g6f 8b9b 2f2h 4d6f 8h9h 7d7e 6e7d 8e7g 8i7g 6f7g+ 7d8c N*6f N*8i 7g7f 8c9b+ 9a9b P*7g 7f9d 5h5g S*7h 5g6f 7h6i N*8f 9d7b B*6d 3a2b 2e2d 2c2d 4h5i G*7h 5i5h 6i5h 2h5h S*6i 5h2h P*8h S*6g 8h8i+ P*2c 2b2c 6g7h 6i7h R*2g 8i9i 9h9i L*2e P*2f N*3e 2f2e 3e2g+ 2e2d 2c1d 2h7h R*6i G*7i 6i6f+ 6d9a+ S*6g 7h9h 6f7g S*7h 6g7h+ 7i7h 7g4g L*7d 7b8c P*6c 6b5c S*8a 4g4i 9i8h 4i2i 8a9b N*8e L*7i 8c8d 9a7c 8d7c 7d7c+ S*9g 9h9g B*2b S*5e 8e9g+ 8h9g 2i1i N*6e L*7g 7h8h 1i7i 8h9h G*9i 9f9e 9i9h 9g9f P*8d B*5h 1d2d 8f7d R*9g 9f8f G*8e 5h8e 9g8g+ 8f7e 8g8e 7e6f 7i6h G*6g B*4h

		→　そこそこ激しい戦型になっているので仕方ないのか。
		→　定跡32手目までにするのやめたほうがいいのか…。序盤がばらけることより、変な戦型で決着がついて勝率が5割に寄る
			デメリットのほうが大きいのでは…。
		→　100局に5局ぐらいがノイズになってしまうと、勝率で5%ぐらい計算が違ってくるか..これはでかいか…。

	・local-game-serverに子プロセスの終了判定のコード追加。
	・local-game-server、プロセスの起動に失敗したときのコード追加。

	・探索ノード数を表示させてみて、一定値を示しているかの調査
	→　まあいいや。負荷率がきちんとしている以上、そこはいま問題ではないだろう。

	・置換表サイズによる差の計測

		// hash 16MB
		c:\jenkins\workspace\yanejob\連続自己対戦>start /B /WAIT /NODE 0 c:/python27/python.exe \\WS2012_860C_YAN\yanehome\script\engine_invoker.py \\WS2012_860C_YAN\yanehome exe\YaneuraOuV347RR2.exe eval/Apery20160505  exe\YaneuraOuV347RR2.exe eval/Haku20160731 40 10000 0 { 100 } 
		home         :  \\WS2012_860C_YAN\yanehome\
		byoyomi_list :  ['100']
		evaldirs     :  ['eval/Haku20160731']
		engine1 = exe\YaneuraOuV347RR2.exe , eval = eval/Apery20160505
		engine2 = exe\YaneuraOuV347RR2.exe , eval = eval/Haku20160731
		threads = 40 , loop = 10000 , numa = 0 , byoyomi = 100
		\\WS2012_860C_YAN\yanehome\\exe\local-game-serverV347.exe , booksfenfile \\WS2012_860C_YAN\yanehome\book/records1.sfen , threads 40 , enginenuma 0 , go btime 10000 , quit
		finish 3895 - 70 - 6035(39.22% R-76.07)

		// hash 128MB
		c:\jenkins\workspace\yanejob\連続自己対戦@2>start /B /WAIT /NODE 1 c:/python27/python.exe \\WS2012_860C_YAN\yanehome\script\engine_invoker.py \\WS2012_860C_YAN\yanehome exe\YaneuraOuV347RR2.exe eval/Apery20160505  exe\YaneuraOuV347RR2.exe eval/Haku20160731 40 10000 1 { 100 } 
		home         :  \\WS2012_860C_YAN\yanehome\
		byoyomi_list :  ['100']
		evaldirs     :  ['eval/Haku20160731']
		engine1 = exe\YaneuraOuV347RR2.exe , eval = eval/Apery20160505
		engine2 = exe\YaneuraOuV347RR2.exe , eval = eval/Haku20160731
		threads = 40 , loop = 10000 , numa = 1 , byoyomi = 100
		\\WS2012_860C_YAN\yanehome\\exe\local-game-serverV347.exe , booksfenfile \\WS2012_860C_YAN\yanehome\book/records1.sfen , threads 40 , enginenuma 1 , go btime 10000 , quit
		finish 4179 - 95 - 5726(42.19% R-54.71)

		// hash 256MB
		final result : 
		engine1 = exe\YaneuraOuV350.exe , eval = eval/Apery20160505
		engine2 = exe\YaneuraOuV350.exe , eval = eval/Haku20160731
		byoyomi = 100 ,  3820 - 79 - 6101(38.5% R-81.34)


	置換表サイズの差ではなく、3%ぐらいはゴミ定跡を掴まされた差が出ると考えるのが自然か。
	ゴミ定跡を掴まされて勝率50%に寄ると仮定すると本来のR差は76以上のはずだから、定跡を短くしたときに、そうなるはずだが…。

	置換表サイズが大きくなる ≒ 探索効率がよくなる　≒　持ち時間が増えたときと同じ
	　なので、R差が開く傾向にあるのか..。

	・book moves = 16
		engine1 = exe\YaneuraOuV350.exe , eval = eval/Apery20160505
		engine2 = exe\YaneuraOuV350.exe , eval = eval/Haku20160731
		byoyomi = 100 ,  3945 - 85 - 5970(39.79% R-71.97)

		engine1 = exe\YaneuraOuV350.exe , eval = eval/Apery20160505
		engine2 = exe\YaneuraOuV350.exe , eval = eval/Apery20160730
		threads = 40 , loop = 10000 , numa = 0 , byoyomi = 500
		389 - 8 - 1443(21.23% R-227.73)
		→　おかしい。何かおかしいところを引いてくるのか？
			hash size    :  24
			book_moves   :  16
		→　hash size間違えたのか。うむむむ..。この差は何なのか。棋譜全部調べたほうがいいな。
		→　メモリが足りなかったわけではなさそうなのだが…。

		// book_moves = 24
		engine1 = exe\YaneuraOuV350.exe , eval = eval/Apery20160505
		engine2 = exe\YaneuraOuV350.exe , eval = eval/Apery20160730
		byoyomi = 500 ,  417 - 15 - 568(42.34% R-53.68)

		置換表サイズをおかしくしたときに評価関数のメモリを破壊して、
		全プロセスでおかしくなっている可能性ってないのかな。
		・hash size 24MBでシミュレーションしてみる。
		・置換表のメモリ、readonlyに出来るか試す。
		・メモリ共有、40HTで読み込み中に別のスレッドが壊す/使いはじめるということはあるか?

		// hash 24MB , bookmoves = 16
		engine1 = exe\YaneuraOuV350.exe , eval = eval/Apery20160505
		engine2 = exe\YaneuraOuV350.exe , eval = eval/Apery20160730
		byoyomi = 500 ,  417 - 9 - 574(42.08% R-55.51)

		// hash 16MB , bookmoves = 24
		engine1 = exe\YaneuraOuV350.exe , eval = eval/Apery20160505
		engine2 = exe\YaneuraOuV350.exe , eval = eval/Apery20160730
		byoyomi = 1000 ,  397 - 9 - 594(40.06% R-70.0)

		メモリテストしたほうが良いか？
		→　メモリ、問題なかった。

		Aperyの新バイナリのテスト。

		hash size    :  16
		book_moves   :  24

		engine1 = exe\YaneuraOuV350.exe , eval = eval/Apery20160730
		engine2 = exe\YaneuraOuV350.exe , eval = eval/Apery20160803
		byoyomi = 100 ,  5464 - 83 - 4453(55.1% R35.54)

		engine1 = exe\YaneuraOuV350.exe , eval = eval/Apery20160730
		engine2 = exe\YaneuraOuV350.exe , eval = eval/Apery20160803
		byoyomi = 300 ,  5409 - 115 - 4476(54.72% R32.89)

		engine1 = exe\YaneuraOuV350.exe , eval = eval/Apery20160730
		engine2 = exe\YaneuraOuV350.exe , eval = eval/Apery20160803
		byoyomi = 100 ,  572 - 8 - 420(57.66% R53.66)

		engine1 = exe\YaneuraOuV350.exe , eval = eval/Apery20160730
		engine2 = exe\YaneuraOuV350.exe , eval = eval/Apery20160803
		byoyomi = 300 ,  532 - 11 - 457(53.79% R26.4)


		Apery20160803、強くなってない可能性が微レ存。

		engine1 = exe\YaneuraOuV350.exe , eval = eval/Haku20160731
		engine2 = exe\YaneuraOuV350.exe , eval = eval/Apery20160803
		byoyomi = 100 ,  5697 - 69 - 4234(57.37% R51.56)

		engine1 = exe\YaneuraOuV350.exe , eval = eval/Haku20160731
		engine2 = exe\YaneuraOuV350.exe , eval = eval/Apery20160803
		byoyomi = 300 ,  5486 - 79 - 4435(55.3% R36.94)

		engine1 = exe\YaneuraOuV350.exe , eval = eval/Haku20160731
		engine2 = exe\YaneuraOuV350.exe , eval = eval/Apery20160803
		byoyomi = 100 ,  565 - 6 - 429(56.84% R47.84)

		engine1 = exe\YaneuraOuV350.exe , eval = eval/Haku20160731
		engine2 = exe\YaneuraOuV350.exe , eval = eval/Apery20160803
		byoyomi = 300 ,  558 - 4 - 438(56.02% R42.06)


■　2016/08/03


		c:\jenkins\workspace\yanejob\連続自己対戦>start /B /WAIT /NODE 0 c:/python27/python.exe \\WS2012_860C_YAN\yanehome\script\engine_invoker.py \\WS2012_860C_YAN\yanehome exe\YaneuraOuV347RR2.exe eval/179_0042G_V3  exe\YaneuraOuV347RR2.exe eval/Haku20160731 40 10000 0 { 1000 } 
		home         :  \\WS2012_860C_YAN\yanehome\
		byoyomi_list :  ['1000']
		evaldirs     :  ['eval/Haku20160731']
		engine1 = exe\YaneuraOuV347RR2.exe , eval = eval/179_0042G_V3
		engine2 = exe\YaneuraOuV347RR2.exe , eval = eval/Haku20160731
		threads = 40 , loop = 10000 , numa = 0 , byoyomi = 1000
		\\WS2012_860C_YAN\yanehome\\exe\local-game-serverV347.exe , booksfenfile \\WS2012_860C_YAN\yanehome\book/records1.sfen , threads 40 , enginenuma 0 , go btime 10000 , quit
		finish 3839 - 136 - 6025(38.92% R-78.3)


		c:\jenkins\workspace\yanejob\連続自己対戦>start /B /WAIT /NODE 0 c:/python27/python.exe \\WS2012_860C_YAN\yanehome\script\engine_invoker.py \\WS2012_860C_YAN\yanehome exe\YaneuraOuV347RR2.exe eval/179_0042G_V3  exe\YaneuraOuV347RR2.exe eval/Haku20160731 40 10000 0 { 300 } 
		home         :  \\WS2012_860C_YAN\yanehome\
		byoyomi_list :  ['300']
		evaldirs     :  ['eval/Haku20160731']
		engine1 = exe\YaneuraOuV347RR2.exe , eval = eval/179_0042G_V3
		engine2 = exe\YaneuraOuV347RR2.exe , eval = eval/Haku20160731
		threads = 40 , loop = 10000 , numa = 0 , byoyomi = 300
		\\WS2012_860C_YAN\yanehome\\exe\local-game-serverV347.exe , booksfenfile \\WS2012_860C_YAN\yanehome\book/records1.sfen , threads 40 , enginenuma 0 , go btime 10000 , quit
		finish 3880 - 97 - 6023(39.18% R-76.39)


		c:\jenkins\workspace\yanejob\連続自己対戦@2>start /B /WAIT /NODE 1 c:/python27/python.exe \\WS2012_860C_YAN\yanehome\script\engine_invoker.py \\WS2012_860C_YAN\yanehome exe\YaneuraOuV347RR2.exe eval/Apery20160730  exe\YaneuraOuV347RR2.exe eval/Haku20160731 40 10000 1 { 300 } 
		home         :  \\WS2012_860C_YAN\yanehome\
		byoyomi_list :  ['300']
		evaldirs     :  ['eval/Haku20160731']
		engine1 = exe\YaneuraOuV347RR2.exe , eval = eval/Apery20160730
		engine2 = exe\YaneuraOuV347RR2.exe , eval = eval/Haku20160731
		threads = 40 , loop = 10000 , numa = 1 , byoyomi = 300
		\\WS2012_860C_YAN\yanehome\\exe\local-game-serverV347.exe , booksfenfile \\WS2012_860C_YAN\yanehome\book/records1.sfen , threads 40 , enginenuma 1 , go btime 10000 , quit
		finish 4316 - 70 - 5614(43.46% R-45.68)


		c:\jenkins\workspace\yanejob\連続自己対戦>start /B /WAIT /NODE 0 c:/python27/python.exe \\WS2012_860C_YAN\yanehome\script\engine_invoker.py \\WS2012_860C_YAN\yanehome exe\YaneuraOuV347RR2.exe eval/Apery20160730  exe\YaneuraOuV347RR2.exe eval/Haku20160731 40 10000 0 { 100 } 
		home         :  \\WS2012_860C_YAN\yanehome\
		byoyomi_list :  ['100']
		evaldirs     :  ['eval/Haku20160731']
		engine1 = exe\YaneuraOuV347RR2.exe , eval = eval/Apery20160730
		engine2 = exe\YaneuraOuV347RR2.exe , eval = eval/Haku20160731
		threads = 40 , loop = 10000 , numa = 0 , byoyomi = 100
		\\WS2012_860C_YAN\yanehome\\exe\local-game-serverV347.exe , booksfenfile \\WS2012_860C_YAN\yanehome\book/records1.sfen , threads 40 , enginenuma 0 , go btime 10000 , quit
		finish 4081 - 68 - 5851(41.09% R-62.59)


		c:\jenkins\workspace\yanejob\連続自己対戦@2>start /B /WAIT /NODE 1 c:/python27/python.exe \\WS2012_860C_YAN\yanehome\script\engine_invoker.py \\WS2012_860C_YAN\yanehome exe\YaneuraOuV347RR2.exe eval/Apery20160505  exe\YaneuraOuV347RR2.exe eval/Haku20160731 40 10000 1 { 1000 } 
		home         :  \\WS2012_860C_YAN\yanehome\
		byoyomi_list :  ['1000']
		evaldirs     :  ['eval/Haku20160731']
		engine1 = exe\YaneuraOuV347RR2.exe , eval = eval/Apery20160505
		engine2 = exe\YaneuraOuV347RR2.exe , eval = eval/Haku20160731
		threads = 40 , loop = 10000 , numa = 1 , byoyomi = 1000
		\\WS2012_860C_YAN\yanehome\\exe\local-game-serverV347.exe , booksfenfile \\WS2012_860C_YAN\yanehome\book/records1.sfen , threads 40 , enginenuma 1 , go btime 10000 , quit
		finish 3629 - 138 - 6233(36.8% R-93.96)


		c:\jenkins\workspace\yanejob\連続自己対戦>start /B /WAIT /NODE 0 c:/python27/python.exe \\WS2012_860C_YAN\yanehome\script\engine_invoker.py \\WS2012_860C_YAN\yanehome exe\YaneuraOuV347RR2.exe eval/Apery20160505  exe\YaneuraOuV347RR2.exe eval/Haku20160731 40 10000 0 { 400 } 
		home         :  \\WS2012_860C_YAN\yanehome\
		byoyomi_list :  ['400']
		evaldirs     :  ['eval/Haku20160731']
		engine1 = exe\YaneuraOuV347RR2.exe , eval = eval/Apery20160505
		engine2 = exe\YaneuraOuV347RR2.exe , eval = eval/Haku20160731
		threads = 40 , loop = 10000 , numa = 0 , byoyomi = 400
		\\WS2012_860C_YAN\yanehome\\exe\local-game-serverV347.exe , booksfenfile \\WS2012_860C_YAN\yanehome\book/records1.sfen , threads 40 , enginenuma 0 , go btime 10000 , quit
		finish 3732 - 106 - 6162(37.72% R-87.11)


		c:\jenkins\workspace\yanejob\連続自己対戦@2>start /B /WAIT /NODE 1 c:/python27/python.exe \\WS2012_860C_YAN\yanehome\script\engine_invoker.py \\WS2012_860C_YAN\yanehome exe\YaneuraOuV347RR2.exe eval/Apery20160505  exe\YaneuraOuV347RR2.exe eval/Haku20160731 40 10000 1 { 300 } 
		home         :  \\WS2012_860C_YAN\yanehome\
		byoyomi_list :  ['300']
		evaldirs     :  ['eval/Haku20160731']
		engine1 = exe\YaneuraOuV347RR2.exe , eval = eval/Apery20160505
		engine2 = exe\YaneuraOuV347RR2.exe , eval = eval/Haku20160731
		threads = 40 , loop = 10000 , numa = 1 , byoyomi = 300
		\\WS2012_860C_YAN\yanehome\\exe\local-game-serverV347.exe , booksfenfile \\WS2012_860C_YAN\yanehome\book/records1.sfen , threads 40 , enginenuma 1 , go btime 10000 , quit
		finish 3728 - 103 - 6169(37.67% R-87.5)


		c:\jenkins\workspace\yanejob\連続自己対戦>start /B /WAIT /NODE 0 c:/python27/python.exe \\WS2012_860C_YAN\yanehome\script\engine_invoker.py \\WS2012_860C_YAN\yanehome exe\YaneuraOuV347RR2.exe eval/Apery20160505  exe\YaneuraOuV347RR2.exe eval/Haku20160731 40 10000 0 { 100 } 
		home         :  \\WS2012_860C_YAN\yanehome\
		byoyomi_list :  ['100']
		evaldirs     :  ['eval/Haku20160731']
		engine1 = exe\YaneuraOuV347RR2.exe , eval = eval/Apery20160505
		engine2 = exe\YaneuraOuV347RR2.exe , eval = eval/Haku20160731
		threads = 40 , loop = 10000 , numa = 0 , byoyomi = 100
		\\WS2012_860C_YAN\yanehome\\exe\local-game-serverV347.exe , booksfenfile \\WS2012_860C_YAN\yanehome\book/records1.sfen , threads 40 , enginenuma 0 , go btime 10000 , quit
		finish 3895 - 70 - 6035(39.22% R-76.07)



・benchコマンドの引数の説明が、USI拡張コマンド.txtのほう、間違っていたので修正。(uuunuuunさんより指摘あり)
	https://twitter.com/uuunuuun1/status/760324601637253120

・新しいPCのほう、自己対戦、おかしな結果が…。ああ、評価関数がないからか。
	Error、伝達したほうが良いのでは…。うーむ..
	finish 986 - 1 - 13(98.7% R751.97)
	評価関数の読み込み失敗しているのに1.3%は勝つんだな…。なんぞこれ…。

・よしよし、新しいPC、うまく動いているようだ。


■　2016/08/02

・YaneuraOuV347TC

  if (limits.rtime)
  {
	  auto r = limits.rtime;
	  remain_time = minimumTime = optimumTime = maximumTime = r;
	  return;
  }

・YaneuraOuV347RR.exe

  if (limits.rtime)
  {
	  auto r = limits.rtime;
	  r += (int)prng.rand((int)std::min(r * 1.5f , r * 10.0f / (ply)));

	  remain_time = minimumTime = optimumTime = maximumTime = r;
	  return;
  }

これで0.1秒、0.3秒を1万局やって、どうなるかを検証する。

	c:\jenkins\workspace\yanejob\連続自己対戦>start /B /WAIT /NODE 1 c:/python27/python.exe \\WS2012_860C_YAN\yanehome\script\engine_invoker.py \\WS2012_860C_YAN\yanehome exe\YaneuraOuV347rr.exe eval/Apery20160505  exe\YaneuraOuV347rr.exe eval/Apery20160730 40 10000 1 { 100 } 
	home         :  \\WS2012_860C_YAN\yanehome\
	byoyomi_list :  ['100']
	evaldirs     :  ['eval/Apery20160730']
	engine1 = exe\YaneuraOuV347rr.exe , eval = eval/Apery20160505
	engine2 = exe\YaneuraOuV347rr.exe , eval = eval/Apery20160730
	threads = 40 , loop = 10000 , numa = 1 , byoyomi = 100
	\\WS2012_860C_YAN\yanehome\\exe\local-game-serverV347.exe , booksfenfile \\WS2012_860C_YAN\yanehome\book/records1.sfen , threads 40 , enginenuma 1 , go btime 10000 , quit
	finish 4860 - 86 - 5054(49.02% R-6.8)

	もっと微差になった。そんな馬鹿な…。
	ああ、r * 1.5fではなく、こうすべきなのか。そうか。
	  if (ply)
		  r += (int)prng.rand((int)std::min(r * 0.5f, r * 10.0f / (ply)));

		→ rr2

	c:\jenkins\workspace\yanejob\連続自己対戦>start /B /WAIT /NODE 1 c:/python27/python.exe \\WS2012_860C_YAN\yanehome\script\engine_invoker.py \\WS2012_860C_YAN\yanehome exe\YaneuraOuV347tc.exe eval/Apery20160505  exe\YaneuraOuV347tc.exe eval/Apery20160730 40 10000 1 { 100 } 
	home         :  \\WS2012_860C_YAN\yanehome\
	byoyomi_list :  ['100']
	evaldirs     :  ['eval/Apery20160730']
	engine1 = exe\YaneuraOuV347tc.exe , eval = eval/Apery20160505
	engine2 = exe\YaneuraOuV347tc.exe , eval = eval/Apery20160730
	threads = 40 , loop = 10000 , numa = 1 , byoyomi = 100
	\\WS2012_860C_YAN\yanehome\\exe\local-game-serverV347.exe , booksfenfile \\WS2012_860C_YAN\yanehome\book/records1.sfen , threads 40 , enginenuma 1 , go btime 10000 , quit
	finish 4796 - 74 - 5130(48.32% R-11.7)

	c:\jenkins\workspace\yanejob\連続自己対戦@2>start /B /WAIT /NODE 0 c:/python27/python.exe \\WS2012_860C_YAN\yanehome\script\engine_invoker.py \\WS2012_860C_YAN\yanehome exe\YaneuraOuV347tc.exe eval/Apery20160505  exe\YaneuraOuV347tc.exe eval/Apery20160730 40 10000 0 { 300 } 
	home         :  \\WS2012_860C_YAN\yanehome\
	byoyomi_list :  ['300']
	evaldirs     :  ['eval/Apery20160730']
	engine1 = exe\YaneuraOuV347tc.exe , eval = eval/Apery20160505
	engine2 = exe\YaneuraOuV347tc.exe , eval = eval/Apery20160730
	threads = 40 , loop = 10000 , numa = 0 , byoyomi = 300
	\\WS2012_860C_YAN\yanehome\\exe\local-game-serverV347.exe , booksfenfile \\WS2012_860C_YAN\yanehome\book/records1.sfen , threads 40 , enginenuma 0 , go btime 10000 , quit
	finish 4568 - 85 - 5347(46.07% R-27.35)

	tcでも微差。0.1秒が厳しすぎるのか…。

	自己対戦フレームワークのバグというよりは、思考エンジン側の問題と、自己対戦フレームワークのタスクの処理の問題とがあるような気はする。

	c:\jenkins\workspace\yanejob\連続自己対戦>start /B /WAIT /NODE 1 c:/python27/python.exe \\WS2012_860C_YAN\yanehome\script\engine_invoker.py \\WS2012_860C_YAN\yanehome exe\YaneuraOuV347rr.exe eval/Apery20160505  exe\YaneuraOuV347rr.exe eval/Apery20160730 40 10000 1 { 300 } 
	home         :  \\WS2012_860C_YAN\yanehome\
	byoyomi_list :  ['300']
	evaldirs     :  ['eval/Apery20160730']
	engine1 = exe\YaneuraOuV347rr.exe , eval = eval/Apery20160505
	engine2 = exe\YaneuraOuV347rr.exe , eval = eval/Apery20160730
	threads = 40 , loop = 10000 , numa = 1 , byoyomi = 300
	\\WS2012_860C_YAN\yanehome\\exe\local-game-serverV347.exe , booksfenfile \\WS2012_860C_YAN\yanehome\book/records1.sfen , threads 40 , enginenuma 1 , go btime 10000 , quit
	finish 4524 - 97 - 5379(45.68% R-30.07)

	c:\jenkins\workspace\yanejob\連続自己対戦@2>start /B /WAIT /NODE 0 c:/python27/python.exe \\WS2012_860C_YAN\yanehome\script\engine_invoker.py \\WS2012_860C_YAN\yanehome exe\YaneuraOuV347rr2.exe eval/Apery20160505  exe\YaneuraOuV347rr2.exe eval/Apery20160730 40 10000 0 { 300 } 
	home         :  \\WS2012_860C_YAN\yanehome\
	byoyomi_list :  ['300']
	evaldirs     :  ['eval/Apery20160730']
	engine1 = exe\YaneuraOuV347rr2.exe , eval = eval/Apery20160505
	engine2 = exe\YaneuraOuV347rr2.exe , eval = eval/Apery20160730
	threads = 40 , loop = 10000 , numa = 0 , byoyomi = 300
	\\WS2012_860C_YAN\yanehome\\exe\local-game-serverV347.exe , booksfenfile \\WS2012_860C_YAN\yanehome\book/records1.sfen , threads 40 , enginenuma 0 , go btime 10000 , quit
	finish 4509 - 102 - 5389(45.55% R-30.97)

	rr2でいいや。

	しかし持ち時間で勝率がここまで変わるのは、Stockfish7の探索部の性質のような気もする。
	1秒未満のテストが信用ならないのはツライ。

	40コアにするのがいかんのか？20コアでテストしなおす。


	c:\jenkins\workspace\yanejob\連続自己対戦>start /B /WAIT /NODE 1 c:/python27/python.exe \\WS2012_860C_YAN\yanehome\script\engine_invoker.py \\WS2012_860C_YAN\yanehome exe\YaneuraOuV347rr2.exe eval/Apery20160505  exe\YaneuraOuV347rr2.exe eval/Apery20160730 20 10000 1 { 100 } 
	home         :  \\WS2012_860C_YAN\yanehome\
	byoyomi_list :  ['100']
	evaldirs     :  ['eval/Apery20160730']
	engine1 = exe\YaneuraOuV347rr2.exe , eval = eval/Apery20160505
	engine2 = exe\YaneuraOuV347rr2.exe , eval = eval/Apery20160730
	threads = 20 , loop = 10000 , numa = 1 , byoyomi = 100
	\\WS2012_860C_YAN\yanehome\\exe\local-game-serverV347.exe , booksfenfile \\WS2012_860C_YAN\yanehome\book/records1.sfen , threads 20 , enginenuma 1 , go btime 10000 , quit
	finish 4640 - 85 - 5275(46.8% R-22.28)

	c:\jenkins\workspace\yanejob\連続自己対戦@2>start /B /WAIT /NODE 0 c:/python27/python.exe \\WS2012_860C_YAN\yanehome\script\engine_invoker.py \\WS2012_860C_YAN\yanehome exe\YaneuraOuV347rr2.exe eval/Apery20160505  exe\YaneuraOuV347rr2.exe eval/Apery20160730 20 10000 0 { 300 } 
	home         :  \\WS2012_860C_YAN\yanehome\
	byoyomi_list :  ['300']
	evaldirs     :  ['eval/Apery20160730']
	engine1 = exe\YaneuraOuV347rr2.exe , eval = eval/Apery20160505
	engine2 = exe\YaneuraOuV347rr2.exe , eval = eval/Apery20160730
	threads = 20 , loop = 10000 , numa = 0 , byoyomi = 300
	\\WS2012_860C_YAN\yanehome\\exe\local-game-serverV347.exe , booksfenfile \\WS2012_860C_YAN\yanehome\book/records1.sfen , threads 20 , enginenuma 0 , go btime 10000 , quit
	finish 4487 - 98 - 5415(45.31% R-32.66)

	20コアにしてもほぼ変わらず。うーん..



■　2016/08/01


・持ち時間ごとに勝率は一定値に近いから、自己対戦フレームワークの問題ではなさげ。
	rtimeで、揺らしたときに、短い時間だと勝率への影響が大きいというのはあるのか。


	c:\jenkins\workspace\yanejob\連続自己対戦@2>start /B /WAIT /NODE 0 c:/python27/python.exe \\WS2012_860C_YAN\yanehome\script\engine_invoker.py \\WS2012_860C_YAN\yanehome exe\YaneuraOuV347.exe eval/Apery20160505  exe\YaneuraOuV347.exe eval/Apery20160730 40 10000 0 { 1000 } 
	home         :  \\WS2012_860C_YAN\yanehome\
	byoyomi_list :  ['1000']
	evaldirs     :  ['eval/Apery20160730']
	engine1 = exe\YaneuraOuV347.exe , eval = eval/Apery20160505
	engine2 = exe\YaneuraOuV347.exe , eval = eval/Apery20160730
	threads = 40 , loop = 10000 , numa = 0 , byoyomi = 1000
	\\WS2012_860C_YAN\yanehome\\exe\local-game-serverV347.exe , booksfenfile \\WS2012_860C_YAN\yanehome\book/records1.sfen , threads 40 , enginenuma 0 , go btime 10000 , quit
	finish 4168 - 125 - 5707(42.21% R-54.59)

	c:\jenkins\workspace\yanejob\連続自己対戦>start /B /WAIT /NODE 1 c:/python27/python.exe \\WS2012_860C_YAN\yanehome\script\engine_invoker.py \\WS2012_860C_YAN\yanehome exe\YaneuraOuV347.exe eval/Apery20160505  exe\YaneuraOuV347.exe eval/Apery20160730 40 1000 1 { 1000 } 
	home         :  \\WS2012_860C_YAN\yanehome\
	byoyomi_list :  ['1000']
	evaldirs     :  ['eval/Apery20160730']
	engine1 = exe\YaneuraOuV347.exe , eval = eval/Apery20160505
	engine2 = exe\YaneuraOuV347.exe , eval = eval/Apery20160730
	threads = 40 , loop = 1000 , numa = 1 , byoyomi = 1000
	\\WS2012_860C_YAN\yanehome\\exe\local-game-serverV347.exe , booksfenfile \\WS2012_860C_YAN\yanehome\book/records1.sfen , threads 40 , enginenuma 1 , go btime 1000 , quit
	finish 407 - 11 - 582(41.15% R-62.13)

	c:\jenkins\workspace\yanejob\連続自己対戦>start /B /WAIT /NODE 1 c:/python27/python.exe \\WS2012_860C_YAN\yanehome\script\engine_invoker.py \\WS2012_860C_YAN\yanehome exe\YaneuraOuV347.exe eval/Apery20160505  exe\YaneuraOuV347.exe eval/Apery20160730 40 10000 1 { 500 } 
	home         :  \\WS2012_860C_YAN\yanehome\
	byoyomi_list :  ['500']
	evaldirs     :  ['eval/Apery20160730']
	engine1 = exe\YaneuraOuV347.exe , eval = eval/Apery20160505
	engine2 = exe\YaneuraOuV347.exe , eval = eval/Apery20160730
	threads = 40 , loop = 10000 , numa = 1 , byoyomi = 500
	\\WS2012_860C_YAN\yanehome\\exe\local-game-serverV347.exe , booksfenfile \\WS2012_860C_YAN\yanehome\book/records1.sfen , threads 40 , enginenuma 1 , go btime 10000 , quit
	finish 4393 - 106 - 5501(44.4% R-39.07)

	c:\jenkins\workspace\yanejob\連続自己対戦@2>start /B /WAIT /NODE 1 c:/python27/python.exe \\WS2012_860C_YAN\yanehome\script\engine_invoker.py \\WS2012_860C_YAN\yanehome exe\YaneuraOuV347.exe eval/Apery20160505  exe\YaneuraOuV347.exe eval/Apery20160730 40 10000 1 { 300 } 
	home         :  \\WS2012_860C_YAN\yanehome\
	byoyomi_list :  ['300']
	evaldirs     :  ['eval/Apery20160730']
	engine1 = exe\YaneuraOuV347.exe , eval = eval/Apery20160505
	engine2 = exe\YaneuraOuV347.exe , eval = eval/Apery20160730
	threads = 40 , loop = 10000 , numa = 1 , byoyomi = 300
	\\WS2012_860C_YAN\yanehome\\exe\local-game-serverV347.exe , booksfenfile \\WS2012_860C_YAN\yanehome\book/records1.sfen , threads 40 , enginenuma 1 , go btime 10000 , quit
	finish 4552 - 96 - 5352(45.96% R-28.13)

	c:\jenkins\workspace\yanejob\連続自己対戦>start /B /WAIT /NODE 0 c:/python27/python.exe \\WS2012_860C_YAN\yanehome\script\engine_invoker.py \\WS2012_860C_YAN\yanehome exe\YaneuraOuV347.exe eval/Apery20160505  exe\YaneuraOuV347.exe eval/Apery20160730 40 10000 0 { 300 } 
	home         :  \\WS2012_860C_YAN\yanehome\
	byoyomi_list :  ['300']
	evaldirs     :  ['eval/Apery20160730']
	engine1 = exe\YaneuraOuV347.exe , eval = eval/Apery20160505
	engine2 = exe\YaneuraOuV347.exe , eval = eval/Apery20160730
	threads = 40 , loop = 10000 , numa = 0 , byoyomi = 300
	\\WS2012_860C_YAN\yanehome\\exe\local-game-serverV347.exe , booksfenfile \\WS2012_860C_YAN\yanehome\book/records1.sfen , threads 40 , enginenuma 0 , go btime 10000 , quit
	finish 4535 - 122 - 5343(45.91% R-28.48)



・自己対戦フレームワーク、一度、棋譜全部調べたほうが良いのでは。
　→　ソースコードレベルではおかしくないように思う。
　→　棋譜をひとつひとつ観察する。


	c:\jenkins\workspace\yanejob\連続自己対戦>start /B /WAIT /NODE 1 c:/python27/python.exe \\WS2012_860C_YAN\yanehome\script\engine_invoker.py \\WS2012_860C_YAN\yanehome exe\YaneuraOuV347.exe eval/Apery20160505  exe\YaneuraOuV347.exe eval/Apery20160730 40 1000 1 { 1000 } 
	home         :  \\WS2012_860C_YAN\yanehome\
	byoyomi_list :  ['1000']
	evaldirs     :  ['eval/Apery20160730']
	engine1 = exe\YaneuraOuV347.exe , eval = eval/Apery20160505
	engine2 = exe\YaneuraOuV347.exe , eval = eval/Apery20160730
	threads = 40 , loop = 1000 , numa = 1 , byoyomi = 1000
	\\WS2012_860C_YAN\yanehome\\exe\local-game-serverV347.exe , booksfenfile \\WS2012_860C_YAN\yanehome\book/records1.sfen , threads 40 , enginenuma 1 , go btime 1000 , quit
	finish 407 - 11 - 582(41.15% R-62.13)


	c:\jenkins\workspace\yanejob\連続自己対戦@2>start /B /WAIT /NODE 0 c:/python27/python.exe \\WS2012_860C_YAN\yanehome\script\engine_invoker.py \\WS2012_860C_YAN\yanehome exe\YaneuraOuV347.exe eval/Apery20160722  exe\YaneuraOuV347.exe eval/Apery20160730 40 1000 0 { 1000 } 
	home         :  \\WS2012_860C_YAN\yanehome\
	byoyomi_list :  ['1000']
	evaldirs     :  ['eval/Apery20160730']
	engine1 = exe\YaneuraOuV347.exe , eval = eval/Apery20160722
	engine2 = exe\YaneuraOuV347.exe , eval = eval/Apery20160730
	threads = 40 , loop = 1000 , numa = 0 , byoyomi = 1000
	\\WS2012_860C_YAN\yanehome\\exe\local-game-serverV347.exe , booksfenfile \\WS2012_860C_YAN\yanehome\book/records1.sfen , threads 40 , enginenuma 0 , go btime 1000 , quit
	finish 536 - 13 - 451(54.31% R30.0)


	c:\jenkins\workspace\yanejob\連続自己対戦>start /B /WAIT /NODE 1 c:/python27/python.exe \\WS2012_860C_YAN\yanehome\script\engine_invoker.py \\WS2012_860C_YAN\yanehome exe\YaneuraOuV347.exe eval/179_0042G_V3  exe\YaneuraOuV347.exe eval/Apery20160730 40 1000 1 { 1000 } 
	home         :  \\WS2012_860C_YAN\yanehome\
	byoyomi_list :  ['1000']
	evaldirs     :  ['eval/Apery20160730']
	engine1 = exe\YaneuraOuV347.exe , eval = eval/179_0042G_V3
	engine2 = exe\YaneuraOuV347.exe , eval = eval/Apery20160730
	threads = 40 , loop = 1000 , numa = 1 , byoyomi = 1000
	\\WS2012_860C_YAN\yanehome\\exe\local-game-serverV347.exe , booksfenfile \\WS2012_860C_YAN\yanehome\book/records1.sfen , threads 40 , enginenuma 1 , go btime 1000 , quit
	finish 441 - 13 - 546(44.68% R-37.1)


	c:\jenkins\workspace\yanejob\連続自己対戦@2>start /B /WAIT /NODE 0 c:/python27/python.exe \\WS2012_860C_YAN\yanehome\script\engine_invoker.py \\WS2012_860C_YAN\yanehome exe\YaneuraOuV347.exe eval/Apery20160505  exe\YaneuraOuV347.exe eval/Apery20160730 40 1000 0 { 1000 } 
	home         :  \\WS2012_860C_YAN\yanehome\
	byoyomi_list :  ['1000']
	evaldirs     :  ['eval/Apery20160730']
	engine1 = exe\YaneuraOuV347.exe , eval = eval/Apery20160505
	engine2 = exe\YaneuraOuV347.exe , eval = eval/Apery20160730
	threads = 40 , loop = 1000 , numa = 0 , byoyomi = 1000
	\\WS2012_860C_YAN\yanehome\\exe\local-game-serverV347.exe , booksfenfile \\WS2012_860C_YAN\yanehome\book/records1.sfen , threads 40 , enginenuma 0 , go btime 1000 , quit
	finish 512 - 19 - 469(52.19% R15.24)
	→　この結果がおかしい。こんなことってあるのか…。


	c:\jenkins\workspace\yanejob\連続自己対戦>start /B /WAIT /NODE 1 c:/python27/python.exe \\WS2012_860C_YAN\yanehome\script\engine_invoker.py \\WS2012_860C_YAN\yanehome exe\YaneuraOuV347.exe eval/Apery20160727  exe\YaneuraOuV347.exe eval/Apery20160730 40 1000 1 { 1000 } 
	home         :  \\WS2012_860C_YAN\yanehome\
	byoyomi_list :  ['1000']
	evaldirs     :  ['eval/Apery20160730']
	engine1 = exe\YaneuraOuV347.exe , eval = eval/Apery20160727
	engine2 = exe\YaneuraOuV347.exe , eval = eval/Apery20160730
	threads = 40 , loop = 1000 , numa = 1 , byoyomi = 1000
	\\WS2012_860C_YAN\yanehome\\exe\local-game-serverV347.exe , booksfenfile \\WS2012_860C_YAN\yanehome\book/records1.sfen , threads 40 , enginenuma 1 , go btime 1000 , quit
	finish 456 - 16 - 528(46.34% R-25.47)


	c:\jenkins\workspace\yanejob\連続自己対戦>start /B /WAIT /NODE 0 c:/python27/python.exe \\WS2012_860C_YAN\yanehome\script\engine_invoker.py \\WS2012_860C_YAN\yanehome exe\YaneuraOuV347.exe eval/Apery20160722  exe\YaneuraOuV347.exe eval/Apery20160727 40 1000 0 { 1000 } 
	home         :  \\WS2012_860C_YAN\yanehome\
	byoyomi_list :  ['1000']
	evaldirs     :  ['eval/Apery20160727']
	engine1 = exe\YaneuraOuV347.exe , eval = eval/Apery20160722
	engine2 = exe\YaneuraOuV347.exe , eval = eval/Apery20160727
	threads = 40 , loop = 1000 , numa = 0 , byoyomi = 1000
	\\WS2012_860C_YAN\yanehome\\exe\local-game-serverV347.exe , booksfenfile \\WS2012_860C_YAN\yanehome\book/records1.sfen , threads 40 , enginenuma 0 , go btime 1000 , quit
	finish 433 - 23 - 544(44.32% R-39.64)


■　2016/07/31

・Aperyの新バイナリ、結論

	1スレッド1手1秒1000局。

	eval/Apery20160505
	eval/Apery20160727
	429 - 19 - 552(43.73% R-43.79)

	eval/Apery20160722
	eval/Apery20160727
	433 - 23 - 544(44.32% R-39.64)

定跡で散らしているので勝率5割に引き寄せられるというのはある。
実際はこの倍ぐらいのR差があるのかも。


・局面生成、最後の出力がいい加減なので規定の数を少しオーバーしたり、足りなかったりしているような？

・局面生成のときにこの変数参照してなかった…。削除。
	// 生成したい局面の数
	u64 sfen_count_limit;

・局面生成のwriterの終了条件、こうすべきなのか？
		while (!finished || sfen_buffers_pool.size())
	うーむ、難しい。


#if 0
				{
					// メモリにコピーしてでも一気に書きだしたほうが速いかも。
					// →　変わらなかった。
					size_t one_size = buffers[0]->size() * sizeof(PackedSfenValue);
					size_t size = buffers.size()*one_size;
					u8* p = new u8[size];
					for (size_t i = 0; i < buffers.size(); ++i)
						memcpy(p + one_size*i, &(*buffers[i])[0] , one_size);

					fs.write((const char*)p, size);
					delete[] p;
				}
#endif

		// 書きだした局面の数
		u64 sfen_write_count = 0;

	これ初期化忘れてた。修正した。

■　2016/07/30

・局面生成、規定回数になっていないのに終了するバグがあるようだ。
	→　わかった。メモリ、ガバガバ食っとる。
	→　書き出しが間に合わないという問題ではなさそう。
	→　圧縮ドライブに対するflushがいかんのか。

		805000 sfens , at Sat Jul 30 19:44:50 2016
		[38]
		1005000 sfens , at Sat Jul 30 19:44:58 2016
		[15]
		1205000 sfens , at Sat Jul 30 19:45:05 2016
		[27][39]
		1405000 sfens , at Sat Jul 30 19:45:16 2016
		[57]
		1605000 sfens , at Sat Jul 30 19:45:31 2016

		1805000 sfens , at Sat Jul 30 19:45:44 2016
		[101]
		2005000 sfens , at Sat Jul 30 19:46:02 2016

		2205000 sfens , at Sat Jul 30 19:46:14 2016
		[152]
		2405000 sfens , at Sat Jul 30 19:46:23 2016

		2605000 sfens , at Sat Jul 30 19:46:38 2016

	圧縮関係なしに、普通に断片的なwrite自体が間に合わない。なんだこれ。

	NICがぶら下がっているほうのNUMAとそうでないNUMAとで差が出る感じなのかな。
	どうしようもないな…。ネットワークドライブ、RAID1にしているのも関係するんだろうな。

	ネットワークドライブ上にSSDぶら下げるか。

	YANEHOME
		\\WS2012_860C_YAN\yanehome
		↓
		\\YANE4771K\yanehome

		Node0がネットワークまわり遅いというのはあるようだ。ふーん..。
		余計なルーティングをしている可能性もあったりして？

		やはりネットワークドライブではなく、node0のネットワーク性能が悪いというのが原因のようだ。
		ネットワークドライバ、更新。
		→　めっちゃマシになった。なんぞこれ…。
		→　でもまだwrite間に合わない。うーん..

		start /NODE %EXECUTOR_NUMBER% /B /WAIT /D %YANEHOME% %YANEHOME%\exe\YaneuraOuV347.exe evaldir %EVAL_DIR% , threads %HT_CORES% , hash 4096 , gensfen depth %DEPTH% loop %LOOP_MAX% eval_limit %EVAL_LIMIT% file %YANEHOME%\gen_sfen\%BUILD_NUMBER%.bin , quit
		↓
		start /NODE %EXECUTOR_NUMBER% /B /WAIT /D %YANEHOME% %YANEHOME%\exe\YaneuraOuV347.exe evaldir %EVAL_DIR% , threads %HT_CORES% , hash 4096 , gensfen depth %DEPTH% loop %LOOP_MAX% eval_limit %EVAL_LIMIT% file %WORKSPACE%\%BUILD_NUMBER%.bin , quit
		start /NODE %EXECUTOR_NUMBER% /B /WAIT move %WORKSPACE%\%BUILD_NUMBER%.bin %YANEHOME%\gen_sfen\

		仕方がないのでローカルで生成してコピーするしかなさげ。うーん..そういうものか…。
		ローカルのSSD、ギリギリだな、こりゃ。

		なんにせよ、高負荷時のネットワーク性能が悪いことには違いないな。
		ローカルのSSD、圧縮ドライブにして運用したほうがマシか。
		JenkinsのJobでビルド後の処理としてworkspaceのdelete追加。

		あるいは、書き込みが一定量溜まったら、worker止めて書き込みに専念したほうがいいのかも。
		→　ローカルのほうが書き込みも速いのでネットワークドライブ、使わずに済むなら使わずに済ませたいな…。


■　2016/07/29

・depth 3, eval_limit 2000にして、棋力がサチるまでまずは回し続けるのが良いのでは。
	depth 3でサチってから、eval_limit変えたり、学習方法変えたりしたほうが良いのでは。
	それでサチったら、depthを4,5,6のように段階的に上げていく。闇雲に6にしない。これ大切。
	学習中は棋譜生成しても仕方がないし、対局も出来ないから、PCが遊ぶのか…。そうか…。
	なら、80億と言わず、40億でいいのかも知れない。

	SGD、結局、減衰率がないから、10億ぐらいでサチっている可能性が…。
	まあとりあえず80億生成してから考える。

	学習方法、何通りか変えて並行して学習させるのがいいかも。

・gensfenのときに評価値の上限はeval_limitとして指定できるように変更。

・Aperyの教師局面生成部について

		usi.cppの248行目からがそれ。
		> void make_teacher(std::istringstream& ssCmd) {

		1) 探索深さ = depth 6
		2) goコマンドで実行するのでスレッド並列には出来ない。
		 GUIのほうでプロセスを並行スレッド数だけ起動する仕組み。
		 さすがにメモリ消費しすぎるような…。

		3) 評価値2000で打ち切り
		4) 400手目まで

		ここ手数が長いほうが終盤の入玉がらみの指し手があって、良いのかも知れない。

		5) 2駒入れ替えではなく、ランダムムーブ
		・玉の24近傍へのランダム移動(多め)
		・合法手のなかからランダムに1つ移動

		6) ランダムムーブの採択確率を、ランダムムーブをするごとに 1/2 にして減衰させていく。
		(終盤ではランダムムーブは生じにくくなり、実戦的に起こりやすいような終局図に向かう..たぶん)

		※　4)～6)はさすが。棋力の伸びがサチったら、試してみる価値あり。



		c:\jenkins\workspace\yanejob\連続自己対戦>start /B /WAIT /NODE 0 c:/python27/python.exe \\WS2012_860C_YAN\yanehome\script\engine_invoker.py \\WS2012_860C_YAN\yanehome exe\YaneuraOuV347.exe eval/Apery20160722  exe\YaneuraOuV347.exe eval/Apery20160727 40 1000 0 { 1000 } 
		home         :  \\WS2012_860C_YAN\yanehome\
		byoyomi_list :  ['1000']
		evaldirs     :  ['eval/Apery20160727']
		engine1 = exe\YaneuraOuV347.exe , eval = eval/Apery20160722
		engine2 = exe\YaneuraOuV347.exe , eval = eval/Apery20160727
		threads = 40 , loop = 1000 , numa = 0 , byoyomi = 1000
		\\WS2012_860C_YAN\yanehome\\exe\local-game-serverV347.exe , booksfenfile \\WS2012_860C_YAN\yanehome\book/records1.sfen , threads 40 , enginenuma 0 , go btime 1000 , quit
		finish 433 - 23 - 544(44.32% R-39.64)

		思ったより伸びてるな…。1秒だからか？
		1000回だと少ないか。


・VALUE_MAX_EVALから学習させた件

		弱くなっている気が…。やはり、勝ち付近で極端な値が出るのは交差エントロピーと相性が悪いのかも。


		c:\jenkins\workspace\yanejob\連続自己対戦>start /B /WAIT /NODE 0 c:/python27/python.exe \\WS2012_860C_YAN\yanehome\script\engine_invoker.py \\WS2012_860C_YAN\yanehome exe\YaneuraOuV347.exe eval/179_0042G_V3  exe\YaneuraOuV347.exe eval/learn_8 40 1000 0 { 1000 } 
		home         :  \\WS2012_860C_YAN\yanehome\
		byoyomi_list :  ['1000']
		evaldirs     :  ['eval/learn_8/0', 'eval/learn_8/1', 'eval/learn_8/2']
		engine1 = exe\YaneuraOuV347.exe , eval = eval/179_0042G_V3
		engine2 = exe\YaneuraOuV347.exe , eval = eval/learn_8/0
		threads = 40 , loop = 1000 , numa = 0 , byoyomi = 1000
		\\WS2012_860C_YAN\yanehome\\exe\local-game-serverV347.exe , booksfenfile \\WS2012_860C_YAN\yanehome\book/records1.sfen , threads 40 , enginenuma 0 , go btime 1000 , quit
		finish 516 - 23 - 461(52.81% R19.58)

		engine1 = exe\YaneuraOuV347.exe , eval = eval/179_0042G_V3
		engine2 = exe\YaneuraOuV347.exe , eval = eval/learn_8/1
		threads = 40 , loop = 1000 , numa = 0 , byoyomi = 1000
		\\WS2012_860C_YAN\yanehome\\exe\local-game-serverV347.exe , booksfenfile \\WS2012_860C_YAN\yanehome\book/records1.sfen , threads 40 , enginenuma 0 , go btime 1000 , quit
		finish 521 - 20 - 459(53.16% R22.01)

		engine1 = exe\YaneuraOuV347.exe , eval = eval/179_0042G_V3
		engine2 = exe\YaneuraOuV347.exe , eval = eval/learn_8/2
		threads = 40 , loop = 1000 , numa = 0 , byoyomi = 1000
		\\WS2012_860C_YAN\yanehome\\exe\local-game-serverV347.exe , booksfenfile \\WS2012_860C_YAN\yanehome\book/records1.sfen , threads 40 , enginenuma 0 , go btime 1000 , quit
		finish 495 - 13 - 492(50.15% R1.06)


・
		c:\jenkins\workspace\yanejob\連続自己対戦>start /B /WAIT /NODE 0 c:/python27/python.exe \\WS2012_860C_YAN\yanehome\script\engine_invoker.py \\WS2012_860C_YAN\yanehome exe\YaneuraOuV347.exe eval/Apery20160722  exe\YaneuraOuV347.exe eval/179_0042G_V3 40 1000 0 { 1000 } 
		home         :  \\WS2012_860C_YAN\yanehome\
		byoyomi_list :  ['1000']
		evaldirs     :  ['eval/179_0042G_V3']
		engine1 = exe\YaneuraOuV347.exe , eval = eval/Apery20160722
		engine2 = exe\YaneuraOuV347.exe , eval = eval/179_0042G_V3
		threads = 40 , loop = 1000 , numa = 0 , byoyomi = 1000
		\\WS2012_860C_YAN\yanehome\\exe\local-game-serverV347.exe , booksfenfile \\WS2012_860C_YAN\yanehome\book/records1.sfen , threads 40 , enginenuma 0 , go btime 1000 , quit
		finish 504 - 19 - 477(51.38% R9.56)


・3億局面生成では落ちなかった。落ちたのは何だったのだ…。メモリ不足か？

・pythonのコード、勝率は小数点以下2桁にして、Rを表示するようにしよう。

		import math

		win = 10
		lose = 5

		rate = win/float(win+lose)

		print round(rate* 100,2)
		print round(-400*math.log(1/rate-1,10),2)

	こうか？

		if total != 0 :
			win_rate = win / float(win+lose)
		else:
			win_rate = 0
		print "finish " + str(win) + " - " + str(draw) + " - " + str(lose) + "(" + str(round(win_rate*100,2)) + "% R" + str(round(-400*math.log(1/win_rate-1,10),2)) + ")\n"
	

・
		c:\jenkins\workspace\yanejob\連続自己対戦>start /B /WAIT /NODE 0 c:/python27/python.exe \\WS2012_860C_YAN\yanehome\script\engine_invoker.py \\WS2012_860C_YAN\yanehome exe\YaneuraOuV347.exe eval/Apery20160505  exe\YaneuraOuV347.exe eval/Apery20160727 40 1000 0 { 1000 } 
		home         :  \\WS2012_860C_YAN\yanehome\
		byoyomi_list :  ['1000']
		evaldirs     :  ['eval/Apery20160727']
		engine1 = exe\YaneuraOuV347.exe , eval = eval/Apery20160505
		engine2 = exe\YaneuraOuV347.exe , eval = eval/Apery20160727
		threads = 40 , loop = 1000 , numa = 0 , byoyomi = 1000
		\\WS2012_860C_YAN\yanehome\\exe\local-game-serverV347.exe , booksfenfile \\WS2012_860C_YAN\yanehome\book/records1.sfen , threads 40 , enginenuma 0 , go btime 1000 , quit
		finish 429 - 19 - 552(43.7308868502%)


		c:\jenkins\workspace\yanejob\連続自己対戦>exit 0 
		Finished: SUCCESS

		ユーザーyaneenが実行
		2498a でビルドします。 ワークスペース: c:/jenkins/workspace/yanejob/連続自己対戦
		[連続自己対戦] $ cmd /c call C:\Users\yaneen\AppData\Local\Temp\hudson4761567536305457594.bat

		c:\jenkins\workspace\yanejob\連続自己対戦>start /B /WAIT /NODE 1 c:/python27/python.exe \\WS2012_860C_YAN\yanehome\script\engine_invoker.py \\WS2012_860C_YAN\yanehome exe\YaneuraOuV347.exe eval/Apery20160505  exe\YaneuraOuV347.exe eval/learn_8 40 1000 1 { 1000 3000 } 
		home         :  \\WS2012_860C_YAN\yanehome\
		byoyomi_list :  ['1000', '3000']
		evaldirs     :  ['eval/learn_8/0', 'eval/learn_8/1', 'eval/learn_8/2']
		engine1 = exe\YaneuraOuV347.exe , eval = eval/Apery20160505
		engine2 = exe\YaneuraOuV347.exe , eval = eval/learn_8/0
		threads = 40 , loop = 1000 , numa = 1 , byoyomi = 1000
		\\WS2012_860C_YAN\yanehome\\exe\local-game-serverV347.exe , booksfenfile \\WS2012_860C_YAN\yanehome\book/records1.sfen , threads 40 , enginenuma 1 , go btime 1000 , quit
		finish 455 - 8 - 537(45.8669354839%)

		threads = 40 , loop = 1000 , numa = 1 , byoyomi = 3000
		\\WS2012_860C_YAN\yanehome\\exe\local-game-serverV347.exe , booksfenfile \\WS2012_860C_YAN\yanehome\book/records1.sfen , threads 40 , enginenuma 1 , go btime 1000 , quit
		finish 474 - 19 - 507(48.3180428135%)

		engine1 = exe\YaneuraOuV347.exe , eval = eval/Apery20160505
		engine2 = exe\YaneuraOuV347.exe , eval = eval/learn_8/1
		threads = 40 , loop = 1000 , numa = 1 , byoyomi = 1000
		\\WS2012_860C_YAN\yanehome\\exe\local-game-serverV347.exe , booksfenfile \\WS2012_860C_YAN\yanehome\book/records1.sfen , threads 40 , enginenuma 1 , go btime 1000 , quit
		finish 456 - 13 - 531(46.2006079027%)

		threads = 40 , loop = 1000 , numa = 1 , byoyomi = 3000
		\\WS2012_860C_YAN\yanehome\\exe\local-game-serverV347.exe , booksfenfile \\WS2012_860C_YAN\yanehome\book/records1.sfen , threads 40 , enginenuma 1 , go btime 1000 , quit
		finish 465 - 14 - 521(47.1602434077%)

		engine1 = exe\YaneuraOuV347.exe , eval = eval/Apery20160505
		engine2 = exe\YaneuraOuV347.exe , eval = eval/learn_8/2
		threads = 40 , loop = 1000 , numa = 1 , byoyomi = 1000
		\\WS2012_860C_YAN\yanehome\\exe\local-game-serverV347.exe , booksfenfile \\WS2012_860C_YAN\yanehome\book/records1.sfen , threads 40 , enginenuma 1 , go btime 1000 , quit
		finish 463 - 5 - 532(46.5326633166%)

		threads = 40 , loop = 1000 , numa = 1 , byoyomi = 3000
		\\WS2012_860C_YAN\yanehome\\exe\local-game-serverV347.exe , booksfenfile \\WS2012_860C_YAN\yanehome\book/records1.sfen , threads 40 , enginenuma 1 , go btime 1000 , quit
		finish 467 - 15 - 518(47.4111675127%)


		c:\jenkins\workspace\yanejob\連続自己対戦>exit 0 
		Finished: SUCCESS

	・VALUE_MAX_EVALにすると過学習している気がする。学習対象局面が少なすぎるからかも。
	・しかしこれだけでは傾向がわからない。10個ぐらいないと。
	・1秒と3秒はそんなに変わらないようなので1秒のほうだけでもとりあえずは良いかも。
	・rtimeで時間ばらけるのに意味があるだろうか…。まあいいか。
	・ゼロベクトルから学習させたとは言え、Apery20160505と5%も変わらないとかやばすぎ。
	・NUMA1で、裏で局面生成していたこととも関係するのかも。そうでもないか。


		ユーザーyaneenが実行
		2498a でビルドします。 ワークスペース: c:/jenkins/workspace/yanejob/連続自己対戦@2
		[連続自己対戦@2] $ cmd /c call C:\Users\yaneen\AppData\Local\Temp\hudson3989661511375186194.bat

		c:\jenkins\workspace\yanejob\連続自己対戦@2>start /B /WAIT /NODE 0 c:/python27/python.exe \\WS2012_860C_YAN\yanehome\script\engine_invoker.py \\WS2012_860C_YAN\yanehome exe\YaneuraOuV347.exe eval/Apery20160722  exe\YaneuraOuV347.exe eval/learn_8 40 1000 0 { 1000 3000 } 
		home         :  \\WS2012_860C_YAN\yanehome\
		byoyomi_list :  ['1000', '3000']
		evaldirs     :  ['eval/learn_8/0', 'eval/learn_8/1', 'eval/learn_8/2']
		engine1 = exe\YaneuraOuV347.exe , eval = eval/Apery20160722
		engine2 = exe\YaneuraOuV347.exe , eval = eval/learn_8/0
		threads = 40 , loop = 1000 , numa = 0 , byoyomi = 1000
		\\WS2012_860C_YAN\yanehome\\exe\local-game-serverV347.exe , booksfenfile \\WS2012_860C_YAN\yanehome\book/records1.sfen , threads 40 , enginenuma 0 , go btime 1000 , quit
		finish 596 - 21 - 383(60.8784473953%)

		threads = 40 , loop = 1000 , numa = 0 , byoyomi = 3000
		\\WS2012_860C_YAN\yanehome\\exe\local-game-serverV347.exe , booksfenfile \\WS2012_860C_YAN\yanehome\book/records1.sfen , threads 40 , enginenuma 0 , go btime 1000 , quit
		finish 585 - 19 - 396(59.6330275229%)

		engine1 = exe\YaneuraOuV347.exe , eval = eval/Apery20160722
		engine2 = exe\YaneuraOuV347.exe , eval = eval/learn_8/1
		threads = 40 , loop = 1000 , numa = 0 , byoyomi = 1000
		\\WS2012_860C_YAN\yanehome\\exe\local-game-serverV347.exe , booksfenfile \\WS2012_860C_YAN\yanehome\book/records1.sfen , threads 40 , enginenuma 0 , go btime 1000 , quit
		finish 611 - 9 - 380(61.6548940464%)

		threads = 40 , loop = 1000 , numa = 0 , byoyomi = 3000
		\\WS2012_860C_YAN\yanehome\\exe\local-game-serverV347.exe , booksfenfile \\WS2012_860C_YAN\yanehome\book/records1.sfen , threads 40 , enginenuma 0 , go btime 1000 , quit
		finish 598 - 22 - 380(61.145194274%)

		engine1 = exe\YaneuraOuV347.exe , eval = eval/Apery20160722
		engine2 = exe\YaneuraOuV347.exe , eval = eval/learn_8/2
		threads = 40 , loop = 1000 , numa = 0 , byoyomi = 1000
		\\WS2012_860C_YAN\yanehome\\exe\local-game-serverV347.exe , booksfenfile \\WS2012_860C_YAN\yanehome\book/records1.sfen , threads 40 , enginenuma 0 , go btime 1000 , quit
		finish 589 - 16 - 395(59.8577235772%)

		threads = 40 , loop = 1000 , numa = 0 , byoyomi = 3000
		\\WS2012_860C_YAN\yanehome\\exe\local-game-serverV347.exe , booksfenfile \\WS2012_860C_YAN\yanehome\book/records1.sfen , threads 40 , enginenuma 0 , go btime 1000 , quit
		finish 595 - 19 - 386(60.6523955148%)


		c:\jenkins\workspace\yanejob\連続自己対戦@2>exit 0 
		Finished: SUCCESS

	・Apery20160722に対して負けすぎ。


■ 2016/07/28

・
		c:\jenkins\workspace\yanejob\連続自己対戦>start /B /WAIT /NODE 1 c:/python27/python.exe \\WS2012_860C_YAN\yanehome\script\engine_invoker.py \\WS2012_860C_YAN\yanehome exe\YaneuraOuV347.exe eval/Apery20160505  exe\YaneuraOuV347.exe eval/learn_8 40 500 1 { 100 } 
		home         :  \\WS2012_860C_YAN\yanehome\
		byoyomi_list :  ['100']
		evaldirs     :  ['eval/learn_8/0', 'eval/learn_8/1', 'eval/learn_8/2']
		engine1 = exe\YaneuraOuV347.exe , eval = eval/Apery20160505
		engine2 = exe\YaneuraOuV347.exe , eval = eval/learn_8/0
		threads = 40 , loop = 500 , numa = 1 , byoyomi = 100
		\\WS2012_860C_YAN\yanehome\\exe\local-game-serverV347.exe , booksfenfile \\WS2012_860C_YAN\yanehome\book/records1.sfen , threads 40 , enginenuma 1 , go btime 500 , quit
		finish 253 - 2 - 245(50.8032128514%)

		engine1 = exe\YaneuraOuV347.exe , eval = eval/Apery20160505
		engine2 = exe\YaneuraOuV347.exe , eval = eval/learn_8/1
		threads = 40 , loop = 500 , numa = 1 , byoyomi = 100
		\\WS2012_860C_YAN\yanehome\\exe\local-game-serverV347.exe , booksfenfile \\WS2012_860C_YAN\yanehome\book/records1.sfen , threads 40 , enginenuma 1 , go btime 500 , quit
		finish 226 - 4 - 270(45.564516129%)

		engine1 = exe\YaneuraOuV347.exe , eval = eval/Apery20160505
		engine2 = exe\YaneuraOuV347.exe , eval = eval/learn_8/2
		threads = 40 , loop = 500 , numa = 1 , byoyomi = 100
		\\WS2012_860C_YAN\yanehome\\exe\local-game-serverV347.exe , booksfenfile \\WS2012_860C_YAN\yanehome\book/records1.sfen , threads 40 , enginenuma 1 , go btime 500 , quit
		finish 232 - 4 - 264(46.7741935484%)


		c:\jenkins\workspace\yanejob\連続自己対戦>start /B /WAIT /NODE 1 c:/python27/python.exe \\WS2012_860C_YAN\yanehome\script\engine_invoker.py \\WS2012_860C_YAN\yanehome exe\YaneuraOuV347.exe eval/Apery20160722  exe\YaneuraOuV347.exe eval/learn_8 40 500 1 { 100 } 
		home         :  \\WS2012_860C_YAN\yanehome\
		byoyomi_list :  ['100']
		evaldirs     :  ['eval/learn_8/0', 'eval/learn_8/1', 'eval/learn_8/2']
		engine1 = exe\YaneuraOuV347.exe , eval = eval/Apery20160722
		engine2 = exe\YaneuraOuV347.exe , eval = eval/learn_8/0
		threads = 40 , loop = 500 , numa = 1 , byoyomi = 100
		\\WS2012_860C_YAN\yanehome\\exe\local-game-serverV347.exe , booksfenfile \\WS2012_860C_YAN\yanehome\book/records1.sfen , threads 40 , enginenuma 1 , go btime 500 , quit
		finish 242 - 3 - 255(48.6921529175%)

		engine1 = exe\YaneuraOuV347.exe , eval = eval/Apery20160722
		engine2 = exe\YaneuraOuV347.exe , eval = eval/learn_8/1
		threads = 40 , loop = 500 , numa = 1 , byoyomi = 100
		\\WS2012_860C_YAN\yanehome\\exe\local-game-serverV347.exe , booksfenfile \\WS2012_860C_YAN\yanehome\book/records1.sfen , threads 40 , enginenuma 1 , go btime 500 , quit
		finish 237 - 4 - 259(47.7822580645%)

		engine1 = exe\YaneuraOuV347.exe , eval = eval/Apery20160722
		engine2 = exe\YaneuraOuV347.exe , eval = eval/learn_8/2
		threads = 40 , loop = 500 , numa = 1 , byoyomi = 100
		\\WS2012_860C_YAN\yanehome\\exe\local-game-serverV347.exe , booksfenfile \\WS2012_860C_YAN\yanehome\book/records1.sfen , threads 40 , enginenuma 1 , go btime 500 , quit
		finish 252 - 2 - 246(50.6024096386%)

	0.1秒だからからか、結果が安定してなくて何もわからないな、これ。


・1億局面生成のjob、片方途中で落ちてた。プロセスが落ちたのだろうか。
	VALUE_EVAL_MAXまで生成していることに関係しているのかも。
	困るなぁ…。再度落ちるようなら、ASSERT有効にして単体で走らせるしかあるまい。
	→　NUMA1のほうでデバッグで回しておく。

		start /NODE 1 /B /WAIT /D \\WS2012_860C_YAN\yanehome YaneuraOu.exe evaldir eval/179_0042G_V3 , threads 40 , hash 4096 , gensfen depth 6 loop 300000000 file \\WS2012_860C_YAN\yanehome\gen_sfen\00.bin , quit 

・棋譜生成、16手目まで定跡の指し手だが、もう少し先までやったほうがいいかも。
　あるいはもうちょっとなぞったほうがいいかも。

・depth3で10億生成してみるか。
	→　depth3にしたけど生成速度早くならん。なぜ？
	→　learnのほうでgensfenしてたような？

・Jenkins、master側再起動するとJob全部キャンセルするな…。再起動できないではないか…。
	→　Windows updateで再起動しないようにしておく。

・Jenkinsのmasterで実行できない件、workspaceフォルダ、該当ユーザーがフルコントロールに
　なってないからのようだ。
	→　フォルダに権限与えたところ実行できるようになった。

・局面生成、何が起きたのかわからないが20万局面を数秒で連続3回ぐらい生成してるタイミングがある。
	これ書き出し絡みのバグの可能性が…。

	書き出しthreadのバグなのか生成のバグなのか、ネットワークドライブが詰まっているのかが
	判然としない。生成スレッドのほう、
				cout << '[' << thread_id << ']';
	これ一行入れてテストする。
	→　一個書き込みしている間に複数queueに積まれることはありえるようではあるが…。
	→　ネットワークドライブが詰まるというのはあるのかも。
	→　違うようだ。ファイルの書き出しworkerで、論理スレッドいっぱいまで使っているためにcoutが詰まって、
	それゆえ、バッファ処理が少しずつ間に合わなくなるという問題があるようだ。
	coutが詰まるというよりネットワークドライブの書き出しで、書き出しのためのnet layerで詰まっているようだ。なるほど。
	なら、生成に問題があるわけではなさそう。

・連続自己対戦、engine configをpython側で生成するか。
	・フルスロットルで回せるべき。
	・numa指定できるべき。
	・records.sfenが実行ファイル直下固定なの、変更できるべき。
	・フォルダ名をコマンドライン引数などでpython側に渡すか…。
		→　テンプレからengine config持ってきて、python側で書き換えるか？
		エンジン名と評価関数とマッチング条件…。うーむ。書くの面倒だな、これ。
		・python2.7インストール
		環境変数pathの設定と、これを反映させるためのPCの再起動が必要なようだ…。うーん。
		c:\python27\python
		として実行して良いような気も…。
		とりあえずpathは通しておく。次の再起動のときになおるであろう。
	・python エンジン名1 evaldir1 エンジン名2 evaldir2 1手のms
		こう指定してengine configを生成するスクリプトを書くか。
		そして、engine configのフォルダ位置、変更できるようにする。
		→　pythonのスクリプト書けた。

			import sys

			def write_engine_file(num , engine_name , eval_dir , byoyomi):
				f = open("engine-config"+str(num)+".txt","w")
				f.write(engine_name+"\n")
				f.write("go btime 0 wtime 0 byoyomi "+byoyomi+"\n")
				f.write("setoption name EvalDir value " + eval_dir+"\n")
				f.write("setoption name Hash value 32\n")
				f.write("setoption name Threads value 1\n")
				f.write("setoption name NetworkDelay value 0\n")
				f.write("setoption name NetworkDelay2 value 0\n")

				f.close()

			param = sys.argv
			if len(param) != 6 :
				print " engine1 evaldir1 engine2 evaldir2 byoyomi"
				sys.exit()

			write_engine_file(1,param[1],param[2],param[5])
			write_engine_file(2,param[3],param[4],param[5])

	・local game serverにオプションいくつか追加。

			// "engine_configX.txt"が配置してあるフォルダ
			o["EngineConfigDir"] << Option("");

			// 子プロセスでEngineを実行するプロセッサグループ(Numa node)
			// -1なら、指定なし。
			o["EngineNuma"] << Option(-1, 0, 99999);

		CreateProcess、startコマンド呼べない。Node指定どうするのだ…。
				(LPWSTR)to_wstring("start /node 0 " + app_path_).c_str(),

		CreateProcessにSTARTUPINFOEXを指定するのか。情報少なすぎてわからん。

			  PPROC_THREAD_ATTRIBUTE_LIST attribs = { 0 };

			  size_t cb;
			  char sAttribsBuf[4096];
			  auto pAttribs = (PPROC_THREAD_ATTRIBUTE_LIST)sAttribsBuf;

			  if (!InitializeProcThreadAttributeList(NULL, 1, 0, &cb)
				  && (GetLastError() != ERROR_INSUFFICIENT_BUFFER))
				  return ;
			  if (!InitializeProcThreadAttributeList(pAttribs, 1, 0, &cb))
				  return ;

			  LPPROC_THREAD_ATTRIBUTE_LIST lpAttribs = (LPPROC_THREAD_ATTRIBUTE_LIST)sAttribsBuf;
			  if (!UpdateProcThreadAttribute(lpAttribs, 0, PROC_THREAD_ATTRIBUTE_PREFERRED_NODE
				  , &iNuma, sizeof(iNuma), NULL, NULL))
			  {
				  si.lpAttributeList = lpAttribs;

				  // これを反映させておき、STARTUPINFOEXが指定されていることをCreateProcessに示す必要がある。
				  si.StartupInfo.cb = sizeof(si);
			  }

		→　これやめよう。
			cmd.exe /c start /node 0 calc.exe
		こんな感じでcmd.exeから起動させよう。

		pythonだとこうか。

			import subprocess
			cmd = "cmd.exe /c start /node 0 calc.exe"
			subprocess.call( cmd.strip().split(" "))

		→　うまく動いている感じ。

			app_path_ = "cmd.exe /c start /B /WAIT /NODE " + to_string(numa) + " " + app_path_;

			/*
				/NODE
				Numa node(実行するプロセッサグループ)の指定

				/B
				実行したコマンドを別窓で開かないためのオプション。

				/WAIT
				/Bを指定したときにはこれを指定して、本窓の終了を待機しないと
				プロセス実行中に制御を抜けてしまい、file descriptorがleakする。
			*/

		→　やった！ここまでは意図通り動いた。

			あとは、さらにpython側からhookするコードを書けばいいのか…。大変だな、これまた。

			・BookSfenFileオプション追加。

			よしよし。あとは、

			・evalフォルダにサブフォルダがあるときにそれらをすべて対戦させるコード。
				→　書けた。

			・local-game-serverにフルスロットルで回すコード追加。
				→　出来た。

			・pythonで出力をリダイレクトして戦績を返すコード追加。
				→　それより先にgoコマンド終了時にquitさせることが出来ない。
				local game serverにおいてbyoyomi = 1なら終了後にquitするか。
				→　よくない実装。メインスレッドではないのでexit()できない。
			
				→　local-game-serverにおいて、goコマンドのあとstopで停止できないように変更する。
					そうしないとquitをqueueに積めない。
				→　うまく動いた。

				c:/python27/python.exe engine_invoker.py \\WS2012_860C_YAN\yanehome exe/YaneuraOuV347.exe eval/Apery20160505 exe/YaneuraOuV347.exe eval/learn_8 8 10 0 { 100 300 }

			// 以下、python側のコード。
			import sys
			import subprocess
			import os.path

			def write_engine_file(num , engine_name , eval_dir , byoyomi):
				f = open("engine-config"+str(num)+".txt","w")
				f.write(engine_name+"\n")
			#	f.write("go btime 0 wtime 0 byoyomi "+byoyomi+"\n")
				f.write("go rtime " + byoyomi + "\n")
				f.write("setoption name EvalDir value " + eval_dir+"\n")
				f.write("setoption name Hash value 16\n")
				f.write("setoption name Threads value 1\n")
				f.write("setoption name BookFile value no_book\n")
				f.write("setoption name NetworkDelay value 0\n")
				f.write("setoption name NetworkDelay2 value 0\n")

				f.close()

			param = sys.argv

			# args format
			# 	HOMEPATH engine1 evaldir1 engine2 evaldir2 threads loop numa { rtime1 ... rtimeN }

			# loop for invoker

			home = param[1]
			if not (home.endswith('/') or home.endswith('\\')):
				home += '\\'

			threads = param[6]
			loop = param[7]
			numa = param[8]

			if param[9] != "{" :
				byoyomi_list = param[9]
			else:
				byoyomi_list = []
				for i in range (10,len(param)-1):
					byoyomi_list.append(param[i])

			# expand eval_dir

			evaldirs = []
			if not os.path.exists(home + param[5] + "/0") :
				evaldirs.append(param[5])
			else:
				i = 0
				while os.path.exists(home + param[5] + "/" + str(i)):
					evaldirs.append(param[5] + "/" + str(i) )
					i += 1

			print "home         : " , home
			print "byoyomi_list : " , byoyomi_list
			print "evaldirs     : " , evaldirs

			for evaldir in evaldirs:

				print "engine1 = " + param[2] + " , eval = " + param[3]
				print "engine2 = " + param[4] + " , eval = " + evaldir

				for byoyomi in byoyomi_list:

					print "threads = " + threads + " , loop = " + loop + " , numa = " + numa + " , byoyomi = " + byoyomi
					write_engine_file(1,home + param[2],home + param[3],byoyomi)
					write_engine_file(2,home + param[4],home + evaldir,byoyomi)

					cmd = home + "\\exe\\local-game-serverV347.exe , booksfenfile " + home + "book/records1.sfen , threads " + threads + " , enginenuma " + numa + " , go btime " + loop + " , quit"

					# subprocess.call( cmd.strip().split(" "))
					print cmd
					p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
					stdout_data, stderr_data = p.communicate()
					# print "finish: \n%s\n%s" % (stdout_data, stderr_data)

					win = lose = draw = 0
					for line in stdout_data.split('\n'):
						if line.startswith("win"):
							win += 1
						elif line.startswith("lose"):
							lose += 1
						elif line.startswith("draw"):
							draw += 1

					total = win + lose
					if total != 0 :
						win_rate = 100 * win / float(win+lose)
					else:
						win_rate = 0
					print "finish " + str(win) + " - " + str(draw) + " - " + str(lose) + "(" + str(win_rate) + "%)\n"

				→　JenkinsのJob化、成功した。


■ 2016/07/27

・Jenkins Job化残り
	・学習のJob化
	→　できた…気がする。
	・連続自己対局のJob化
	→　あとで
	・gensfen、flush()してるのに、ネットワークドライブ上だと途中で終了すると保存されないな…。うーん..

・mkdir、フォルダ再帰的に作ってくれる？
	→　くれなかった。コマンドラインのmkdirは掘ってくれるのに…。

・連続自己対戦の改良
	・指定された回数、全スレッドでフルスロットルで回す
	・指定されたevaldirを順に変更して回す
	・学習と連携したいが、書き出しフォルダと切り離しているので出来ない。
	　evalの書き出しフォルダ、変更すべきか？
	→　よく考える。
	→　評価関数の書き出しをcontainerのなかにするとrobocopyが定期的にコピーしてしまい、
	余計なオーバーヘッドが発生するしな…。どうしたものか..さすがに80スレッドがネットワークドライブ上の
	同じ評価関数読み込むとなると80GBぐらいのトラフィックが発生してそれはそれで無駄だし…。
	いや、evalshareしてるから、それでもいいのか…。そうか…。
	なら学習回して、連続自己対戦までは自動化できそう。よしよし。
	あ、これ棋譜生成してるやつの評価関数使うと、それ学習してるのか。げろげろマズー。
	learnはevalshare offにしとかなきゃ。

		start /B /WAIT /NODE %EXECUTOR_NUMBER% robocopy \\Ws2012_860c_yan\e\jenkins_container  c:\jenkins/container /s /mir
		cd c:\jenkins\container
		mkdir \\Ws2012_860c_yan\e\jenkins_output\eval\%BUILD_NUMBER%
		start /NODE %EXECUTOR_NUMBER% /B /WAIT exe\YaneuraOuV345learn.exe evaldir %EVAL_DIR% , evalsavedir \\Ws2012_860c_yan\e\jenkins_output\eval\%BUILD_NUMBER% , threads 40 , hash 4096 , evalshare false , learn loop %LOOP_MAX% dir \\Ws2012_860c_yan\e\jenkins_output\learn_sfen  %KIF_FILES% , quit

	よしよし。出来てきた。
	連続自己対戦のJobまで書けたらJenkinsのバックアップをとる。

・考えまとまった。
	ネットワーク上の共有ドライブに何もかも配置したほうがいいという結論になった。
	robocopy不要になる。評価関数読み込むのは1つのJobにつきたかだか2回だけだし無視できるだろう。

	startコマンドの/Dでworkig directoryが指定できるようなのでこれを利用。
		例)
		start /NODE %EXECUTOR_NUMBER% /B /WAIT /D %YANEHOME% %YANEHOME%\exe\YaneuraOuV345.exe evaldir %EVAL_DIR% , threads %HT_CORES% , hash 4096 , gensfen depth %DEPTH% loop %LOOP_MAX% file %YANEHOME%\gen_sfen\%BUILD_NUMBER%.bin , quit
			HT_CORESに各nodeの論理コア数を入れておけば非対称なプロセッサでも大丈夫か。

	→　うまく動かん。startコマンド、スペースが入るとき""でpathくくるべきだが、
	  1つ目の""はwindow titleになるというstartコマンドの謎仕様。うむむ。
	→　よくわからん。Jenkinsのmasterだとネットワークドライブが見えないようだ。
	　サービスを動かしているuserが異なるからか？
		まあいいや。masterで動かさない。たぶん。

	例) 学習用
		mkdir %YANEHOME%\eval\learn_%BUILD_NUMBER%
		start /NODE %EXECUTOR_NUMBER% /B /WAIT /D %YANEHOME% %YANEHOME%\exe\YaneuraOuV345learn.exe evaldir %EVAL_DIR% , evalsavedir %YANEHOME%\eval\learn_%BUILD_NUMBER% , threads %HT_CORES% , hash 4096 , evalshare false , learn loop %LOOP_MAX% dir %YANEHOME%\learn_sfen  %KIF_FILES% , quit
		→　完璧。

・連続自己対戦用にやねうら王を改造する。
	・対戦条件を書いてファイルを食わせるとそれをやってくれると良いのか…な？
	→　ネットワークフォルダにそんなファイル置きたくないしな…。引数として指定できるといいのかな。
		よく考えよう…。
	→　まず、フルスロットルで回すコード追加するところからだ。

・学習のときにfinalizeするフォルダ名、
	learn_%BUILD_NUMBER%/f/
	とかのほうが良いのでは…。ここを固定しておかないと比較するときに難しくなる気が。
	そうでもないのかな…。
	→　そうでもない気がしてきた。

・eval limit=VALUE_EVAL_MAXで2億局面生成してSGDで1回まわして一つ前のものと比較。

		秒読み1000[ms]

		50.2%	
		#283
		やねうら王2016mid V344
		eval 179_0043G_V4
		#281
		やねうら王2016mid V344
		eval 179_0042G_V3

		1440-33-1426(39.7% R1.7)	

	ほぼ、変わらず？


■ 2016/07/26

・Jenkinsのテスト。
	・robocopyでミラーするjob作成
	→ JavaWebStartを使っていると実行権限が違って、ネットワークドライブが見れない。
	→　DCOMで実行するように変更。でも見れない。
		> whoami
		nt authority\system
	→　JenkinsのDCOMバグっているとしか思えん。
	→　ああ、UseLocal System Userであって、Jenkinsに入力したアカウントではないのか。これはあかん…。
	→　Jenkinsを実行しているWindowsのサービスを、指定ユーザーで実行するように変えれば良いのか。そうか。
	→　robocopyはできた。

	・NUMA、そもそも
	ビルド番号か何かで識別できないのか？
	https://wiki.jenkins-ci.org/display/JA/Building+a+software+project
	EXECUTOR_NUMBER	このビルドを実行するエグゼキューターを識別（同一マシン内で）するユニークな番号。
	"ビルド実行状態"で表示されている番号ですが、1ではなく0始まりです。
	→　これで出来そうな予感。%EXECUTOR_NUMBER% これで出来るわ。
	> start /NODE %EXECUTOR_NUMBER% robocopy ...
	こう書けばいいのか？
	→　よし、出来たっぽい。
	> start /NODE 0 robocopy \\Ws2012_860c_yan\e\jenkins_container  c:\jenkins/container /s /mir 
	→　よし、robocopy成功！
	
	・あと、同時実行されたときにフォルダが分かれて欲しいのだが..
	→　tempを必要とするなら、そのフォルダを分けるか。
		/{リモートFSルート}/workspace/{JOB_NAME}{EXECUTOR_NUMBER}
		こうなってくれないと困る。
	→ 自動的に、@2のようにJOB_NAMEの後ろにつくようだ。なら要らないのか、この機能は。

	Jenkins、MSBuildも使えるようなのでMSBuildでビルドしたほうが楽かも知れない。うむむ..
	msys2のmakeとか起動すると、numa nodeを指定できないか…。そんな問題があるのか…。うむむ…。
	普通にgitコマンドとMSBuildコマンド叩いたほうが賢いか。うむむ…。そんな気がしてきた。
	→　デプロイ少し楽になるかも知れないが、環境構築、面倒くさすぎる。
	→　2つの対戦をさせるのに２つGitHubから取ってきてMSBuildして対戦。うーん。それはいいような悪いような…。
	→　これはやめよう。

・Jenkinsのjob化していく。
	1) 局面生成をjob化
		・NUMA固定するためのプログラム考える。
		→　不要になった。

		・jobを細分化したいので、教師局面ファイルはもっと細切れに生成してconcatするべき。concatのプログラム書く。
		・生成された局面のgatherの手段、よく考える。

		→　とりあえずgensfenのファイル名を指定する手段を用意する。
		→　用意した。

			> start /NODE %EXECUTOR_NUMBER% exe/YaneuraOu.exe evaldir eval/179_0042G_V3 , threads 40 , hash 4096 , gensfen depth 6 loop 10000 file \\Ws2012_860c_yan\e\jenkins_output\kif1.bin , quit
			こんな感じでどうか。
			start /NODE 1 exe/YaneuraOuV345.exe evaldir eval/179_0042G_V3 , threads 40 , hash 4096 , gensfen depth 6 loop 100000 file \\Ws2012_860c_yan\e\jenkins_output\ファイル名 , quit 
			start /NODE 1 /B ...
			という/Bオプションを発見。
			cf. http://pf-j.sakura.ne.jp/program/dos/doscmd/start.htm

			Jenkinsがなんかleakしてるとかなんとか
			> Process leaked file descriptors. See http://wiki.jenkins-ci.org/display/JENKINS/Spawning+processes+from+build for more information
			うーん。startコマンドがforkみたいなことするから、file descriptorのleakとみなされてるのかな。厳しい。
			start /B /WAIT
			これが正しいのか？
			→　これでうまく動作した。難しすぎ。
		・とりあえず局面生成はJenkinsのjob化できた。
			ファイルの結合はDOSのcopyコマンドでいいか..そうか..。ならこれで完成か。
			copy /b a.bin + b.bin c.bin
			こんな魔法のような記法があるとは。
			copy /b *.bin all.bin
			これでいいか。そうか。

			ではこうか。
				start /B /WAIT /NODE %EXECUTOR_NUMBER% robocopy \\Ws2012_860c_yan\e\jenkins_container  c:\jenkins/container /s /mir
				cd c:\jenkins\container
				start /NODE %EXECUTOR_NUMBER% /B /WAIT exe\YaneuraOuV345.exe evaldir %EVAL_DIR% , threads 40 , hash 4096 , gensfen depth %DEPTH% loop %LOOP_MAX% file \\Ws2012_860c_yan\e\jenkins_output\%SFEN_FILE_NAME% , quit
			→できた(気がする)

			depth 6, 40HT 1億局面生成 = 9時間のようだ。
			80*9/24 = 30日かかるな。10プロセッサで3日か。そうか。
			もとい、1億局面、7時間ぐらいでいけそう。
			Jenkinsのjob、ひとつが4時間以内に収まるようにして、平均2時間の待ちで優先jobが実行されるぐらいにしておかないと
			TATが悪くてかなわん。長いjobと短いjobとアトランダムにあればマシか…。


	2) 学習をjob化
		・デプロイ、どうするべきか。
		→ robocopy組み合わせれば出来そう。事前にrobocopyすればいいだけか。

		・評価関数ファイルの保存フォルダ、別途指定できたほうが良いのでは。考える。
		→　Options("EvalSaveDir")用意したほうがいいかも。
		→　そうした。

		・jenkinsのjob、よほどのことがない限りキャンセルしないので、saveは1回でいいかも。
		→　5億学習ごとに1回とかの意味。まあいいや。ここがそんなに問題ではないだろうし。たぶん。
		→　とりあえず、1億局面に1回に変更。
		→　これで学習のjobを書けるはず…。

	3) 自己対局をjob化
		・pythonスクリプトの活用
		→　うーん。pythonすら要らないような気がしてきた。


・特定のjobと評価関数ファイルがバッティングしてはいけないので異なる評価関数ファイルは必ずフォルダを分けるべき..なのか..。そうか..。
	→　ちょっと仕組みを考える。
	・robocopyをしてネットワークドライブと同期させるスクリプトをJenkinsのjob化する。
		→　実行ファイルが重複してしまった場合は仕方がない。なるべくそれは起こらないようにするしかない。
		→　GitHubのprivate repositoryをfetchして、都度コンパイルすることは出来るのか…そうか…。
		やねうら王の公式のほうとごっちゃになるな…。
		Visual StudioのGitHubのplug-in使うのやめて、別で管理するしかないな…。うーむ..
		→　gitコマンドに慣れたほうがいいかも知れんな…。
		→　TortoiseGit導入した。
		→　GitHubから取ってくるのLAN内に大きなストレージがあるなら、いいアイデアではなさげだった。

	・save_eval()のフォルダ、設定できるようにする。
		→　した。


・Apery(WCSC26)から10億局面追加学習してそれと比較する。

			5G

			秒読み1000[ms]

			47.9%	
			#282
			やねうら王2016mid V344
			eval AppendApery20160726
			#272
			やねうら王2016mid V344
			eval Apery20160722

			883-19-960(96.4% R-14.5)	


			秒読み100[ms]

			50.6%	
			#282
			やねうら王2016mid V344
			eval AppendApery20160726
			#272
			やねうら王2016mid V344
			eval Apery20160722

			1677-32-1636(23.8% R4.3)	


			2G
			秒読み1000[ms]

			45.8%	
			#282
			やねうら王2016mid V344
			eval AppendApery20160726
			#272
			やねうら王2016mid V344
			eval Apery20160722

			544-26-643(99.8% R-29.0)	


			1G

			秒読み1000[ms]

			43.9%	
			#282
			やねうら王2016mid V344
			eval AppendApery20160726
			#272
			やねうら王2016mid V344
			eval Apery20160722

			235-11-300(99.8% R-42.4)	


			秒読み100[ms]

			50.2%	
			#282
			やねうら王2016mid V344
			eval AppendApery20160726
			#272
			やねうら王2016mid V344
			eval Apery20160722

			1427-36-1416(41.8% R1.3)	


			秒読み100[ms]

			52.5%	
			#282
			やねうら王2016mid V344
			eval AppendApery20160726
			#0
			やねうら王2016mid V344
			新基準(AperyWCSC26)

			735-7-665(3.1% R17.4)	


			秒読み1000[ms]

			53.8%	
			#282
			やねうら王2016mid V344
			eval AppendApery20160726
			#0
			やねうら王2016mid V344
			新基準(AperyWCSC26)

			477-8-409(1.0% R26.7)	



■ 2016/07/25

・そうか。Jenkins + 同時ビルド数=2にして、NUMA 0,1を必ず使うように強制できればいいのか。
	空いているほうのnumaを調べて、それをstartコマンドでそちらからタスクを起動できればいいのか。
	空いているほうのnumaを調べるのも、file lockか何かで済むのでは..
	global mutex使うか..。そうか…。
		launcher YaneuraOu.exe
	のようにしたときに空いてるほうのNUMAで実行してくれればいいだけか。そうか。

・Jenkinsインストール
	> java -jar jenkins.war

・CPU affinityの設定

	NUMA node番号は、startコマンドの/nodeオプションで指定できるようだ。(/affinity N ではない)
		start /node 0 YaneuraOu.exe


		0039Gから強くなってるとは言いがたいな。弱くもなってなさそうだけども。

		秒読み10000[ms]

		53.2%	
		#281
		やねうら王2016mid V344
		eval 179_0042G_V3
		#0
		やねうら王2016mid V344
		新基準(AperyWCSC26)

		885-40-777(0.4% R22.6)	

		10秒でこれだけしか変わらないのか…？


		秒読み500[ms]

		52.5%	
		#281
		やねうら王2016mid V344
		eval 179_0042G_V3
		#0
		やねうら王2016mid V344
		新基準(AperyWCSC26)

		480-7-435(6.4% R17.1)	


		秒読み500[ms]

		51.5%	
		#281
		やねうら王2016mid V344
		eval 179_0042G_V3
		#272
		やねうら王2016mid V344
		eval Apery20160722

		362-6-341(20.3% R10.4)	



		秒読み1000[ms]

		52.5%	
		#281
		やねうら王2016mid V344
		eval 179_0042G_V3
		#279
		やねうら王2016mid V344
		eval 179_0040G_V3

		622-12-563(4.3% R17.3)	
		1秒だと結構変わるような？
		10秒で回して、寝る。


		秒読み100[ms]

		50.0%	
		#281
		やねうら王2016mid V344
		eval 179_0042G_V3
		#279
		やねうら王2016mid V344
		eval 179_0040G_V3

		578-11-578(50.0% R0.0)	
		・10億局面に対してさらに2周まわしたが、変わらず


		秒読み100[ms]

		46.9%	
		#279
		やねうら王2016mid V344
		eval 179_0041G_V3
		#278
		やねうら王2016mid V344
		eval 179_0039G_V3

		559-10-634(98.5% R-21.9)	

	学習進めたら弱くなった。うーむ、そうか、やはり…。


		秒読み100[ms]

		50.2%	
		#279
		やねうら王2016mid V344
		eval 179_0040G_V3
		#278
		やねうら王2016mid V344
		eval 179_0039G_V3

		534-13-530(45.1% R1.3)	


179_0041G_V3
・よく考えたらSGDはcount集計しているからmini-batchのサイズで学習率変える必要ないわ。

・
1) 学習に使っているPC
2) 棋譜生成に使っているPC
3) 自己対局に使っているPC

	1)と3)を一緒にすると学習のmini batchの1回の処理が間に合わなくなって、勾配がおかしくなる。
	2)と3)をペアにして、1)とは隔離すべき。しかし1)に3)の処理が付随していて何とも。
	Jenkins導入するときに、このへんややこしいな…。
	1)と3)を同じPCでやるならプロセッサグループを指定すればいいのか…。うーむ。
	Jenkins入れて、かつ、プロセッサグループを管理する何かが必要だな。

	→　Jenkinsを使わなくて済む案を考えた。

	実行環境がフォルダ化されているとする。これをDockerのコンテナに相当するものだとみなす。
		container1/
		container2/
		container3/
	空いているプロセッサを見つけて、そのプロセッサに、コンテナ番号とタスク内容を割り振る。
	そのプロセッサは、ネットワークから、robocopyでlocal環境のなかにそのコンテナをコピーして実行する。
	実行結果は、robocopyで逆方向にsyncさせて終了…というのはどうだろうか。

	逆方向にsyncさせると共用したときに困るか。
	出力は別のフォルダがあるとすればいいのか。

		result/1
		result/2

	みたいな。
	ここに出力すると。

	これだけでいいなら、なんとなく出来そうな気はする。
	ログもそこに出力すればいいのか。うーん。そうか…。

	result一覧が表になっていて欲しいのだが。
	CSVファイルを別で生成するだとか？追記で済む方法がないものか..

	うーん。棋譜生成を4PCで回しておいて、自己対戦がしたいときはその負荷状態でいまの
	連続自己対戦フレームワークで行なって、学習だけ1PCで回すとちょうどよかったり？


・局面生成のときに評価値の打ち切り上限を3000にしたものを10億局面混ぜて学習を進めた。
	平均誤差(mean error)が215になってしまった。あらら？
	終盤のほうの評価値の絶対値の大きな局面だと誤差が大きくなるから、これは仕方ないのか…。
	
		179_0039G_V3

			秒読み100[ms]

			51.8%	
			#278
			やねうら王2016mid V344
			eval 179_0039G_V3
			#277
			やねうら王2016mid V344
			eval 179_0038G_CE

			1057-25-983(5.1% R12.6)	


			秒読み100[ms]

			49.5%	
			#278
			やねうら王2016mid V344
			eval 179_0039G_V3
			#272
			やねうら王2016mid V344
			eval Apery20160722

			619-8-631(63.3% R-3.3)	


			秒読み1000[ms]

			51.8%	
			#278
			やねうら王2016mid V344
			eval 179_0039G_V3
			#272
			やねうら王2016mid V344
			eval Apery20160722

			352-7-327(15.9% R12.8)	

		Apery20160722が+R50らしいので、ここに+R12
		おそらく+R65～R70程度に相当するのか？

			秒読み100[ms]

			55.4%	
			#278
			やねうら王2016mid V344
			eval 179_0039G_V3
			#0
			やねうら王2016mid V344
			新基準(Apery WCSC26)

			360-3-290(0.3% R37.6)
			

・学習のときに棋譜フォルダを指定するオプションをつけるか..
	learn dir XXX とか。
	あとloop回数かな。

	こんな感じ？
		log
		evalshare false
		threads 39
		learn bat 100 loop 3 dir \\Ws2012_860c_yan\e\genkif201607 kifu201607250800.bin kifu201607230600.bin kifu201607152200.bin kifu201607171700.bin kifu201607171800.bin kifu201607151400.bin


		log
		evalshare false
		threads 8
		learn bat 100 loop 3 dir \\Ws2012_860c_yan\e\genkif201607 kifu201607250800.bin kifu201607230600.bin kifu201607152200.bin kifu201607171700.bin kifu201607171800.bin kifu201607151400.bin

・棋譜、10億追加。(トータル65億程度？)

		log
		evalshare false
		threads 39
		learn bat 100 \\Ws2012_860c_yan\e\genkif201607\kifu201607250800.bin \\Ws2012_860c_yan\e\genkif201607\kifu201607230600.bin \\Ws2012_860c_yan\e\genkif201607\kifu201607152200.bin \\Ws2012_860c_yan\e\genkif201607\kifu201607171700.bin \\Ws2012_860c_yan\e\genkif201607\kifu201607171800.bin \\Ws2012_860c_yan\e\genkif201607\kifu201607151400.bin \\Ws2012_860c_yan\e\genkif201607\kifu201607230600.bin \\Ws2012_860c_yan\e\genkif201607\kifu201607152200.bin \\Ws2012_860c_yan\e\genkif201607\kifu201607171700.bin \\Ws2012_860c_yan\e\genkif201607\kifu201607171800.bin \\Ws2012_860c_yan\e\genkif201607\kifu201607151400.bin \\Ws2012_860c_yan\e\genkif201607\kifu201607230600.bin \\Ws2012_860c_yan\e\genkif201607\kifu201607152200.bin \\Ws2012_860c_yan\e\genkif201607\kifu201607171700.bin \\Ws2012_860c_yan\e\genkif201607\kifu201607171800.bin \\Ws2012_860c_yan\e\genkif201607\kifu201607151400.bin \\Ws2012_860c_yan\e\genkif201607\kifu201607230600.bin \\Ws2012_860c_yan\e\genkif201607\kifu201607152200.bin \\Ws2012_860c_yan\e\genkif201607\kifu201607171700.bin \\Ws2012_860c_yan\e\genkif201607\kifu201607171800.bin \\Ws2012_860c_yan\e\genkif201607\kifu201607151400.bin


・評価値の打ち切り上限を無しにしたら、40HTで20万局面生成に50秒かかるようになってしまった。
	これはまずいかも…。以前は30秒だったはず…。


・究極的には評価関数は、search(N)をdepth Nでのsearchとして、
		qsearch = search(1) = search(2) = ... = search(n)
	となるべき。なので、いま
		qsearch = search(6)
	としているのは、
		qsearch = search(1) = search(6)
	のほうがいいはず。しかし学習時にsearch(1)の探索が必要になるので学習時間が増加する。
	どうしたものか…。現状の方法で頭打ちになるまでは頑張ってみるか…。


・損失関数、交差エントロピーと勝率とで比較。ただし勝率のほうはあまりiteration回せなかった。
	交差エントロピーのほうはSGDで3Mのmini-batchにした。
	rmseは下がってないのに多少強くなっているようだ。

	次回の方針
	・SGDは勾配が出にくいとおかしくなるのでmini-batchのサイズを大きくしてみる。
	・局面数100億ぐらいまで増やしてみる。
	・SGDでもいいからきちんと回す。
	・探索深さ深くして教師を使ってみる。
	・VALUE_MAX_EVALまで生成した局面データにしてみる。

			秒読み100[ms]

			53.2%	
			#277
			やねうら王2016mid V344
			eval 179_0038G_CE
			#276
			やねうら王2016mid V344
			eval 179_0034G_WIN

			1048-22-922(0.2% R22.3)	

		新Apery

			秒読み100[ms]

			52.3%	
			#277
			やねうら王2016mid V344
			eval 179_0038G_CE
			#272
			やねうら王2016mid V344
			eval Apery20160722

			916-12-835(2.6% R16.1)	


			秒読み1000[ms]

			47.8%	
			#277
			やねうら王2016mid V344
			eval 179_0038G_CE
			#272
			やねうら王2016mid V344
			eval Apery20160722

			752-12-822(96.1% R-15.5)	


		旧Apery

			秒読み100[ms]

			52.1%	
			#277
			やねうら王2016mid V344
			eval 179_0038G_CE
			#266
			やねうら王2016mid V344
			新基準

			1221-17-1124(2.3% R14.4)	


			秒読み1000[ms]

			51.9%	
			#277
			やねうら王2016mid V344
			eval 179_0038G_CE
			#266
			やねうら王2016mid V344
			新基準

			451-5-418(12.4% R13.2)	
		

・Adamの定数、static constexpr LearnFloatTypeに変更。

・SGDのパラメーターもlearn.hではなく、自動的に計算して設定するように変更。

	SGDで3Mぐらいの単位で回すとさらに損失関数の値は下がる。
	SGDが一番、統御しやすいという意味はあるのか…。


・棋譜生成、評価値上限、VALUE_MAX_EVALに変更してみる。

・learnコマンドでbatchサイズ指定できるようにする。

		log
		threads 8
		evalshare false
		learn bat 100 \\Ws2012_860c_yan\e\genkif201607\kifu201607230600.bin \\Ws2012_860c_yan\e\genkif201607\kifu201607152200.bin \\Ws2012_860c_yan\e\genkif201607\kifu201607171700.bin \\Ws2012_860c_yan\e\genkif201607\kifu201607171800.bin \\Ws2012_860c_yan\e\genkif201607\kifu201607151400.bin

		log
		threads 8
		evalshare false
		learn bat 500 \\Ws2012_860c_yan\e\genkif201607\kifu201607230600.bin \\Ws2012_860c_yan\e\genkif201607\kifu201607152200.bin \\Ws2012_860c_yan\e\genkif201607\kifu201607171700.bin \\Ws2012_860c_yan\e\genkif201607\kifu201607171800.bin \\Ws2012_860c_yan\e\genkif201607\kifu201607151400.bin
		→　これで改善するかしばらく回してみる。

		mini-batchサイズを上げると学習率を下げないと辻褄が合わないのかも…。うむむ…。

		学習率5.0f→1.0fにしたもので比較。うーん..よくわからん。


・YaneGrad、LOSS_FUNCTION_IS_WINNING_PERCENTAGEにするときは、学習率を変更するようにした。

		// 学習率η
#if defined (LOSS_FUNCTION_IS_CROSS_ENTOROPY)
		const LearnFloatType eta = 5.0f;
#elif defined (LOSS_FUNCTION_IS_WINNING_PERCENTAGE)
		const LearnFloatType eta = 20.0f;
		// 少し大きめに
#endif

	4倍しておく。

・learnコマンド使ったときに更新式を表示するようにしよう。
	→　した。

・Adamおかしい。損失関数減らない。

	const double eta = double(32)/64.0
	const double epsilon = 10e-8
		がゼロになってた。禿げそう。
	class内のconst doubleまわりの最適化、何か怪しげ。
	しかもクラス外から参照できない糞仕様。static constexprにするか..
	→　全部defineにしてやったら直った。
	→　Adamの更新式、結構きわどいので更新式の中身だけdoubleにして計算しておく。
	→　Adamめっちゃ遅い…。g == 0のところも更新しているからか。うーん。
	結果的にmini batchのサイズが大きくなって、かえってよかったり？


・学習のときにepochの初期化忘れていたの修正。
	→　問題はこれだけではないようだ…。

・Adam、wがゼロベクトルから損失関数が下がること自体は確認できた。

・Adam、更新に時間がかかるので、あまりよろしくなかった。
	1) doubleの計算精度
	2) sqrt 2回
	3) 途中計算ややこしい
	4) gがゼロでも更新必要(もしかすると不要？)
	特に4)が遅くなる要因。sparse性が生きてない感じ。

	結論的にはAdaGradのほうが良いのではという感じ。

・Adamで30億局面追加学習させた。

		秒読み100[ms]

		50.8%	
		#275
		やねうら王2016mid V344
		eval 179_0033G
		#0
		やねうら王2016mid V344
		新基準

		637-10-618(29.6% R5.3)	


		秒読み100[ms]

		50.6%	
		#275
		やねうら王2016mid V344
		eval 179_0033G
		#274
		やねうら王2016mid V344
		eval 180_0030G

		720-6-703(32.6% R4.2)	

		ひとつ前のバージョンに対してR3,4ぐらい強くなっているかも、という程度。

・目的関数、変更してAdaGradで追加学習させてみる。
	learnのときに目的関数を表示したほうがいいかも？


■ 2016/07/24

・定跡のバイナリサーチ、バグってた
	https://twitter.com/merom686/status/756746338268618752
	e - 40 < sは、eが無符号型だとまずいのか。修正した。


・AdaGradの更新式、1箇所にまとめられないのか？
	→　できそう。
	→　1箇所にまとめられた。よしよし。
	そしてKK配列のlimit、緩和する。

		//#undef YANE_GRAD_ALPHA
		//#define YANE_GRAD_ALPHA 0.99f
		//#undef YANE_GRAD_ETA
		//#define YANE_GRAD_ETA 5.0f
		//#undef YANE_GRAD_EPSILON
		//#define YANE_GRAD_EPSILON 1.0f
	→　この定数、defineで定義するのやめる。

・Adam書けた。

		log
		threads 8
		evalshare false
		learn \\Ws2012_860c_yan\e\genkif201607\kifu201607230600.bin \\Ws2012_860c_yan\e\genkif201607\kifu201607152200.bin \\Ws2012_860c_yan\e\genkif201607\kifu201607171700.bin \\Ws2012_860c_yan\e\genkif201607\kifu201607171800.bin \\Ws2012_860c_yan\e\genkif201607\kifu201607151400.bin

		→　学習率調整し忘れていた。とりあえずFV_SCALE/64にした。

・新Apery評価関数(20160722) vs 旧Aperyの評価関数     : 943-19-795(R29.7) 1手1秒相当
・新Apery評価関数(20160722) vs やねうら王(181_0020G) : 547-7-461(R29.7)	1手1秒相当
	だそうな。


		秒読み2000[ms]

		50.5%	
		#273
		やねうら王2016mid V341b
		eval 181_0024G
		#0
		やねうら王2016mid V341b2
		新基準

		143-3-140(40.6% R3.7)	

		これでもまだApery(WCSC26)と互角ぐらいか。

・そうか。評価関数のMutex名、USI Optionで指定できるといいのかな。そうすれば同じバージョン同士でも
	　共有メモリを使って対戦できるわけで…。あるいは、フォルダ名をそのままmutex名にするだとか。
	 バックスラッシュがmutexに使えないのか。うーん、この..。仕方ないな。

・learnコマンドのために置換表をオフにしている場合、起動時にメッセージが出たほうが良いな。
　これで間違えて棋譜を生成してはかなわん。

・gensfen、最適化したけどあまり速くならん。評価値3000まで出力するようにすると、終盤だからdepth 6に
　要する時間が相対的に増加するということなのか。そうか…。

・53億局面でもう少し学習を回してみる。

		log
		threads 39
		evalshare false
		learn \\Ws2012_860c_yan\e\genkif201607\kifu201607230600.bin \\Ws2012_860c_yan\e\genkif201607\kifu201607152200.bin \\Ws2012_860c_yan\e\genkif201607\kifu201607171700.bin \\Ws2012_860c_yan\e\genkif201607\kifu201607171800.bin \\Ws2012_860c_yan\e\genkif201607\kifu201607151400.bin

・batch型連続自己対局が出来ないと不便だな…。
・自己対戦フレームワーク、対局回数を指定してその回数だけフルスレッドでぶん回してくれたほうが嬉しい。
	→　この２つ、あとで書くか…。


■ 2016/07/23

・とりあえず、これでおおむね作業終了。


・やねうら王V3.43から、同時に起動している同じバージョンのやねうら王同士で評価関数を共有するようになりました。
	(こうすることで100個同時に起動しても置換表サイズ＋αぐらいのサイズしか消費しないというメリットがあります。)
	その代わり、評価関数ファイルを変えた自己対戦は出来なくなります。(異なるバージョンのやねうら王を用いれば出来ます)
	このへん、オプション設定で共有をオフにする機能をつけるか考え中です。

	→　オプションで設定できたほうがいいような気がしてきた。
	→　この機能追加した。


・40億局面だとまだ足りてない感。
	→　もう20億ほど生成してから考えるか…。

・評価関数ファイルを20種類ぐらい公開する準備。
	→　28バリエーション公開した。

・ネットワーク上の局面ファイルからの読み込みが遅いの改善できるかも。
	全スレッドがI/O待ちになるのがイケてなくて、読み込みバッファの残りが少なくなったら
	先行して読みに行っておくべきなのでは。
	→　ファイル読み込み専用スレッドを起動して、読み込んでつねに充填しておくぐらいのことをしないとダメか..
	→　うまく書けた…気がする。

		log
		threads 40
		learn \\Ws2012_860c_yan\e\genkif201607\kifu201607151400.bin \\Ws2012_860c_yan\e\genkif201607\kifu201607152200.bin \\Ws2012_860c_yan\e\genkif201607\kifu201607171700.bin \\Ws2012_860c_yan\e\genkif201607\kifu201607171800.bin

		→　10万局面に対して4,5秒だったのが7秒かかるようになったけど、前よりはマシか。
			許せる範囲と言えば許せる範囲なのかも。うーん。やはり、もったいない気もするのでSSD使うか…。
		→　sleep(1)に変えたら6秒になった。ほぼ変わらず。というか、SSDからが逆に6秒になってしまった。
			workerの書き方がよろしくないか？
		→　これはこれでいいや。
		→　4CHT8だと17秒、20CHT40で7秒は悪すぎ…。どうなってんの…。
		→　340MBのrandom shuffleが遅い可能性も..うーん、どうなんだろ。
			hotspot調べてみる。
		→　調べるまでもなく、lockしてのmemcpyとか筋が悪すぎるな。あれ全部やめよう。
		→　書き換えた。めっちゃシンプルになった。これで動いてくれれば。
		→　デバッグ完了。
		→　40HTで100万局面、4秒程度になった！速い！やったー！


・AdaGradで一度目にrmse上がるのおかしすぎ。何かバグがある予感。

				if (abs(w.g[0] > 100))
				{
					cout << endl << k1 << k2;
					cout << endl << w.g[0] << " , " << w.g[1] << " | " << w.g2[0] << "," << w.g2[1];
				}

		w.g[0]、一回目300とかつくんだな。こりゃいかんわ。
		SGDでもこんなに大きな値が来るとたまらん気はする。
		AdaGrad、最初のiteration 3回ぐらいはupdateを保留するか。

		→　AdaGradとYaneGrad、3回目ぐらいまではg2のupdateのみにするようにした。
		→　しかしあまり意味がなかった…。
		→　5回に変更。

・sfenのgeneratorもI/Oまわりの並列化、きちんと出来る気がしてきた…。
		→　計算したところ、しても速度的に改善しなさそうなのでこれでいいや。

・コンソール出力が詰まる問題、コマンドプロンプトの出来がよくないんだろうな…。
	他のコンソールエミュレーターを試してみる。
	http://conemu.github.io/
	→　あかん。余計悪かった。
	→　powershellのほうがなんぼかマシ。

・学習モードでの出力をもっと抑制するモードをつけないとまずいな。あとファイルをエンドレスに読み込むモードと。
　あとで考えよう…。
	→　抑制機能つけた。
	→　2周回したいなら同じファイル名 2回書けばいいか。そうか。

・最後まで回すと落ちた。
	rmse = 0.0789076 , mean_error = 181.632
	file_worker_threadのjoin()書いてないからか。そうか。


■ 2016/07/22

・ゼロパラメーターから学習させた評価関数パラメーターについて。

 →Xeon Dualで自己対戦させたときに子プロセスの属するプロセッサグループはランダムのようだ。
 　自動的にバラける。これは便利。1PCで並列80対局、できる。これはすごい…。


 	181_0020G
		秒読み200[ms]

		46.2%	
		#271
		やねうら王2016mid V341b
		eval 181_0020G
		#0
		やねうら王2016mid V341b2
		新基準

		423-4-493(99.1% R-26.6)	

		不思議なことに長い時間においては互角ぐらいっぽい。ふーん..

		秒読み2000[ms]

		50.2%	
		#271
		やねうら王2016mid V341b
		eval 181_0020G
		#0
		やねうら王2016mid V341b2
		新基準

		146-2-145(45.3% R1.2)	


	182_0018G

		秒読み200[ms]

		46.9%	
		#271
		やねうら王2016mid V341b
		eval 182_0018G
		#0
		やねうら王2016mid V341b2
		新基準

		336-1-381(95.7% R-21.8)	


	190_0013G

		秒読み300[ms]

		44.9%	
		#271
		やねうら王2016mid V341b
		eval 190_0013G
		#0
		やねうら王2016mid V341b2
		新基準

		269-6-330(99.4% R-35.5)	


		秒読み5000[ms]

		44.5%	
		#271
		やねうら王2016mid V341b
		eval 190_0013G
		#0
		やねうら王2016mid V341b2
		新基準

		175-6-218(98.7% R-38.2)	


	200_0011G

		秒読み1000[ms]

		43.6%	
		#271
		やねうら王2016mid V341b
		eval 200_0011G
		#0
		やねうら王2016mid V341b2
		新基準

		184-1-238(99.6% R-44.7)	

		
		秒読み5000[ms]

		37.8%	
		#271
		やねうら王2016mid V341b
		eval 200_0011G
		#0
		やねうら王2016mid V341b2
		新基準

		93-1-153(100.0% R-86.5)	



	 222_0010G

		秒読み1000[ms]

		43.8%	
		#270
		やねうら王2016mid V341b
		eval 222_0010G
		#0
		やねうら王2016mid V341b2
		新基準

		141-1-181(98.9% R-43.4)	

		長い時間においてはそこそこ強いっぽい？
		序盤の形の理解において優れているのかも。


	さらに40億局面ほど回してみた。弱くはなってなさげ。もう少し回す。

		秒読み100[ms]

		41.9%	
		#270
		やねうら王2016mid V341b
		eval 223_9000M
		#0
		やねうら王2016mid V341b2
		新基準

		373-6-518(100.0% R-57.0)	


		秒読み1000[ms]

		41.5%	
		#270
		やねうら王2016mid V341b
		eval 223_9000M
		#0
		やねうら王2016mid V341b2
		新基準

		211-2-298(100.0% R-60.0)	


	損失関数の値は悪化したが、過学習ではなさげ。

	225_8000M

		秒読み1000[ms]

		37.2%	
		#269
		やねうら王2016mid V341b
		eval 225_6000M
		#0
		やねうら王2016mid V341b2
		新基準

		129-3-218(100.0% R-91.1)	


		秒読み100[ms]

		38.5%	
		#269
		やねうら王2016mid V341b
		eval 225_6000M
		#0
		やねうら王2016mid V341b2
		新基準

		380-9-607(100.0% R-81.4)	



	220_4033M

		秒読み100[ms]

		27.6%	
		#268
		やねうら王2016mid V341b
		eval 220_4033M
		#0
		やねうら王2016mid V341b2
		新基準

		249-6-652(100.0% R-167.2)	


		秒読み500[ms]

		27.5%	
		#268
		やねうら王2016mid V341b
		eval 220_4033M
		#0
		やねうら王2016mid V341b2
		新基準

		82-0-216(100.0% R-168.3)	



	255_3680M

		秒読み100[ms]

		30.2%	
		#267
		やねうら王2016mid V341b
		eval 255_3680M
		#266
		やねうら王2016mid V341b2
		新基準

		163-0-376(100.0% R-145.2)	


		秒読み500[ms]

		25.5%	
		#267
		やねうら王2016mid V341b
		eval 255_3680M
		#266
		やねうら王2016mid V341b2
		新基準

		48-0-140(100.0% R-186.0)	


		秒読み1000[ms]

		25.9%	
		#267
		やねうら王2016mid V341b
		eval 255_3680M
		#266
		やねうら王2016mid V341b2
		新基準

		41-1-117(100.0% R-182.2)	

・学習時に置換表オフに出来たほうが良いのでは..
	→　learn.hに書けるようにした。

・mini-batchサイズをlearn.hに書けるようにした。



■　2016/07/21

・40コアでテスト

	network上のファイルだとそこがボトルネックになるのか？
	→　ちょっとマシになったがやはり遅い。
	→　sfenのunpackとかがボトルネックになっている。
	うわぁぁぁ。

	Position::sfen()、stream使わないようにして書き直すか…。
	→　高速化した。

	HT8コアで100万局面が25秒→17秒に短縮した。

		log
		threads 40
		learn \\Ws2012_860c_yan\e\genkif201607\kifu201607151400.bin \\Ws2012_860c_yan\e\genkif201607\kifu201607152200.bin \\Ws2012_860c_yan\e\genkif201607\kifu201607171700.bin \\Ws2012_860c_yan\e\genkif201607\kifu201607171800.bin

	HT40でSSD上なら100万局面4,5秒。ネットワーク上のHDDだと15秒ぐらい。何も速くなってないな。これは参った…。
	もう少し大きなSSD買おう…。そうしよう…。

	SGDとAdaGrad 10億局面ほど回して比較。

	SGD 196.983
	AdaGrad 196.329
	↓ ここから再開して20億局面
	SGD 200超えた
	AdaGrad 210超えた
	発散してる感じ？

・手番クリアして、手番のgrad=0にして誤差がどれだけ下がるかテスト。
	スタート時点で227。7ぐらい高いのか。これが195ぐらいに下がってくれればKPP手番は不要かも。
	rmse = 0.094付近から。確かにrmse少し高いな。

	→　発散した。手番消している分、eta半分にしないと辻褄が合わないのか。そうか…。再チャレンジ。
	→　突然発散するの、どこかがオーバーフローしているからでは…。

	eta、1/4にしてSGDで再開。


・手番の値を動かすの、η2 = η/4とかでいいのでは..。
・評価関数パラメーターの各値にリミットをかける。

	INT16_MAX/2 ≒ 8096 , FV_SCALEで割って256。
	　KPPの位置評価、そんなに大きな値になるのはおかしいのでは。


						ASSERT_LV3(abs(kk[k1][k2][0]) < INT16_MAX / 2);
						ASSERT_LV3(abs(kk[k1][k2][1]) < INT16_MAX / 2);
				
		#if ASSERT_LV < 3
						// 絶対値を抑制する。
						SET_A_LIMIT_TO(kk[k1][k2],INT16_MIN/2,INT16_MAX / 2);
		#endif

	→　これassertで書くのやめて、この制限は必ずしておくことにする。

・AdaGradに最初のほうの更新量を抑制するε項を追加。

				// AdaGradにおいて最初のほうのiterationでは値を動かさない。
				if (w.g2[0] < 0.01f || w.g2[1] < 0.01f)
						goto NEXT_KK;

			→　これやめて、epsilon項を追加するように変更。

・AdaGradが発散するはずがなかった。kkpだけ更新式間違えてた。
	→　うまく学習できるようになった。

・ゼロパラメーターからの学習、再挑戦。

・AdaGradのη、再調整。
	eta =  2.0  , ε=10 , mean_error = 212.141　→　207.130(1000万局面)
	eta =  5.0  , ε=10 , mean_error = 213.765  →  206.951(1000万局面)
	eta =  5.0  , ε= 5 , mean_error = 214.090  →  206.897(1000万局面)
	eta =  6.0  , ε= 3 , mean_error = 215.484  →  207.038(1000万局面)
	eta =  7.0  , ε= 1 , mean_error = 217.741  →  208.684(1000万局面)
	eta = 10.0  , ε= 1 , mean_error = 225.195  →  215.708(1000万局面)

	発散しないなら大きな値から開始したほうが気分がいいのでは。

		log
		threads 8
		learn \\Ws2012_860c_yan\e\genkif201607\kifu201607151400.bin \\Ws2012_860c_yan\e\genkif201607\kifu201607152200.bin \\Ws2012_860c_yan\e\genkif201607\kifu201607171700.bin \\Ws2012_860c_yan\e\genkif201607\kifu201607171800.bin

・手番なし、mean_error = 201から下がらない。(10億局面あたりでサチった模様)

	AdaGrad、g2が大きくなってくるとそのパラメーター移動させられなくなるので他のパラメーターが遅れて追随してきてもどうしようもないという意味はあるのでは。
	　g2の条件、制限しておくほうが無難なような気も。しかし、そこをゆるやかに減衰させていくとAdamになるのか…。うーん。

	→　g2 *= 0.999; みたいな式を入れると、どこかで律速するのでこういうのを入れるべきかも知れない。

・
		log
		threads 40
		learn ..\YaneuraOu2016Engine\genkif\kifu201607171700.bin ..\YaneuraOu2016Engine\genkif\kifu201607151400.bin ..\YaneuraOu2016Engine\genkif\kifu201607171800.bin ..\YaneuraOu2016Engine\genkif\kifu201607152200.bin



■　2016/07/20

・AdaGradうまく動くようになったので一晩回してみる。
	→　なんかおかしい。やりなおし。

	やりすぎであったか…。
-				if (w.g2[0] < 1000.0f || w.g2[1] < 1000.0f)
+				if (w.g2[0] < 0.01f || w.g2[1] < 0.01f)
	→　やはり原因はこれだったみたいだ。

		log
		threads 8
		learn \\Ws2012_860c_yan\e\genkif201607\kifu201607151400.bin \\Ws2012_860c_yan\e\genkif201607\kifu201607152200.bin \\Ws2012_860c_yan\e\genkif201607\kifu201607171700.bin \\Ws2012_860c_yan\e\genkif201607\kifu201607171800.bin

		1000万局面での学習率の調整。

		eta = 2
			mean_error = 213.334 → 206.672

		eta = 2.5
			mean_error = 218.201 → 210.661

		eta = 5
			mean_error = 219.022 → 224.263 → 208.294

		eta = 10
			mean_error = 247.432 → 285.383 → 233.979

		// 乱数を固定化して200万局面

		eta = 1.7
			mean_error = 212.212 → 209.221
		eta = 1.8
			mean_error = 212.261 → 209.029
		eta = 1.9
			mean_error = 212.206 → 209.723
		eta = 2.0
			mean_error = 212.515 → 209.497
		eta = 2.1
			mean_error = 212.969 → 209.951

		このテスト自動化して1億局面ぐらいのところで比較すべき。

・交差エントロピーも試す。

		eta = 1.8 , cross entropy
			mean_error = 212.221 →　208.536(200万局面) →　206.486(1000万局面)

		eta = 2.0 , cross entropy
			mean_error = 213.109 →　208.993(200万局面) →　205.895(1000万局面)

		eta = 2.2 , cross entropy
			mean_error = 213.417 →　209.231(200万局面) →　206.037(1000万局面)

・評価関数ファイルの定期的な保存、もう少し何か考える。(べき)
	 10億局面ごとにファイル名を変更して保存するなどしたほうが良いのでは…。
	 →　変更した。

・AdaGrad、中断するときにg2の配列を保存しておかないと再開できないのでは…。まあいいか…。
	AdaGradのほうがSGDよりいい値に行くんだろうけど、いまひとつ…。

	SGDをadaptiveにしたほうがいいのではなかろうか。

	しかしAdaGradは、mini-batchにしなくてもうまくいくのかも？うむむ？

・ゼロベクトルから学習させたやつ、R2000程度は余裕でありそう。うーん、そうなのか…。


■　2016/07/19

・ミラー、よく考える。
	→　実装した。
	→　ミラー、なんかおかしい。やめよう。

・評価関数、ゼロパラメーターから学習できるのかテスト。

	rmse = 0.190385 // zero vector
	rmse = 0.170538 // 1000万局面
	rmse = 0.163090 // 2000万局面。

	そこそこいけるかも？

・評価関数パラメーターの保存ルーチン書く。
→　書けた。

・ゼロベクターから学習させてみる。

	45億ほど。

		log
		threads 8
		learn \\Ws2012_860c_yan\e\genkif201607\kifu201607151400.bin \\Ws2012_860c_yan\e\genkif201607\kifu201607152200.bin \\Ws2012_860c_yan\e\genkif201607\kifu201607171700.bin \\Ws2012_860c_yan\e\genkif201607\kifu201607171800.bin

	8HT、25秒で100万局面。4.5G * 25 / 1M = 4500 * 25 = 112,500秒。1.5日ぐらいで終わる感じ？

	rmse = 0.194836 , mean_error = 490.541 //	開始時。
		0ベクトルだと490も差があるのか…。
		たぶん0.01ぐらいになると以前の評価関数と同じぐらい。
		ゼロから棋譜生成して学習を繰り返してもいいぐらいだな…。
	rmse = 0.155197 , mean_error = 373.743  //  1億
	rmse = 0.151064 , mean_error = 360.2    //  2億
	rmse = 0.149133 , mean_error = 352.575  //  3億
	rmse = 0.150657 , mean_error = 353.563  //  4億
	rmse = 0.14781 , mean_error = 341.956   // 10億

	この速度だと80億やっても..。

	rmse = 0.0966129 , mean_error = 226.607 // 再起動するとなぜかだいぶ減ってる。なんで？
	// 置換表に値が残っていて下がっていないように見えていたのかも。rmseの計算前に置換表の世代進めたほうが良いのでは。
	
	棋譜の順番入れ替えて再開。
		log
		threads 8
		learn \\Ws2012_860c_yan\e\genkif201607\kifu201607171800.bin \\Ws2012_860c_yan\e\genkif201607\kifu201607151400.bin \\Ws2012_860c_yan\e\genkif201607\kifu201607152200.bin \\Ws2012_860c_yan\e\genkif201607\kifu201607171700.bin
	
	ここから8億回したがmse上がった。qsearch()の結果に対して強化学習するのがいけないんだろうな。

	qsearch()の結果ではなくevaluate()に対して強化学習するか。
	↓
	何も下がらない。なんで？

	学習オプションを一箇所にまとめたほうが良いのでは…。
	→　まとめた。

	evaluate()で下がらないのはSGDのほう間違いなく何かバグってる。
	count少ないときには勾配出てないから値は動かさないほうが良いのでは。

	evaluateのほう、損失関数下がるようになった。ifdefどこか名前間違ってたっぽい。


・Weight配列、型指定間違っていたので修正して、ゼロベクターからの学習再開。
	→　と思ったら問題なかった。

・256手付近でmax_plyのためleafが辿れないのまずいかも。

	-    for (ply = 0; ply < MAX_PLY; ++ply)
	+    for (ply = 0; ply < MAX_PLY - 16; ++ply)

	棋譜生成のときに16手前までにしとくか…。


■　2016/07/18

・AdaGradで学習する部分書けた。次元下げまだだけど。

		threads 8
		learn \\Ws2012_860c_yan\e\genkif201607\kifu201607151400.bin

	100万局面 17秒/8スレッド。
	40スレッドで17/5秒。80億局面で8000倍 = 27200秒。1周7.55時間。

・SGDで
	rmse = 0.09053
	rmse = 0.08677 // 1000万局面
	rmse = 0.08520 // 2000万局面
	// rmse下がった!!

	↓kpp次元下げあり。
	rmse = 0.0897942
	rmse = 0.0866647 // 1000万局面
	rmse = 0.0862505 // 2000万局面
	rmse = 0.0861872 // 3000万局面

	// ミラーなしで、p1,p2の入れ替えだけあり。
	rmse = 0.0898962
	rmse = 0.0870459 // 1000万局面
	rmse = 0.0866125 // 2000万局面
	rmse = 0.0863849 // 3000万局面

	// ミラーは入れておくか。
	
・AdaGradで
	rmse = 0.0907107
	rmse = ...
	// 最初の数回ぐらい、むしろ上がるのか。そうか。
	// この調整難しいな。updateに時間がかかるというのもあるし…。

	SGDでがんばろう。


■　2016/07/17

・生成された80億局面のファイルの読み込み例

	while (!fs.eof())
	{
		u8 data[34];
		fs.read((char*)data, 34);

		auto sfen = pos.sfen_unpack(data);
		pos.set(sfen);

		// 評価値は棋譜生成のときに、この34バイトの末尾2バイトに埋めてある。
		Value value = (Value)*(int16_t*)&data[32];

		cout << pos << value << endl;
	}

・learnのスレッド並列で局面ファイルを読み込むルーチン、少し書いた。


#if 1
	{
		fstream fs;
		fs.open("a.bin", ios::binary | ios::in);

		PackedSfenValue p[10000];
		while (fs.read((char*)&p, sizeof(PackedSfenValue)*10000))
		{
			for (int i = 0; i < 10000; ++i)
			{
				auto q = p[i];
				auto sfen = pos.sfen_unpack(q.data);
				pos.set(sfen);
			}
			cout << '.';
		}
		return;
	}
#endif

・learnコマンド少し実装。packed sfenファイルの読み込みとshuffle～unpackのコードは書けた。

	あとは、棋譜分離してmse計算する部分と、AdaGradか何かで値動かす部分か…。

・mseを計算するルーチン書けた。
	→　初回だけ表示おかしい。デバッグすべき。
	→　二回目以降、置換表にhitするからか。そうか…。



■　2016/07/16

・ai5さんいわく、USI原案によると手駒の表記は、飛・角・金・銀・桂・香・歩の順らしい。

	Wayback Machine
	https://web.archive.org/web/20080131070731/http://www.glaurungchess.com/shogi/usi.html

	> The pieces are always listed in the order rook, bishop, gold, silver, knight, lance, pawn;

	ai5さんのおっしゃる通りのようです。将棋所の作者が将棋所で実装するときに削ったようですね。
	せっかく原案のほうはsfen文字列が一意に定まるようになっていたというのに…。いまのうちに思考エンジン側も
	出力はこれに倣うべきかも知れませんね。このあと禍根を残さないためにも…。

・上の内容に伴い、Position::sfen()を修正。

			const Piece USI_Hand[7] = { ROOK,BISHOP,GOLD,SILVER,KNIGHT,LANCE,PAWN };
			auto p = USI_Hand[pn];

・makebook sortコマンドを実行したときにsfen文字列を再構築するように変更する。



■ 2016/07/15

・sfenの手駒の表記の揺れを補整するために、makebook sortコマンドのときに
　一度sfen()から局面を作ってそれを書き出すようにすることで、やねうら王定跡フォーマットで
　使っているsfen文字列化したほうがよさげ。

	https://twitter.com/merom686/status/753406922414432259
		SFENで先手の持ち駒が角金歩のときの表記。
		BGP : ShogiGUI, 局面ペディア
		PGB : Blunder.Converter
		PBG : やねうら王定跡フォーマット2016

	→　うーん。逆に、やねうら王定跡フォーマット2016では手駒のところは、PLKSBRGの順であるものとしよう。

・ShogiGUIの検討モードで定跡DBにhitしたときの表示、思考エンジン側でどうするのがベストなのかよくわからない。

	→　ShogiGUIの掲示板で質問しておく。

		ShogiGUIの検討モードで、ShogiGUI側の定跡を用いない設定で検討させているときに、
		思考エンジン側の定跡にhitしたときに、思考エンジン側は複数の候補手が定跡に登録されているのでこれを通常の思考を返すときのように" multipv 1 "のようにして返したいのですが、しかしそうすると、ShogiGUI側で候補手3手のようにしていると" multipv 3"の指し手までしか検討ウィンドウに表示されないように思います。

		ユーザーにとってはおそらく思考エンジン側の定跡DBにhitしている以上、そのすべてが表示されて欲しい気がするのですが、だからと言って「候補手10手」のようにしていると、定跡にhitしない局面でMultiPV = 10で思考してしまうため、ユーザーはこの設定を変えるために定跡にhitするごとに、「候補手3手」と「候補手10手」とを切り替えながら検討することになって、なんともユーザビリティが悪いように思うのです。

		「候補手3手」の状態であっても" multipv 4"以降の指し手も検討ウィンドウに表示されるような仕様にしては何かまずいのでしょうか。あるいは思考エンジン側で何か出来ることがあれば教えていただければと。

	→　ShogiGUIの作者、対応するとのこと。助かる。


■ 2016/07/14

・mirror_write()絡み、何かバグがあるらしい。あとで調査。
	→　バグ修正した。

・Apery(WCSC26)の評価関数バイナリ側の問題もあったのでAperyのGitHubで報告しておいた。

	https://github.com/HiraokaTakuya/apery/issues/7

		Apery(WCSC26)の評価関数ファイルについて。

		問題点1) kppテーブルなのですがkpp[k][p1][p2]に対して、p1==0 もしくは p2==0のときに、値がゼロにならない。(ゴミが入っている)

		駒落ちのとき、BonaPiece == 0としたいので、ここにゴミが入っていると駒落ちでの局面評価がおかしくなります。ここ、ゼロで埋めていただけないでしょうか。kkpテーブルも同様にkkp[k1][k2][0]に対してゴミが入っています。

		問題点2) kkpテーブルのkkp[k1][k2][p]に対して、p == e_hand_pawn-1のような0枚目の手駒に対する値が0になっていない。

		実際にはこの要素は参照しませんが、ここにゴミが入っていると、assert(kkp[k1][k2][p][0] == -kkp[~k2][~k1][~p][0]);のようなassertが通らなくなってしまいます。(Squareに対して~sqは180度回転した升を返す演算子、BonaPieceに対して~pは(盤上の駒であれば180度回転させ)、相手の駒にする演算子だとします。)

		問題点3) kpp[k1][p1][p2] != kpp[k1][mirror(p1)][mirror(p2)] ただし、file_of(k1) == FILE_5

		玉が5筋にいるときに、kppの要素が左右のミラーに対して対称性がありません。玉が5筋以外にいるときは対称性があるので学習上の何らかのバグでノイズを入れてしまっているのではないかと思います。当然ながら、ここは対称にしたほうが棋力的にも強くなるのではないかと思います。

		例) kpp[SQ_51][f_hand_pawn][f_pawn + SQ_12] != kpp[SQ_51][f_hand_pawn][f_pawn + SQ_92]
		※　玉が51にいて、「先手の手駒の1枚目の歩」と、「盤上の12の歩」というkpp値が、この12の歩を92に移動させたときのものと同じ値でないといけないはずなのに、そうはなっていません。

		急ぎませんので、次回、評価関数バイナリを公開されるときにでも直っていれば嬉しいです。


■ 2016/07/12

・深さ8で1億局面ほど作ってみる。
threads 40
hash 4096
gensfen 8
→　HT40で3分で20万局面。
→　1日9600万局面程度作れそう。HT80で2億。5台で10億。8日で80億。
　そこそこ作れるような？
→　棋譜生成中に落ちた。原因不明。ASSERT有効にしてVisual Studio入れてデバッグするか…。
→　このあと棋譜生成のPCでしばらく回しておく。

・定跡作ってるの、最後の1 nodeが20時間かけたのに保存されてなかった。禿げそう。
　まあいいや…。

→　原因わかった。threadの終了フラグは立っていても、joinせずに抜けているので、
 threadのstack破壊しているようだった。修正した。

・深さ6で80億作ってみる。
	threads 40
	hash 4096
	gensfen 6
	→　HT40で30秒で20万局面。6倍速いので..。HT80で12億/日。

・mirror_write()絡み、何かバグがあるらしい。あとで調査。

・動作テストしてリリース。

	bookfile yaneura_book1.db
	bookonthefly true
	isready
	go


■ 2016/07/11

・てか、compute evalのタイミングでis_ready()呼び出しても良いのでは…。
　→　まあいいや。これやりだすとしんどい(気がする)

・スレッドごとに別の局面を探索させるときにhistoryみたいなglobalテーブル持っていると
　まずい気がしてきた。

・定跡生成中に保存できなくてそのまま思考だけ進むことがあるの、本当に謎。
        if (loop_count == loop_max)
		この条件先に満たしてしまうのか…。
		  cout << "waiting for all workers" << endl;
		最後にcallback一回必要なんだな。修正した。

・やねうら大定跡、今日中に生成終わりそう。
　もう少し追加で回しておくか…。


■ 2016/07/10

・shared memoryを用いた評価関数パラメーターの複数プロセス間共有。

	実装した。遅くはないようだ、メモリ節約にはならない模様。

	===========================
	Total time (ms) : 491304
	Nodes searched  : 341103366
	Nodes/second    : 694281

	↑あれ？探索node数が異なる…。配列をポインタにしたときに正しく互換性が保てていないのか…。そうか…。

	===========================
	Total time (ms) : 108695
	Nodes searched  : 68270869
	Nodes/second    : 628095

	shared memory版
	===========================
	Total time (ms) : 102153
	Nodes searched  : 68270869
	Nodes/second    : 668319
	→　完全に一致した。

	isreadyコマンドを入力してからbenchコマンドを叩くと少しnpsが高く出るようだ。
	理由はよくわからないが、評価関数の読み込みから時間をあけて十分CPU負荷が下がってからbenchコマンドを叩いているからか。

・shared memoryでsystem memoryの使用量が減らない問題

	CreateFileMapping, MapViewOfFile, how to avoid holding up the system memory
	http://stackoverflow.com/questions/1880714/createfilemapping-mapviewoffile-how-to-avoid-holding-up-the-system-memory

	VirtualFree on shared memory
	https://groups.google.com/forum/#!topic/microsoft.public.win32.programmer.kernel/3SvznY38SSc

	SEC_RESERVEを指定して確保したあとVirtualUnlockするというhackが書いてある。
	→　pagingされていたものが開放されるが、そのあとアクセスしないことが前提なのか…。

・共有メモリを用いて、メモリ使用量が減らない問題、解決した。
　ベンチマークコマンドがデフォルトで1GB確保しているだけだった。
　共有自体、うまく行っていた。

　あと、npsが上がらない問題も、置換表を16MBだとnps出た。1024MBだと10%ぐらいダウンした。
　なるほど。そういうことか…。


■ 2016/07/09

] V3.33

・やねうら大定跡のような大きなファイルを扱う場合は、packed sfenにして、
	メモリに丸読みせずに1手指すごとにバイナリサーチするような実装もあったほうがいいのかも。
	いや、packed sfenにせずともバイナリサーチは出来るか。そうか…。
	テキストファイルのバイナリサーチ、コード、結構ややこしい気がしなくもないが…。

		BookOnTheFly    : 定跡ファイルをメモリに丸読みしない
		
		やねうら大定跡のような巨大な定跡を試合開始時に読み込まれるとその読み込みに時間がかかるため、
		対局中、1手指すごとにファイルを読みに行くオプション。

	うーん。書き出しのときにsfen文字列でsortされている必要性が出てくるな…。
	これ、定跡フォーマットがそのことを保証していないので、意外と面倒だな。
	読み込みのときのparseを並列化するだとか？

	やはり、packed sfenにして、そちらはsortしておき、バイナリサーチで調べられるように実装すべきかな…。
	もうちょっと定跡ファイルが大きくなってきて気が向いたらやろう。

	てかpacked sfenにしても指し手文字列とその指し手の数が固定長ではないから
	バイナリサーチしにくいことには変わりないのか…。

	どのみち定跡を丸読みしてsortするコマンドは必要なんだな…。
	最終的にファイルが数百GBになる可能性がなくはないが。
	そうなったらそうなったで分割してsortてmergeするプログラム書けばいいのか…。

	やねうら大定跡、1GBを超えたら考えよう。
	しかし書き出しでそこがボトルネックになる可能性はあるな…。
	
	ファイルサイズが問題なのではないから、やはりsfen文字列でsortしてそのまま保存するのが一番良いのでは。

	makebook sort book1.db book2.db
	こうやるとbook2.dbにsortされたものが書き出される。(ように実装する。)

	→　やっとon the flyで定跡参照できるようになった。長かった…。


・Hyper-Vでのbenchテスト

	非Hyper-V 1319万nps 40threads
	Hyper-V   1132万nps 40threads // 14%ぐらいダウン
	Hyper-V   1856万nps 64threads // 40コア時の64/40倍にはなかっているが…。
	非Hyper-V 2079万nps 64threads // 無理やり64論理コア Hyper-Vを入れるとそうなった。


Hyper-V、計算資源として用いるにはオーバーヘッドが大きいように思う。

・USIプロトコルを拡張して、1プロセスで個別にコマンドを並列的に受け付けるモードを用意すべき？
	→　coutの出力がボトルネックになりかねない…。難しい。
	メモリ不足とNUMAでこんなに苦労するとは…。
	coutの出力lockを取り合って出力が詰まりそう…。
	評価関数パラメーターだけshared memory経由で共有かけられると良いのだが…。
	DLLにして分離するとか…。memory mapped file使うだとか…。

	置換表256MB*80 = 20.48GB。
	置換表だけでも馬鹿にならないな。

	DLLもmemory mapped fileも内部的にはOSのpagingの仕組みに依拠していて、
	どちらもオーバーヘッドがなくはないような…。
	ソフト上でどうにかすべきか…。
	TTは共有しててもいいから、Searchのglobalオブジェクトだけどかせば
	あとは何とかなるような気も。ああ、ThreadsとかOptionsもか。
	ただならぬ面倒くささのような気がしてきた。
	USIの並列化された独自応答部を作るほうがいいのかも知れない。
	しかしそれだと持ち時間が調整出来ないのか…。

	globalオブジェクト閉じ込めたC++のclass作って、全部そこ参照するだとか…。
	かなりの関数にそれつけて回るの大変だな。
	this_thread()とかに突っ込むか。
	pos->this_thread()->Options["..."];
	それはそれでダサい気がする。

	MemoryMappedFileを一度試してみる。
	評価関数と置換表を共有してみる。
	置換表は、別プロセスであればgeneration自体は異なるから、共有してもうまく動く(気がする)。
	よしよし、うまくいきそうな気がしてきた。


■ 2016/07/05

] V3.32

・定跡生成中の中断を実装する。
	→　この処理、難しいので定期的に保存するコードを追加することにする。
	→　追加した。

・book mergeの機能、あったほうがいいような気がしなくもない。追加してみる。
	→　実装した。うまく動いてるっぽい。

・定跡絡み。
	BookEvalDiff 定跡の第一候補手との評価値の差
	BookEvalBlackLimit 定跡の先手の評価値下限
	BookEvalWhiteLimit 定跡の後手の評価値下限
	BookDepthLimit 定跡のdepth下限(0=下限なし)

・2016MidのEVAL_LEARNバージョン、Midと統合。

	#ifdef YANEURAOU_2016_MID_ENGINE_LEARN
	#define ENGINE_NAME "YaneuraOu 2016 Mid Learn"
	#define YANEURAOU_2016_MID_ENGINE
	#define ASSERT_LV 3
	#define ENABLE_TEST_CMD
	#define EVAL_KPPT
	#define USE_SIMPLE_SEE
	#define USE_MOVE_PICKER_2016Q2
	#define USE_MATE_1PLY
	#define USE_ENTERING_KING_WIN
	#define USE_TIME_MANAGEMENT
	#define KEEP_PIECE_IN_GENERATE_MOVES
	#define ONE_PLY_EQ_1
	// 学習絡みのオプション
	#define USE_SFEN_PACKER
	#define EVAL_LEARN
	// 定跡生成絡み
	#define ENABLE_MAKEBOOK_CMD
	#endif
	→削除。

	VC++2015 (Hyper-V 8コア割当時)
	===========================
	Total time (ms) : 101001
	Nodes searched  : 68270869
	Nodes/second    : 675942

	gcc PGO(Hyper-V 8コア割当時)
	===========================
	Total time (ms) : 101246
	Nodes searched  : 68270869
	Nodes/second    : 674306

	ほぼ変わらない…。Hyper-V環境下が特殊なのかも…。
	VC++2015をupdate3にしたからなのか、gccのほう-fltoを外したからなのか…。

		※　YaneuraOu-2016-Mid_gcc.exeは、Msys2のg++でコンパイルした
		AVX2用の実行ファイルです。Visual C++2015でコンパイルしたものより10数%速いようです。
		(こちらを使ったほうがレーティングも+R30～40高いと思います)

	→　削除。


・定跡生成のときに思考対象局面の開始手数を指定できるように。startmoves 

	Hash 8192
	MultiPV 10
	Threads 12
	makebook think records1.sfen yaneura_book1.db moves 4 depth 32
	// 206node。これなら2,3日で終わるか？
	// 開始2016/07/05 6:50

	Hash 8192
	MultiPV 10
	Threads 40
	makebook think records1.sfen yaneura_book1.db startmoves 5 moves 5 depth 32
	// 323node。40スレッドなので1日で終わる？
	// 開始2016/07/06 12:30

	Hash 8192
	MultiPV 10
	Threads 40
	makebook think records1.sfen yaneura_book1.db startmoves 6 moves 6 depth 32
	// 678node。
	// 開始2016/07/06 12:30

	Hash 8192
	MultiPV 10
	Threads 12
	makebook think records1.sfen yaneura_book1.db moves 8 depth 24
	// 4418 node。
	// 開始2016/07/05 6:50 → 翌日終了。

	Hash 1024
	MultiPV 5
	Threads 4
	makebook think records1.sfen yaneura_book1.db moves 10 depth 18
	// 6000ノードほど。1秒で2,3ノード処理できるから1時間かからない模様。
	// → multipv 5で16手目までやることに。

	Hash 1024
	MultiPV 5
	Threads 8
	makebook think records1.sfen yaneura_book1.db moves 16 depth 18
	// 51000ノードほど。丸一日あればいけそう。てか32手目まで入れても知れてるような。
	// depth 18の指し手なんかあっても邪魔なだけか…。まあいいや、生成してみる。

	Hash 8192
	MultiPV 5
	Threads 12
	makebook think records1.sfen yaneura_book1.db moves 32 depth 18
	// 42万nodeの模様。2,3日で終わるか。そうか。
	// 開始2016/07/05 6:50

	→　やねうら大定跡.txtに移動。

■ 2016/07/04

] V3.31

		[HISTORY]
		PARAM_FUTILITY_AT_PARENT_NODE_SEE_DEPTH : 4 → 5(50.52%) : ←(値3,勝率49.48%,500局,有意60.76%) ,○(値4,勝率47.12%,500局,有意90.59%) ,→(値5,勝率50.52%,500局,有意39.20%) ,
		PARAM_FUTILITY_AT_PARENT_NODE_MARGIN : 256 → 200(49.79%) : ←(値200,勝率47.93%,500局,有意83.01%) ,○(値200,勝率49.17%,500局,有意65.94%) ,→(値200,勝率49.79%,500局,有意55.44%) ,
		PARAM_FUTILITY_AT_PARENT_NODE_DEPTH : 7 → 8(46.71%) : ←(値6,勝率46.06%,500局,有意96.22%) ,○(値7,勝率46.17%,500局,有意95.82%) ,→(値8,勝率46.71%,500局,有意93.28%) ,
		PARAM_FUTILITY_RETURN_DEPTH : 7 → 8(52.48%) : ←(値6,勝率51.14%,500局,有意29.25%) ,○(値7,勝率49.48%,500局,有意60.78%) ,→(値8,勝率52.48%,500局,有意12.79%) ,
		PARAM_FUTILITY_MARGIN_QUIET : 125 → 125(49.80%) : ←(値122,勝率46.35%,500局,有意95.01%) ,○(値125,勝率49.80%,500局,有意55.40%) ,→(値128,勝率49.38%,500局,有意62.53%) ,
		PARAM_FUTILITY_MARGIN_ALPHA : 197 → 194(51.95%) : ←(値194,勝率51.95%,500局,有意18.24%) ,○(値197,勝率49.07%,500局,有意67.54%) ,→(値200,勝率48.14%,500局,有意80.61%) ,
		PARAM_QUIET_SEARCH_COUNT : 64 → 62(56.61%) : ←(値62,勝率56.61%,500局,有意0.15%) ,○(値64,勝率49.06%,500局,有意67.61%) ,→(値66,勝率47.10%,500局,有意90.68%) ,
		PARAM_RAZORING_MARGIN4 : 554 → 554(50.61%) : ←(値546,勝率48.35%,500局,有意78.01%) ,○(値554,勝率50.61%,500局,有意37.57%) ,→(値562,勝率47.91%,500局,有意83.16%) ,
		PARAM_RAZORING_MARGIN3 : 603 → 595(51.03%) : ←(値595,勝率51.03%,500局,有意30.86%) ,○(値603,勝率48.74%,500局,有意72.43%) ,→(値611,勝率48.35%,500局,有意77.97%) ,
		PARAM_RAZORING_MARGIN2 : 570 → 578(50.82%) : ←(値562,勝率46.09%,500局,有意96.16%) ,○(値570,勝率48.76%,500局,有意72.31%) ,→(値578,勝率50.82%,500局,有意34.19%) ,
		PARAM_RAZORING_MARGIN1 : 483 → 475(48.57%) : ←(値475,勝率48.57%,500局,有意75.14%) ,○(値483,勝率48.03%,500局,有意81.86%) ,→(値491,勝率47.12%,500局,有意90.59%) ,
		PARAM_NULL_MOVE_DYNAMIC_BETA : 67 → 64(49.48%) : ←(値64,勝率49.48%,500局,有意60.73%) ,○(値67,勝率46.23%,500局,有意95.48%) ,→(値70,勝率44.58%,500局,有意99.27%) ,
		PARAM_NULL_MOVE_DYNAMIC_ALPHA : 823 → 839(48.46%) : ←(値807,勝率47.40%,500局,有意88.21%) ,○(値823,勝率45.29%,500局,有意98.34%) ,→(値839,勝率48.46%,500局,有意76.58%) ,
		PARAM_FUTILITY_AT_PARENT_NODE_SEE_DEPTH : 4 → 3(52.69%) : ←(値3,勝率52.69%,500局,有意10.98%) ,○(値4,勝率50.62%,500局,有意37.52%) ,→(値5,勝率49.38%,500局,有意62.51%) ,
		PARAM_FUTILITY_AT_PARENT_NODE_MARGIN : 256 → 256(52.24%) : ←(値200,勝率49.59%,500局,有意58.99%) ,○(値200,勝率52.24%,500局,有意14.94%) ,→(値200,勝率51.03%,500局,有意30.86%) ,
		PARAM_FUTILITY_AT_PARENT_NODE_DEPTH : 7 → 8(53.10%) : ←(値6,勝率52.29%,500局,有意14.69%) ,○(値7,勝率49.69%,500局,有意57.21%) ,→(値8,勝率53.10%,500局,有意7.94%) ,
		PARAM_FUTILITY_RETURN_DEPTH : 7 → 7(52.72%) : ←(値6,勝率48.87%,500局,有意70.71%) ,○(値7,勝率52.72%,500局,有意10.84%) ,→(値8,勝率49.18%,500局,有意65.84%) ,
		PARAM_FUTILITY_MARGIN_QUIET : 128 → 125(51.16%) : ←(値125,勝率51.16%,500局,有意29.06%) ,○(値128,勝率47.28%,500局,有意89.16%) ,→(値131,勝率50.00%,500局,有意51.81%) ,
		PARAM_FUTILITY_MARGIN_ALPHA : 200 → 197(49.59%) : ←(値197,勝率49.59%,500局,有意58.99%) ,○(値200,勝率43.00%,500局,有意99.91%) ,→(値203,勝率47.42%,500局,有意88.11%) ,

	book生成テスト
	Hash 1024
	MultiPV 5
	Threads 8
	makebook think 2016.sfen yaneura_book1.db moves 16 depth 18
	→　うまく動くようになった

	適当な棋譜を食わせてざっくりと定跡を生成してみる。

	Hash 1024
	MultiPV 7
	Threads 4
	makebook think records1.sfen yaneura_book1.db moves 4 depth 24 →　完了

	Hash 1024
	MultiPV 10
	Threads 4
	makebook think records1.sfen yaneura_book1.db moves 4 depth 32 →　やりかけ

	Hash 1024
	MultiPV 5
	Threads 4
	makebook think records1.sfen yaneura_book1.db moves 8 depth 18

	とりあえず16手目までdepth18で回しておく。
	→　あかん。結構ある。これは死ぬ。8手目まで回して、あとは新しいPC来てからでいいや。
	→　定跡生成中の途中中断に対応させないとやってられない。

	Hash 1024
	MultiPV 5
	Threads 4
	makebook think records1.sfen yaneura_book1.db moves 10 depth 18


・やねうら王2016MidのLEARNバージョン、配布するか？
	→　もうしばらくしてからでいいような…。
	→　やねうら王2016MIDと統合してもいいような…。

・g++で-fltoでセグフォになる件、LONG_EFFECT_LIBRARY絡みか？
　　→　そうではなさげ。
    →　shogi.cppでSearch::init() (やねうら王2016Mid)が呼び出された瞬間に落ちている模様。g++のbugくさい。
	これ以上、どうしようもないので-fltoは付けないということにするしかない。


■　2016/07/02

] V3.29

・1手3秒500局でパラメーター自動調整

		[HISTORY]
		PARAM_NULL_MOVE_DYNAMIC_BETA : 67 → 64(49.48%) : ←(値64,勝率49.48%,500局,有意60.73%) ,○(値67,勝率46.23%,500局,有意95.48%) ,→(値70,勝率44.58%,500局,有意99.27%) ,
		PARAM_NULL_MOVE_DYNAMIC_ALPHA : 823 → 839(48.46%) : ←(値807,勝率47.40%,500局,有意88.21%) ,○(値823,勝率45.29%,500局,有意98.34%) ,→(値839,勝率48.46%,500局,有意76.58%) ,
		PARAM_FUTILITY_AT_PARENT_NODE_SEE_DEPTH : 4 → 3(52.69%) : ←(値3,勝率52.69%,500局,有意10.98%) ,○(値4,勝率50.62%,500局,有意37.52%) ,→(値5,勝率49.38%,500局,有意62.51%) ,
		PARAM_FUTILITY_AT_PARENT_NODE_MARGIN : 256 → 256(52.24%) : ←(値200,勝率49.59%,500局,有意58.99%) ,○(値200,勝率52.24%,500局,有意14.94%) ,→(値200,勝率51.03%,500局,有意30.86%) ,
		PARAM_FUTILITY_AT_PARENT_NODE_DEPTH : 7 → 8(53.10%) : ←(値6,勝率52.29%,500局,有意14.69%) ,○(値7,勝率49.69%,500局,有意57.21%) ,→(値8,勝率53.10%,500局,有意7.94%) ,
		PARAM_FUTILITY_RETURN_DEPTH : 7 → 7(52.72%) : ←(値6,勝率48.87%,500局,有意70.71%) ,○(値7,勝率52.72%,500局,有意10.84%) ,→(値8,勝率49.18%,500局,有意65.84%) ,
		PARAM_FUTILITY_MARGIN_QUIET : 128 → 125(51.16%) : ←(値125,勝率51.16%,500局,有意29.06%) ,○(値128,勝率47.28%,500局,有意89.16%) ,→(値131,勝率50.00%,500局,有意51.81%) ,
		PARAM_FUTILITY_MARGIN_ALPHA : 200 → 197(49.59%) : ←(値197,勝率49.59%,500局,有意58.99%) ,○(値200,勝率43.00%,500局,有意99.91%) ,→(値203,勝率47.42%,500局,有意88.11%) ,

	途中から悪化した。500局が少なすぎてSEE_DEPTHを悪いほうに変更したのが祟っている印象。

・gcc、CFLAGSにも-flto追加。

		===========================
		Total time (ms) : 105466
		Nodes searched  : 69480659
		Nodes/second    : 658796

	あまり変わらず。

・sfenのpacker、learnerと関係ないな。misc/sfen_packer.cppに移動。


■　2016/07/01

] V3.28

・学習ルーチン追加開始。

	learn/learner.cpp追加。
	gensfenコマンド追加。


・パラメーター自動調整関係

	PARAM_FUTILITY_RETURN_DEPTHが8のときにたまにASSERTに引っかかる？
	→ margin値を引いたときにevalの値が-VALUE_INFINITEを下回るのかと思ったが違うようだ。

	V3.28b
・sfenの圧縮出力追加。(かきかけ)



■　2016/06/30

] V3.27

・EVAL_LEARN絡みの作業。

  // 学習時にkppテーブルに値を書き出すためのヘルパ関数。
  void kpp_write(Square k1, BonaPiece p1, BonaPiece p2, ValueKpp value)

  // 学習時にkkpテーブルに値を書き出すためのヘルパ関数。
  void kkp_write(Square k1, Square k2, BonaPiece p1, ValueKkp value)

  を用意。

  V3.27a
・棋譜生成のためのSearchのスタブにaspiration searchを導入する。
	→　よく考えたらdepth5ぐらいでaspirationしても無駄だったのだ…。
	まあいいや。aspirationとMultiPvを導入しよう。

	> test gensfen
	うまく動いたので、とりあえずこれでいいや。

  V3.27b
・定跡ファイルの選択機能追加。


■　2016/06/29

] V3.26

	V3.26a
	・KPPTを、KKPTだけにするテストコード追加。

			秒読み200[ms]

			36.2%	
			#262
			やねうら王2016mid V326a
			KPPT=0
			#261
			やねうら王2016mid V326
			新基準。

			242-6-427(100.0% R-98.6)	


			秒読み1000[ms]

			36.2%	
			#262
			やねうら王2016mid V326a
			KPPT=0
			#261
			やねうら王2016mid V326
			新基準。

			169-13-298(100.0% R-98.5)	


			秒読み3000[ms]

			33.4%	
			#262
			やねうら王2016mid V326a
			KPPT=0
			#261
			やねうら王2016mid V326
			新基準。

			205-15-409(100.0% R-120.0)	

	KPPに手番がないとR100ぐらい下がるのか。
	評価関数の計算で2割ぐらい得するから、R50ぐらいは取り戻せるとして。
	R60ダウンなのか..。思ったより大きいような…。そうでもないような…。
	もう少し評価関数の質が良ければKPPには手番が要らない可能性も。


	・マルチスレッド時のehashの効果調べる。

	eval hash有効 4スレッド比較

		秒読み300[ms]

		50.3%	
		#264
		やねうら王2016mid V326
		no ehash Thread4
		#263
		やねうら王2016mid V326
		新基準。Thread4

		637-30-630(42.2% R1.9)	

	差は微妙。なくてもいいなら無しにしたいぐらいだが…。
	メモリまわりが速いなら意味があるのかも…。
	とりあえず、長い持ち時間でもテスト。

		秒読み2000[ms]

		48.5%	
		#264
		やねうら王2016mid V326
		no ehash Thread4
		#263
		やねうら王2016mid V326
		新基準。Thread4

		64-5-68(66.8% R-10.5)	

	計測に時間かかりすぎてまともに実験できない。現実的ではない。
	短い時間での実験結果を信じることにする。

		秒読み1000[ms]

		50.9%	
		#264
		やねうら王2016mid V326
		no ehash Thread4
		#263
		やねうら王2016mid V326
		新基準。Thread4

		353-32-341(31.1% R6.0)	

	1秒でやってみたが、やはり、ehashはほとんど効果なさげ。
	という結論を得た。
			

■　2016/06/28

] V3.25

	・EVAL_KPPT_FAST

	V3.25a
	KPPT_FASTのdo_a_black/white()をVPGATHERDD化。ベンチ上、速くなったのかどうかすらわからない。
	gccでビルドしたほうはセグフォで落ちる。なんぞこれ。

	do_a_black/white()、玉が移動したときしか関係ないし、しかもおまけの処理だから、
	ここを高速化しても無駄であったか…。そうか…。

	VPGATHERDD自体がHaswellでは遅いのと、垂直addが効率良くないのと二重苦だな…。

		// これに相当する命令がない。簡単に書けない。
		u32 a32[8];
		_mm256_storeu_si256((__m256i*)&a32,data_sum);
		sum[0] = a32[0] + a32[4];
		sum[1] = a32[1] + a32[5];

	gcc、こう書いても落ちる。


		秒読み200[ms]

		50.0%	
		#260
		やねうら王2016late V325a
		evaluate() VPGATHERDD化
		#259
		やねうら王2016late V325
		新基準

		2331-68-2327(47.7% R0.3)	

	強くなってない。速くなってない。なにこれ。


	V3.25b
	玉が移動したときのΣKPPの片側を求めるのは、VPGATHERDDですこぶる効率的に書く方法を発見した。
	というか、思い出した。




■　2016/06/27

] V3.24

	・魔女の実行時間、プロファイラで調べる。
　	  →　調べるまでもなくevaluate()だわ。

	・KPPTの評価関数の差分計算、もう少し簡略化出来るかも。
 　	  →　いい方法思いついたので自分でやる。
	・評価関数のAVX2化。→　tanuki-さんにお願い中 →　評価関数に手番を入れてから →　AVX2化考える
 　	  →　いい方法思いついたので自分でやる。

	・to_sq()→sqww_to_sq()に変更。to_sq()をmove_to()のaliasに。

	V3.24a

	・KPPTのevaluate()高速化のためにソースコード整理していく。
	・Apery、魔女風にした。


		秒読み100[ms]

		52.9%	
		#257
		やねうら王2016mid V324a
		evaluate() リファクタリング
		#256
		やねうら王2016mid V324
		新基準。

		736-11-654(1.4% R20.5)	

	nps上がった分、少し強くなった可能性。

		gcc
		===========================
		Total time (ms) : 104813
		Nodes searched  : 69480659
		Nodes/second    : 662901


		秒読み15000[ms]

		51.1%	
		#258
		やねうら王2016mid V324a-gcc
		evaluate() リファクタリング
		#0
		silent_majority_V1.1公式
		1スレッド

		70-9-67(36.6% R7.6)	

	15秒で魔女に勝ち越したのは初めて。
	もう少し対局数をやったほうがいいが、長い時間だとマシンが長時間専有されて何とも…。
	まあ、互角ということでいいや。


■　2016/06/26

] V3.23

	V3.23a
	-    // IID、null move、singular extensionの判定のときは浅い探索なのでこのときに
	-    // killer等を更新するのは有害である。
	-    if (ss->skipEarlyPruning)
	-      return;
	
	これ、もはやないほうがいいのか…。


		// fail lowを引き起こした前nodeでのcounter moveに対してボーナスを加点する。
		else if (depth >= 3 * ONE_PLY
		  && !bestMove                        // bestMoveが無い == fail low
		  && !InCheck
		  && !pos.captured_piece_type()
		  && is_ok((ss - 1)->currentMove)
	-      && is_ok((ss - 2)->currentMove))
		{

	fail low bonusも修正したほうがいいな。

		秒読み300[ms]

		50.1%	
		#249
		やねうら王2016mid V323a
		update_stats()変更。
		#248
		やねうら王2016mid V323
		新基準

		578-21-576(47.7% R0.6)	

	短い時間において弱くはなっていないので採用。

	move_to → to_sq()にしたほうがStockfishと互換性が上がるのでは…。
	変な独自性出さないほうがいいような…。
	→　これはまだいいか..

	V3.23b
	ehash、bench値は上がらないが、2手前の局面で考えた結果が生きるので
	やったほうがいいのでは。有効にして比較する。

		秒読み300[ms]

		49.6%	
		#250
		やねうら王2016mid V323b
		ehash有効。
		#248
		やねうら王2016mid V323
		新基準

		408-16-414(59.6% R-2.5)	


		秒読み2000[ms]

		50.7%	
		#250
		やねうら王2016mid V323b
		ehash有効。
		#248
		やねうら王2016mid V323
		新基準

		106-5-103(39.1% R5.0)	


		→　よくわからない。スレッド数が多いなら他のスレッドの計算結果が使えていいのかも。
		互角ぐらいなら入れたい気はする。入れる。


	V3.23c
		-	PARAM_DEFINE PARAM_FUTILITY_AT_PARENT_NODE_MARGIN = 170;
		+	PARAM_DEFINE PARAM_FUTILITY_AT_PARENT_NODE_MARGIN = 256;
		いったん元に戻したほうが良いのでは..

			value = search<NonPV>(pos, ss, rBeta - 1, rBeta, depth * PARAM_SINGULAR_SEARCH_DEPTH / 256, cutNode);
			ss->skipEarlyPruning = false;
			ss->excludedMove = MOVE_NONE;

		-	ss->moveCount = moveCount; // 破壊したと思うので修復しておく。


		  if (givesCheck
		-	&& moveCount == 1
		+	&& !moveCountPruning
			&& pos.see_sign(move) >= VALUE_ZERO)
			extension = ONE_PLY;


			else if (depth >= 3 * ONE_PLY
			  && !bestMove                        // bestMoveが無い == fail low
		-	  && !InCheck
			  && !pos.captured_piece_type()
			  && is_ok((ss - 1)->currentMove))
			{
			  // 指し手のなかに移動後の駒が格納されているのでこれで取得できる。
			  Piece prevPc = pos.moved_piece_after((ss - 1)->currentMove);

		  if (  givesCheck
			-   && moveCount == 1
	   		+	&& !moveCountPruning
			&&  pos.see_sign(move) >= VALUE_ZERO)
			extension = ONE_PLY;

			これやはり、やりすぎであったか…。

				秒読み1000[ms]

				53.3%	
				#251
				やねうら王2016mid V323c
				see parant nodeでのmargin変更など。
				#248
				やねうら王2016mid V323
				新基準

				313-11-274(4.9% R23.1)	

			少し上がったか。

	V3.23d
			  // 捕獲する指し手か、歩の成りの指し手であるかを返す。
			  bool capture_or_pawn_promotion(Move m) const
			  {
	+		#ifdef KEEP_PIECE_IN_GENERATE_MOVES
	+			// 移動させる駒が歩かどうかは、Moveの上位16bitを見れば良い
	+			return (is_promote(m) && raw_type_of(moved_piece_after(m)) == PAWN) || capture(m);
	+		#else
				return (is_promote(m) && type_of(piece_on(move_from(m)))==PAWN) || capture(m);
	+		#endif
			  }

			少し高速化。


			null moveのとき、stateEval + 2*Tempo、良くないのでは..

	-		  if ((ss - 1)->currentMove == MOVE_NULL)
	-		    eval = ss->staticEval = -(ss - 1)->staticEval + 2 * Tempo;

	-		ss->staticEval = bestValue =
	-		  (ss - 1)->currentMove != MOVE_NULL ? evaluate(pos)
			                                     : -(ss - 1)->staticEval + 2 * Tempo;
	+		ss->staticEval = bestValue = evaluate(pos);

			秒読み300[ms]

			45.1%	
			#252
			やねうら王2016mid V323d
			null moveのときのevaluate()変更。
			#251
			やねうら王2016mid V323c
			see parant nodeでのmargin変更など。

			246-8-299(99.0% R-33.9)	

			なぜか弱くなった。npsも少し落ちたような感じ。
			null move、なんでこんななるのん..。

	+	  // この処理、入れたほうがいいようだ。一見するとevaluate()は上で手番つきで求めているから
	+	  // これをやると不正確になるだけのようであるが、null moveした局面で手番つきの評価関数を呼ぶと
	+	  // 駒に当たっているものがプラス評価されて、評価値として大きく出すぎて悪作用があるようだ。

		という結論になった。


		魔女公式と比較。


			秒読み3000[ms]

			50.5%	
			#254
			やねうら王2016mid V323e gcc
			戻した。
			#0
			silent_majority_V1.1公式
			1スレッド

			204-10-200(40.2% R3.4)	


	V3.23f
	test gensfenコマンドのデバッグ中に気づいたが、
	金相当のMoveの上位16bitに駒を金としていたのでこれがkillerとかcountermoveになったときは
	非合法手と扱いになるバグがあるようだ。

		  auto from = pieces.pop();
		  // fromの升にある駒をfromの升においたときの利き
		- const auto Pt0 = pos.piece_on(from);
		- const auto Pt = type_of(Pt0);
		- auto target2 = effects_from(Pt0, from, occ) & target;
		- MAKE_MOVE_TARGET(target2);
		+  const auto Pt = pos.piece_on(from);
		+  auto target2 = effects_from(Pt, from, occ) & target;
		+  MAKE_MOVE_TARGET_UNKNOWN(target2);
	
	あとQUIET_CHECKSか。そうか。

		-  case PRO_PAWN  :
		-  case PRO_LANCE :
		-  case PRO_KNIGHT:
		-  case PRO_SILVER:
		+  case PRO_PAWN  : GEN_MOVE_GOLD_CHECK     (PRO_PAWN  , goldEffect  ); break;
		+  case PRO_LANCE : GEN_MOVE_GOLD_CHECK     (PRO_LANCE , goldEffect  ); break;
		+  case PRO_KNIGHT: GEN_MOVE_GOLD_CHECK     (PRO_KNIGHT, goldEffect  ); break;
		+  case PRO_SILVER: GEN_MOVE_GOLD_CHECK     (PRO_SILVER, goldEffect  ); break;
		  case GOLD      : GEN_MOVE_GOLD_CHECK     (GOLD      , goldEffect  ); break;


		pseudo_legal()で落ちたときのデバッグ用のコード

            for (auto m2 : pv)
              cout << m2 << " ";
            cout << endl;

            if (!pos.pseudo_legal(m) || !pos.legal(m))
            {
              auto mg = MoveList<NON_EVASIONS>(pos);
              for (auto move : mg)
              {
                cout << move << " : " << Piece(move >> 16) << " : " ;
                if (!pos.pseudo_legal(move))
                  cout << "not pseudo_legal →　" << move;
                cout << endl;
              }

              cout << endl;
            }

			  if (!pos.pseudo_legal(move))
			  {
				cout << pos << move;
			  }

				秒読み300[ms]

				61.3%	
				#255
				やねうら王2016mid V323f gcc
				genmove修正。
				#254
				やねうら王2016mid V323e gcc
				戻した。

				111-1-70(0.1% R80.1)	

			ひどいバグであった模様。
			短い時間だと相対的にqsearch()の割合が高いために影響がもろに出るようだ。


			秒読み3000[ms]

			47.3%	
			#255
			やねうら王2016mid V323f gcc
			genmove修正。
			#0
			silent_majority_V1.1公式
			1スレッド

			214-13-238(88.0% R-18.5)	

		回数が少ないので何とも。たぶん互角ぐらい。
		10秒で魔女と丸1日回しておく。


			秒読み15000[ms]

			45.3%	
			#255
			やねうら王2016mid V323f gcc
			genmove修正。
			#0
			silent_majority_V1.1公式
			1スレッド

			505-63-611(99.9% R-33.1)	

	まだR33も離れているのか。evaluate()、AVX2化するわ。それでチャラだ。

] V3.22

・futilityとrazoringのパラメーター、元に戻してみる。

		秒読み3000[ms]

		49.7%	
		#246
		やねうら王2016mid V322a
		futilityとrazoringパラメーター戻した
		#0
		silent_majority_V1.1公式
		1スレッド

		357-24-361(57.4% R-1.9)	

	ほぼ互角。

	V3.22b
	LONG_EFFECT_LIBRARY利用でどれくらいの勝率になるのか。
	→　nps5%程度ダウン＋1手詰め発見率5%程度ダウンのコンボなので
	強くなるはずがないが…。1手詰めを3手詰めに変更するなら意味があるかも。
	
	long_effect.cpp、g++でbuild通らない。修正。

		long effect有効、gcc
		===========================
		Total time (ms) : 63803
		Nodes searched  : 42028435
		Nodes/second    : 658721

	そこまで遅くはない印象。

		秒読み3000[ms]

		45.6%	
		#247
		やねうら王2016mid V322b
		利き利用
		#0
		silent_majority_V1.1公式
		1スレッド

		169-12-202(96.1% R-31.0)	

	mate1()の発見率が5%落ちることと、nps 5%ダウン。結構勝率に影響するんだな…。
	同種ソフト対決なのも影響してるのかも知れないが。


		秒読み15000[ms]

		45.3%	
		#246
		やねうら王2016mid V322a
		futilityとrazoringパラメーター戻した
		#0
		silent_majority_V1.1公式
		1スレッド

		377-49-456(99.7% R-33.0)	

	まだ何らか負けているようだ。


	moved_piece_after()やめて、移動させる駒になっていてもどうせ歩のpromoteは除外されるので
	あまり変わらないのかも。桂を成る場合と成らない場合とが同一視されるのがちょっと嫌だな。
	やはり、魔女のこの部分の実装は良いとは思えないのだが…。


] V3.21

	V3.21a
・history、整理

		秒読み300[ms]

		51.8%	
		#242
		やねうら王2016mid V321a
		history整理
		#241
		やねうら王2016mid V321
		新基準

		298-6-277(17.9% R12.7)	


		秒読み10000[ms]

		50.0%	
		#243
		やねうら王2016mid V321b
		history整理
		#0
		silent_majority_V1.1公式
		1スレッド

		79-9-79(53.2% R0.0)	

		魔女と互角ぐらい？


移動させる駒にしたものと比較

	V3.21b

			#define USE_DROPBIT_IN_STATS
			#define KEEP_PIECE_IN_GENERATE_MOVES

		これ、USE_DROPBIT_IN_STATSをundefするとすごく弱くなる。(-R170ぐらい)
		何か修正忘れているのだと思う。この弱くなる原因をよく調べたほうがいい。

			  // Moveの上位16bitのvaridation
		#if 1
			  if (is_drop(move))
			  {
				if (move_dropped_piece(move) + Piece(pos.side_to_move()==BLACK ? 0 : PIECE_WHITE) + PIECE_DROP  != Piece(move >> 16))
				{
				  cout << pos << move << ":" << move_dropped_piece(move);

				}
			  } else if (!is_promote(move)) {
				if (pos.moved_piece_after_ex(move) != pos.piece_on(move_from(move)))
				{
				  cout << pos << move;
				}
			  } else {
				if (pos.moved_piece_after_ex(move) != pos.piece_on(move_from(move)) + PIECE_PROMOTE)
				{
				  cout << pos << move;
				}
			  }
		#endif


		→　わかった。move16_to_move()で復元するときに+32してしまっていた。これで範囲外の配列壊していたのか。

		  // moved_piece_before()の移動後の駒が返る版。
		  // KEEP_PIECE_IN_GENERATE_MOVESのときは単にmoveの上位16bitを返す。
		  Piece moved_piece_after(Move m) const {
		#ifdef    KEEP_PIECE_IN_GENERATE_MOVES
			// 上位16bitにそのまま格納されているはず。
		//    return Piece((m >> 16) & ~32); // DROP BITを飛ばす
			return Piece(m >> 16);
		#else
			return is_drop(m)
			  ? (move_dropped_piece(m) + (sideToMove == WHITE ? PIECE_WHITE : NO_PIECE))
			  : is_promote(m) ? Piece(piece_on(move_from(m)) + PIECE_PROMOTE) : piece_on(move_from(m));
		#endif
		  }

		  moved_piece_after_ex()これ、要らないな。消そう。

		  pseudo_legal_s()でdropのとき+32してた。これか。

			rtime 100[ms]

			49.1%	
			#243
			やねうら王2016mid V321b
			history整理
			#242
			やねうら王2016mid V321a
			DROPBITなし

			279-6-289(67.8% R-6.1)	

	互角ぐらいになった。短い時間だとhistoryが小さくなるとCPU cacheの効率が良くなるからか？
	1000回ぐらいまわしてから判断しよう。

			rtime 1000[ms]

			50.2%	
			#242
			やねうら王2016mid V321a
			DROPBITなし
			#243
			やねうら王2016mid V321b
			history整理

			1084-47-1074(41.5% R1.6)	

	DROPBIT、やはりなくてもいいぐらいだな…。なしにする。

		秒読み10000[ms]

		47.6%	
		#244
		やねうら王2016mid V321a
		Dropなし、gcc
		#0
		silent_majority_V1.1公式
		1スレッド

		175-21-193(83.9% R-17.0)	

	まだわずかに負けているようだ。この原因をよく調べる。


■　2016/06/25

] V3.20

・PVの出力の抑制機能追加。(出力が詰まるため)

・新SEE周り、見直す。

		秒読み3000[ms]

		37.0%	
		#236
		やねうら王2016mid V320a
		新see()
		#235
		やねうら王2016mid V320
		新基準

		91-4-155(100.0% R-92.5)	

	新seeひどすぎ。

	旧see()、少し簡略化できた。

	新see()
	-		Bitboard occupied = pieces();
	+		Bitboard occupied;
	この初期化必要だった。


		秒読み500[ms]

		49.8%	
		#236
		やねうら王2016mid V320a
		新see()
		#235
		やねうら王2016mid V320
		新基準

		141-8-142(54.7% R-1.2)	


		秒読み3000[ms]

		57.5%	
		#236
		やねうら王2016mid V320a
		新see()
		#235
		やねうら王2016mid V320
		新基準

		61-2-45(4.9% R52.8)	

	→　新しいほうのsee()のほうがかなり優秀っぽい。前のsee()とは何だったのだ…。
	前のsee()バグっている可能性が微レ存。

	もう少し長い時間で実験してみる。

		秒読み5000[ms]

		51.3%	
		#236
		やねうら王2016mid V320a
		新see()
		#235
		やねうら王2016mid V320
		新基準

		471-23-448(21.4% R8.7)	

		強くはなっていそう。


	V3.20b

	    attackers = (stmAttackers | attackers_to(~stm, to, occupied)) & occupied;

	この & occupied、不要のはずなのだがこれを無くすとbenchの探索node数が変わる。おかしい。
	よく調べる。

		===========================
		Total time (ms) : 58766
		Nodes searched  : 34588434
		Nodes/second    : 588579

		gcc
		===========================
		Total time (ms) : 53064
		Nodes searched  : 34588434
		Nodes/second    : 651824

	→　理由わかった。KINGをcaptureしたときに、stmAttackersが有ることになってしまうから
	attackers & occupiedみたいな処理が必要になるのか。minAttackersでKINGを返すときに & occupied して返すべきなのか。
	(Aperyはそうなっている)	Stockfishのコードと等価にするにはいまのコードが正しいな。そうか…。

	Aperyのコードがわずかに無駄があるということなんだな。平岡さんに報告しよう。
	https://github.com/HiraokaTakuya/apery/issues/6

	see_sign()、いい加減にするのやめておいたほうがいいのでは…。

	#if 0
	  if (capture(move))
	  {
		// 捕獲する指し手で、移動元の駒の価値のほうが移動先の駒の価値より低い場合、これでプラスになるはず。
		// (取り返されたあとの成りを考慮しなければ)
		const Piece ptFrom = type_of(piece_on(move_from(move)));
		const Piece ptTo = type_of(piece_on(move_to(move)));
		if (CapturePieceValue[ptFrom] <= CapturePieceValue[ptTo])
		  return static_cast<Value>(1);
	  }
	#endif

		秒読み1000[ms]

		47.2%	
		#237
		やねうら王2016mid V320b
		新see()改良
		#236
		やねうら王2016mid V320a
		新see()

		258-6-289(91.4% R-19.7)	

	よくなってない。もう少し長い時間で回してみる。

		秒読み4000[ms]

		49.2%	
		#237
		やねうら王2016mid V320b
		新see()改良
		#236
		やねうら王2016mid V320a
		新see()

		127-11-131(62.2% R-5.4)	

	変わらず。Stockfishでもこの判定になっているから、ここ変えても変わらないのかも知れない。

	see_sign()の判定、kingでcaptureするときは常にプラスを返して良いのでは…。うーん..

    // KINGで取る手は合法手であるなら取り返されないということだから、ここではプラスを返して良い。
    // ゆえに、中盤用のCapturePieceValue[KING]はゼロを返して良いのでは。

	-   if (CapturePieceValue[ptFrom] <= CapturePieceValue[ptTo])
	+   if (CapturePieceValue[ptFrom] <= CapturePieceValue[ptTo] || ptFrom == KING)

	こうするか。

			秒読み300[ms]

			51.6%	
			#238
			やねうら王2016mid V320c
			新see()改良
			#236
			やねうら王2016mid V320a
			新see()

			489-11-458(14.9% R11.4)	

	勝率が上がったが、この実装おかしいなぁ…。

	CapturePieceValue、やはりKINGはゼロにするのが正しいのでは。

		// KINGの場合、プラスが返るが、その場合、moveは非合法手であるから、そのあと引っかかるはずなので
		// この判定、入れなくてもいいかも。
		//if (captured == KING)
		//  return Value(-CapturePieceValue[KING]);


		秒読み300[ms]

		51.3%	
		#239
		やねうら王2016mid V320d
		CapturePieceValue[KING]=0
		#238
		やねうら王2016mid V320c
		新see()改良

		401-11-381(22.6% R8.9)	

	弱くはなってなさそうなのでおk。

	gccでコンパイルして1手5秒で魔女と対戦させておく。

		秒読み5000[ms]

		50.0%	
		#240
		やねうら王2016mid V320d gcc
		CapturePieceValue[KING]=0
		#0
		silent_majority_V1.1公式
		1スレッド

		112-12-112(52.7% R0.0)	

	ほぼ互角っぽい。

		gcc PGO
		===========================
		Total time (ms) : 48621
		Nodes searched  : 32357232
		Nodes/second    : 665499

	1,2%速くなった程度？

	魔女と10秒でテスト。

		秒読み10000[ms]

		45.5%	
		#240
		やねうら王2016mid V320d gcc
		CapturePieceValue[KING]=0
		#0
		silent_majority_V1.1公式
		1スレッド

		438-52-525(99.8% R-31.5)	

	まだ少し負けているのか。

・ASSERT外して何故速くならないのか調べる。
	→　assert()、探索の時間のかかるところにはあまり入ってないからかな。
・プロファイラで調べる。
	
	Eval::calc_diff_kpp             40.29%
	Position::attackers_to          10.82%
	TranspositionTable::probe       10.81%
	is_mate_in_1ply                  3.79%
	MovePicker::generate_next_stage  2.69%

	なにこれ。
	評価関数40%でかすぎ。
	probe時間かかりすぎ。
	attackers_toも重すぎ。

	attackers_to、template<Color us>とかに分けるとか..。

	NullMoveのときにprefetchしたほうがいいのでは。
	misc.cppにprefetch追加。
	TTのfirst_entry()追加。
	→　どちらが速いかほぼ計測不能。

	利きを使わないmate1ply()はテーブル使ってもう少し速く出来るはず＆mate3にすれば
	もうちょっと強くなるはず。


■　2016/06/24

] V3.19

	gccでコンパイル
	===========================
	Total time (ms) : 48419
	Nodes searched  : 34145554
	Nodes/second    : 705209

	めっちゃ速くなった。AVX用のinclude header整理したのが良かったのか…？
	evaluate()でcompute_evalのときにSSE使えてなかったとか？	うーん。それが原因ではなさげなのだが。

	VC++2015
	===========================
	Total time (ms) : 52424
	Nodes searched  : 34145554
	Nodes/second    : 651334



■　2016/06/23

] V3.18

・mate間違う局面を見つけた。

	position startpos moves 7g7f 3c3d 6g6f 8c8d 7i6h 7a6b 5g5f 5c5d 3i4h 3a4b 4i5h 4a3b 5h6g 5a4a 6i7h 7c7d 6h7g 6b5c 2g2f 5d5e 5f5e 2b5e 2f2e 5c5d 5i6i 4b3c 4h5g 8b5b 6f6e 5d6e 5g6f 6e6f 7g6f 5e8b P*5e 4a3a S*8c 8b7a 8c7d+ 6a7b 6i7i 3a2b 8h7g 7b7c 7d7c 8a7c 7g6h 7c8e 8g8f P*7g 8i7g 8e7g+ 6h7g 7a3e G*4f 3e7a N*4e 3c4d 5e5d 5b5d 6f5e 5d7d 5e4d 4c4d S*6e 7d7b P*6b 7a6b 6e5d P*7e P*5c S*4c 5d4c 3b4c S*6a 7b7a 6a5b 4c5d 5b6c 7e7f 6g7f 7a7f 6c5d+ N*6f 2e2d 2c2d 7g6f 7f6f 5d4d B*5g P*6h P*6g 2h2d P*2c G*3c 2b3a N*4c 3a4a 3c3b 4a3b 2d3d

	静止探索絡みだな、これ。
	evasionですべての指し手を生成していない可能性とかも…。

	setoption name Threads value 1
	position startpos moves 7g7f 3c3d 6g6f 8c8d 7i6h 7a6b 5g5f 5c5d 3i4h 3a4b 4i5h 4a3b 5h6g 5a4a 6i7h 7c7d 6h7g 6b5c 2g2f 5d5e 5f5e 2b5e 2f2e 5c5d 5i6i 4b3c 4h5g 8b5b 6f6e 5d6e 5g6f 6e6f 7g6f 5e8b P*5e 4a3a S*8c 8b7a 8c7d+ 6a7b 6i7i 3a2b 8h7g 7b7c 7d7c 8a7c 7g6h 7c8e 8g8f P*7g 8i7g 8e7g+ 6h7g 7a3e G*4f 3e7a N*4e 3c4d 5e5d 5b5d 6f5e 5d7d 5e4d 4c4d S*6e 7d7b P*6b 7a6b 6e5d P*7e P*5c S*4c 5d4c 3b4c S*6a 7b7a 6a5b 4c5d 5b6c 7e7f 6g7f 7a7f 6c5d+ N*6f 2e2d 2c2d 7g6f 7f6f 5d4d B*5g P*6h P*6g 2h2d P*2c G*3c 2b3a N*4c 3a4a 3c3b 4a3b 2d3d
	go infinite

	利きを使わない1手詰め判定、バグがあった。とほほ。

	敵の合駒が歩以外にないという条件を間違えて自駒が歩以外ないという条件になっていた。とほほ。
	-  if (hand_count(ourHand , PAWN) == (int)ourHand)

		秒読み300[ms]

		48.4%	
		#231
		やねうら王2016mid V318
		mate1ply()バグ修正。
		#228
		やねうら王2016mid V317
		基準。

		266-7-284(79.1% R-11.4)	

	バグ取ったのに弱くなった気がする。
	razor margin変えたのとcheck_info_update()のタイミングが早くなったからか…。つらい..。

		秒読み300[ms]

		51.2%	
		#231
		やねうら王2016mid V318
		mate1ply()バグ修正。
		#228
		やねうら王2016mid V317
		基準。

		262-4-250(28.3% R8.1)	

	まあいいや、ほぼ互角ということで。

	V3.18a
	mate1ply()、ランダムプレイヤーでテストする。

	歩の移動による不成の王手による詰み、間違えてた。
		-    to = sq_king + (us == BLACK ? SQ_U : SQ_D);
		+    to = sq_king + (us == BLACK ? SQ_D : SQ_U);

	歩の移動による成りの王手による詰み、間違えてた。

		mate found = 10000 , mate miss = 89 , mate found rate  = 99.1179%
		mate found = 20000 , mate miss = 154 , mate found rate  = 99.2359%
		mate found = 30000 , mate miss = 235 , mate found rate  = 99.2228%
		mate found = 40000 , mate miss = 322 , mate found rate  = 99.2014%
		mate found = 50000 , mate miss = 438 , mate found rate  = 99.1316%
		mate found = 60000 , mate miss = 536 , mate found rate  = 99.1146%
		mate found = 70000 , mate miss = 632 , mate found rate  = 99.1052%
		mate found = 80000 , mate miss = 746 , mate found rate  = 99.0761%
		mate found = 90000 , mate miss = 854 , mate found rate  = 99.06%
		mate found = 100000 , mate miss = 940 , mate found rate  = 99.0688%

	いっぱい引っかかってワロタ。
	mate foundは99%付近か。利きによる詰みmate1ply()は93%ちょいだったのでかなりいいみたい…。

	こんな重大なバグ修正したのに0.3秒では差がほとんどつかない…。不思議なものだ。

		秒読み300[ms]

		50.5%	
		#232
		やねうら王2016mid V318a
		mate1ply()バグ修正。
		#230
		やねうら王2016mid V317b
		razoring改善。

		196-2-192(40.0% R3.6)	


		秒読み3000[ms]

		53.8%	
		#232
		やねうら王2016mid V318a
		mate1ply()バグ修正。
		#230
		やねうら王2016mid V317b
		razoring改善。

		98-5-84(13.3% R26.8)	
	
	長い時間になるにつれて、探索node数が増えるのでmate1ply()で間違う局面が増えるから、
	それによる負けが増える…はず。つまり長い時間においてはこれが差がつく一因であった…はず。


■　2016/06/22

] V3.17

・razoring margin 0.1秒で12時間ほどチューンして、そのあと秒数を広げながらチューンしなおして、
　最終的に強くなったかどうかを長い持ち時間で検証する。

	V3.17a

	・王手延長の単純化	
		-          || ( !moveCountPruning && pos.see_sign(move) >= VALUE_ZERO)))
		+          ||  pos.see_sign(move) >= VALUE_ZERO)))

	・IIDのとき、常にcut nodeにするのではなく、そのnodeのcutNodeを伝播させる
		-  search<NT>(pos, ss, alpha, beta, d, true);
		+  search<NT>(pos, ss, alpha, beta, d, cutNode);

			秒読み1000[ms]

			50.3%	
			#229
			やねうら王2016mid V317a
			simplify check extension
			#228
			やねうら王2016mid V317
			基準。

			332-13-328(42.3% R2.1)	

		ほぼ変わらない。簡単に計測できる量ではない。

	V3.17b
	PARAM_RAZORING_MARGIN4 : 570 → 586(53.33%) : ←←(値554,勝率49.96%,1872局,有意51.14%) ,←(値562,勝率49.35%,1872局,有意67.61%) ,→(値578,勝率50.77%,1872局,有意29.44%) ,→→(値586,勝率53.33%,1872局,有意0.97%) ,
	PARAM_RAZORING_MARGIN3 : 619 → 619(50.00%) : ←←(値603,勝率49.84%,1872局,有意54.54%) ,←(値611,勝率49.15%,1872局,有意72.51%) ,→(値627,勝率49.63%,1872局,有意60.14%) ,→→(値635,勝率49.23%,1872局,有意70.56%) ,
	PARAM_RAZORING_MARGIN2 : 578 → 578(50.00%) : ←←(値562,勝率49.39%,1872局,有意66.52%) ,←(値570,勝率50.65%,1872局,有意32.43%) ,→(値586,勝率49.76%,1872局,有意56.78%) ,→→(値594,勝率50.20%,1872局,有意44.35%) ,
	PARAM_RAZORING_MARGIN1 : 483 → 483(50.00%) : ←←(値467,勝率48.48%,3744局,有意90.41%) ,←(値475,勝率47.33%,1872局,有意96.98%) ,→(値491,勝率49.39%,1872局,有意66.54%) ,→→(値499,勝率50.61%,1872局,有意33.45%) ,

			秒読み1000[ms]

			51.4%	
			#230
			やねうら王2016mid V317b
			razoring改善。
			#228
			やねうら王2016mid V317
			基準。

			323-10-306(23.6% R9.4)	
	
	弱くはなっていなさそうなので良しとする。


] V3.16

	PARAM_RAZORING_MARGIN4 : 554 → 570(53.16%) : ←←(値538,勝率50.97%,1872局,有意24.74%) ,←(値546,勝率50.20%,1872局,有意44.35%) ,→(値562,勝率51.41%,3744局,有意11.27%) ,→→(値570,勝率53.16%,1872局,有意1.36%) ,
	PARAM_RAZORING_MARGIN3 : 603 → 619(52.31%) : ←←(値587,勝率49.16%,3744局,有意76.42%) ,←(値595,勝率49.56%,1872局,有意62.28%) ,→(値611,勝率50.08%,1872局,有意47.72%) ,→→(値619,勝率52.31%,3744局,有意2.39%) ,
	PARAM_RAZORING_MARGIN2 : 570 → 578(51.59%) : ←←(値554,勝率49.84%,1872局,有意54.53%) ,←(値562,勝率49.19%,3744局,有意75.71%) ,→(値578,勝率51.59%,3744局,有意8.56%) ,→→(値586,勝率44.50%,624局,有意99.73%) ,
	PARAM_RAZORING_MARGIN1 : 483 → 483(50.00%) : ←←(値467,勝率49.84%,1872局,有意54.54%) ,←(値475,勝率50.24%,1872局,有意43.21%) ,→(値491,勝率50.73%,1872局,有意30.43%) ,→→(値499,勝率50.65%,1872局,有意32.44%) ,

	assert外しても速くならないな…。
	VS2015、assertのマクロ、除去出来ていない可能性が..

		秒読み3000[ms]

		54.3%	
		#228
		やねうら王2016mid V315gcc
		gccによるコンパイル
		#0
		silent_majority_V1.1公式
		1スレッド

		107-5-90(10.0% R30.1)	

	静止探索のcheck_info_update()、元の位置に戻してなかった。

		秒読み10000[ms]

		44.8%	
		#228
		やねうら王2016mid V315gcc
		gccによるコンパイル
		#0
		silent_majority_V1.1公式
		1スレッド

		125-11-154(96.4% R-36.2)	

	差は縮まってきた。npsさえ出れば魔女には勝っているのでは。
	20秒でもテストしておく。

		秒読み20000[ms]

		50.5%	
		#228
		やねうら王2016mid V315gcc
		gccによるコンパイル
		#0
		silent_majority_V1.1公式
		1スレッド

		49-4-48(42.0% R3.6)	

	ほぼ互角のようだ。よしよし。

	gcc用、コンパイルしなおした。

		秒読み3000[ms]

		52.4%	
		#228
		やねうら王2016mid V315gcc
		gccによるコンパイル
		#0
		silent_majority_V1.1公式
		1スレッド

		55-1-50(27.9% R16.6)	

	利きを求める部分以外はSSEなしでもなんとかなるかも知れないので、
	SSE2オプションを用意して準備をしていく。
	よく考えたらSSE4と4.1って別なのか。そうか…。
	SSE4用のオプションも用意する。
	これでSSE2用のバイナリがSSE2で動くかも。
	あとSSEなしでも動くかも。

	AperyのBitboardのoperator==()の実装、良くないのでGitHubで報告しておいた。

	EvalSumのnoSSE実装用意してなかった。用意する。
	というかUSE_AVX2でAVX2のコンストラクタ実装使っていなかった。
	
	EvalSum、eval/に移動。kppt_evalsumとリネーム

		VC++2015
		===========================
		Total time (ms) : 115619
		Nodes searched  : 72105321
		Nodes/second    : 623645

		gcc
		===========================
		Total time (ms) : 110433
		Nodes searched  : 72105321
		Nodes/second    : 652932

	やねうら王2016Mid、SSE42、SSE4、SSE2、noSSE用のバイナリも用意。

	ToDoより
	・ASSERT外してgccでビルドして2016 Midをリリース。
	→　した。
	・SSE2用バイナリを用意する。
	→　実験環境＆デバッグ環境がなくてよくわからない。
	→　とりあえずした。


■　2016/06/21

] V3.15

gcc 対応。__popcnt →　mm_popcnt_u64を使うと良いらしい。
	#include <nmmintrin.h>
	#define POPCNT32(a) _mm_popcnt_u64(a)
	#define POPCNT64(a) _mm_popcnt_u64(a)

		gcc
		===========================
		Total time (ms) : 128211
		Nodes searched  : 80011406
		Nodes/second    : 624060

		VC2015
		===========================
		Total time (ms) : 128684
		Nodes searched  : 80011406
		Nodes/second    : 621766

		何も変わってなかった。あれれ…。そして速くなっているな。
		FORCE_INLINEをつけた影響で少し速くなったのか？はてはて。

		BitboardのpopまわりにFORCE_INLINE追加した。
		movegen.cppにもFORCE_INLINE追加した。→　コンパイルがめっちゃ遅くなった。
		→　少し減らした。

		VC2015
		===========================
		Total time (ms) : 131980
		Nodes searched  : 80011406
		Nodes/second    : 606238

		gcc
		===========================
		Total time (ms) : 126935
		Nodes searched  : 80011406
		Nodes/second    : 630333

		gcc 仮想環境の外。4771
		===========================
		Total time (ms) : 122866
		Nodes searched  : 80011406
		Nodes/second    : 651208

		VC2015 仮想環境の外。4771
		===========================
		Total time (ms) : 125457
		Nodes searched  : 80011406
		Nodes/second    : 637759

		ASSERT外して、gccでコンパイルするか。
		gcc、もう少し速くなるかと思ったのだが…。


] V3.14

	1手0.5秒～3秒で簡単に調整できそうなパラメーターだけ自動調整してみる。
	調整したくないパラメーターはinterval = 9999に設定。

	まずはrazoring marginから。
	0.5秒で大雑把に調整して、そのあと秒数を増やしてみる。


		秒読み100[ms]

		50.4%	
		#227
		やねうら王2016mid V314slave
		slave。1スレッド
		#226
		やねうら王2016mid V314master
		master。1スレッド

		15558-418-15301(7.2% R2.9)	

	停止条件おかしくて止まってなかった。禿げる。



] V3.13

		秒読み400[ms]

		53.8%	
		#224
		やねうら王2016mid V313
		新基準。1スレッド
		#210
		やねうら王2016mid V311
		新基準。1スレッド

		441-6-378(1.3% R26.8)	


	V3.13a
	search()でのevaluate()の呼び出しタイミング、やはり少し遅くしたほうが良いのでは..

		秒読み400[ms]

		48.8%	
		#225
		やねうら王2016mid V313a
		evaluate()遅延。1スレッド
		#224
		やねうら王2016mid V313
		新基準。1スレッド

		186-4-195(69.6% R-8.2)	

	計測不能な差のようなのでこれはいいや。



■　2016/06/20

] V3.12

	V3.12a
	 このkillerの設定、コメントアウトしたほうがいいかも。
	  {
        // IID、singular extension時であっても
        // killerがないときはkillerぐらいは登録したほうが少しだけ得。

        if (ss->killers[0] == MOVE_NONE)
          ss->killers[0] = move;
        else if (ss->killers[1] == MOVE_NONE)
          ss->killers[1] = move;
      }

		秒読み100[ms]

		54.7%	
		#222
		やねうら王2016mid V312a
		IID killerなし。1スレッド
		#221
		やねうら王2016mid V312
		新基準。1スレッド

		248-4-205(1.9% R33.1)	


		秒読み1000[ms]

		52.0%	
		#222
		やねうら王2016mid V312a
		IID killerなし。1スレッド
		#221
		やねうら王2016mid V312
		新基準。1スレッド

		640-27-591(8.1% R13.8)	

	IIDのkiller設定、よくないことがわかった。ばっさり消す。

	V3.12b
	・qsearch()を直接呼び出せるようにした。(学習で用いるので)
	書きかけ。まだ正しく動作しない。

	V3.12c
	ehashあり
		===========================
		Total time (ms) : 141850
		Nodes searched  : 80011406
		Nodes/second    : 564056

	ehashなし
		===========================
		Total time (ms) : 134267
		Nodes searched  : 80011406
		Nodes/second    : 595912

	なしのほうが速いっぽい。これは禿げる..。

	V3.12d
		if (!captureOrPawnPromotion && move != bestMove && quietCount < 64 - 4 + param1 * 4)
		param1 = 0..2
		10秒で魔女と回しておく。


		秒読み10000[ms]

		41.7%	38.6%	43.3%	
		#223
		やねうら王2016mid V312d
		quiet countテスト。1スレッド
		#0
		silent_majority_V1.1公式
		1スレッド

		123-17-172(99.8% R-58.2)	86-11-137(100.0% R-80.9)	97-10-127(98.1% R-46.8)	

		もう少しやらないと何とも…。


] V3.11

      // 評価関数を呼び出したので置換表のエントリーはなかったことだし、何はともあれそれを保存しておく。
+      // tte->save(posKey, VALUE_NONE, BOUND_NONE, DEPTH_NONE, MOVE_NONE, ss->staticEval, TT.generation());
+      // →　どうせ毎node評価関数を呼び出すので、evalの値にそんなに価値はないからこれをやめる。


	Core i7 4771k
	===========================
	Total time (ms) : 150870
	Nodes searched  : 92242005
	Nodes/second    : 611400


		秒読み1000[ms]

		59.5%	
		#210
		やねうら王2016mid V311
		新基準。1スレッド
		#0
		silent_majority_V1.1公式
		1スレッド

		94-5-64(0.7% R66.8)	


		秒読み3000[ms]

		41.4%	
		#210
		やねうら王2016mid V311
		新基準。1スレッド
		#0
		silent_majority_V1.1公式
		1スレッド

		96-10-136(99.7% R-60.5)	


	V3.11a
	historyでdropの+32をやめると？

		-      pc = Piece(pos.piece_on(sq) + (is_drop(move) ? 32 : 0));     \
		+      pc = Piece(pos.piece_on(sq) );     \

  Piece moved_piece_after_ex(Move m) const {
    return is_drop(m)
-      ? Piece(move_dropped_piece(m) + (sideToMove == WHITE ? PIECE_WHITE : NO_PIECE) + 32)
+      ? Piece(move_dropped_piece(m) + (sideToMove == WHITE ? PIECE_WHITE : NO_PIECE) /*+ 32*/)
      : is_promote(m) ? Piece(piece_on(move_from(m)) + PIECE_PROMOTE) : piece_on(move_from(m));
  }

-        Piece prevPc = pos.piece_on(prevSq) + Piece(is_drop((ss - 1)->currentMove) ? 32 : 0);
+       Piece prevPc = pos.piece_on(prevSq);


  これで互角なら、この処理なくしたい。
  Moveに移動させる駒が入っていれば、親nodeの移動させる駒が得られて、移動前の駒種でhistoryが
  引けて便利なのかも知れない。(cf. Apery)
  そこで強さに差が出ないなら、そのほうがシンプル。

		秒読み1000[ms]

		48.6%	
		#211
		やねうら王2016mid V311a
		history駒打ち削除。1スレッド
		#210
		やねうら王2016mid V311
		新基準。1スレッド

		297-13-314(76.7% R-9.7)	

	誤差ぐらい。ここでわずかに良くとも、CPU cache汚染とかの問題があるので
	誤差ぐらいしか変わらないなら採用したくないのだが…。

		秒読み3000[ms]

		49.7%	
		#211
		やねうら王2016mid V311a
		history駒打ち削除。1スレッド
		#210
		やねうら王2016mid V311
		新基準。1スレッド

		292-17-295(56.6% R-1.8)	

	ほぼ誤差だな。これは削除すべきか。そうか。

		  // 直前のnodeの指し手で動かした駒(移動後の駒)とその移動先の升を返す。
		  // この実装においてmoved_piece()は使えない。これは現在のPosition::side_to_move()の駒が返るからである。
		  // 駒打ちのときは、駒打ちの駒(+32した駒)が返る。
		#define sq_pc_from_move(sq,pc,move)                                \
			{                                                              \
			  sq = move_to(move);                                          \
			  pc = Piece(pos.piece_on(sq);     \
			}

	V3.11b
	ソースコード整理して、やねうら王2016 MidではUSE_DROPBIT_IN_STATSを使わないようにした。
	以前のバージョンより弱くなっていないかをテスト。

	history、移動前の駒で評価しても棋力変わらないのかも。
	指し手生成のときにmoveの上位bitを移動後の駒にするのは難しくはないのだが。
	というか、成りはquietではないのでhistoryからそもそも除外されているのか？
	除外は歩の成りだけか。うーん。角とか飛車の成り、本当に除外していいのか？
	価値上昇値が、歩の成りよりは低いか。	

		秒読み3000[ms]

		42.5%	
		#212
		やねうら王2016mid V311b
		history駒打ち削除。1スレッド
		#210
		やねうら王2016mid V311
		新基準。1スレッド

		110-3-149(99.4% R-52.7)	

	あれ？めっちゃ弱くなった。どうなってんの…。

      // 評価関数を呼び出したので置換表のエントリーはなかったことだし、何はともあれそれを保存しておく。
      // tte->save(posKey, VALUE_NONE, BOUND_NONE, DEPTH_NONE, MOVE_NONE, ss->staticEval, TT.generation());
      // →　どうせ毎node評価関数を呼び出すので、evalの値にそんなに価値はないからこれをやめる。

	この省略が得していない？
	ああ、mate1ply()、置換表にhitしたときに省略されるのか。その差だな。
	修正して、再テスト。

		秒読み3000[ms]

		45.5%	
		#212
		やねうら王2016mid V311b
		history駒打ち削除。1スレッド
		#210
		やねうら王2016mid V311
		新基準。1スレッド

		222-21-266(97.9% R-31.4)	

	やはり悪いのか…。そうなのか…。
	これは戻さざるをえない。

	V3.11c元に戻して0.3秒テスト。
	間違えてた。

		#ifndef USE_DROPBIT_IN_STATS   
			  pos.piece_on(prevSq);
		#else
			  pos.piece_on(prevSq) + Piece(is_drop((ss-1)->currentMove) ? 32 : 0);
		#endif

	こうだった。
	→　これで3.11と互角に戻った。再実験。

	V3.11d
		秒読み300[ms]

		48.3%	
		#214
		やねうら王2016mid V311d
		historyから駒打ち削除。1スレッド
		#210
		やねうら王2016mid V311
		新基準。1スレッド

		703-21-752(90.1% R-11.7)	
	
	短い時間ではCPU cacheの汚染が少ないので勝ち越さなければならないのに
	勝っていないので、これは本当にダメそう。

	V3.11e
	MovePicker、killerの数に応じて、QUIET0,1,2,3とか分岐してはダメか？そこそこ意味があるような？
	Killer、Move32で持つの誤りだった。ExtMoveで持つべきだった。

		===========================
		Total time (ms) : 129748
		Nodes searched  : 74446076
		Nodes/second    : 573774

	比較実験しやすいようにdefineにする。

		// QUIETSの指し手を返すときに、分岐させて、少し高速化する。
		#define FAST_QUIETS

		===========================
		Total time (ms) : 130822
		Nodes searched  : 74446076
		Nodes/second    : 569063

	何も速くなってなかった。禿げた。
	killerまわり修正されたはずなのでV3.10と比較。

		秒読み300[ms]

		53.3%	
		#215
		やねうら王2016mid V311e
		historyから駒打ち削除。1スレッド
		#210
		やねうら王2016mid V311
		新基準。1スレッド

		357-5-313(4.1% R22.8)	

		秒読み3000[ms]

		44.5%	
		#215
		やねうら王2016mid V311e
		historyから駒打ち削除。1スレッド
		#0
		silent_majority_V1.1公式
		1スレッド

		77-5-96(93.6% R-38.3)	
		あとはPGOとeval hashの差か。指し手生成で駒種格納。それからassert()消すと。


		秒読み10000[ms]

		44.7%	
		#215
		やねうら王2016mid V311e
		historyから駒打ち削除。1スレッド
		#0
		silent_majority_V1.1公式
		1スレッド

		209-28-259(99.1% R-37.3)	

		長い時間で勝率に差があったのは解消した。

	結論的には指し手生成段階で移動先での駒種 + 打ち駒なら32 をしたものを
	上位bitに格納したほうがいいのではということになった。

・moved_piece_after_exがいいどうか検討すべき。
	→　これやはり、それで正しい気がする。

	V3.11f
	aspirationのマージンを3秒で自動調整。

	        delta = Value(18 - 6 + 3 * param1);

	param1 = 0..4ぐらいで勝率を見る

		秒読み3000[ms]

		40.9%	46.8%	48.7%	47.4%	44.7%	
		#216
		やねうら王2016mid V311f
		aspiration調整。1スレッド
		#0
		silent_majority_V1.1公式
		1スレッド

		61-5-88(98.9% R-63.7)	36-1-41(75.3% R-22.6)	37-2-39(63.4% R-9.1)	36-2-40(71.7% R-18.3)	34-2-42(84.9% R-36.7)	

	V3.11g
	delta = Value(18 - 2 + 1 * param1);
	param1 = 0..4

		秒読み3000[ms]

		46.7%	48.0%	45.2%	51.3%	41.9%	
		#217
		やねうら王2016mid V311g
		aspiration調整。1スレッド
		#0
		silent_majority_V1.1公式
		1スレッド

		70-6-80(81.5% R-23.2)	72-6-78(71.6% R-13.9)	66-10-80(89.3% R-33.4)	78-4-74(34.3% R9.1)	62-4-86(98.0% R-56.8)	

	回数が少なくてよくわからない。


		// --- Counter Move

		// KEEP_PIECE_IN_COUNTER_MOVEがdefineされていたなら、
		// 移動させた駒を上位16bitに格納しておく。
		// bit24...16 = 移動させた駒(Piece。後手の駒含む)
		// bit15... 0 = 本来のMove

		#ifdef KEEP_PIECE_IN_COUNTER_MOVE
		#define COUNTER_MOVE Move32
		// 指し手の上位に駒種(移動前の駒)を格納してMove32化する。
		#define make_move32(move) ((Move32)((move) + (pos.moved_piece_after_ex(move) << 16)))
		#else
		#define COUNTER_MOVE Move 
		#endif

	このコード完全に削除して、Moveは32bit固定したほうがいいな。

		#ifndef KEEP_PIECE_IN_COUNTER_MOVE
			// しかし、Counter Moveの手は手番に関係ないので(駒種を保持していないなら)取り違える可能性があるため
			// (しかも、その可能性はそこそこ高い)、ここで合法性をチェックする必要がある。
			switch (pr)
			{
			case PAWN:
			case LANCE:
			  if ((us == BLACK && rank_of(to) == RANK_1) || (us == WHITE && rank_of(to) == RANK_9))
				return false;
			  break;
			case KNIGHT:
			  if ((us == BLACK && rank_of(to) < RANK_3) || (us == WHITE && rank_of(to) > RANK_7))
				return false;
			  break;
			}
		#else
			// 変な指し手を渡していないか、assertを入れて調べておく。(ASSERT_LV4以上のとき用)
			switch (pr)
			{
			case PAWN:
			case LANCE:
			  if ((us == BLACK && rank_of(to) == RANK_1) || (us == WHITE && rank_of(to) == RANK_9))
				ASSERT_LV4(false);
			  break;
			case KNIGHT:
			  if ((us == BLACK && rank_of(to) < RANK_3) || (us == WHITE && rank_of(to) > RANK_7))
				ASSERT_LV4(false);
			  break;
			}
		#endif

	V3.11h

	===========================
	Total time (ms) : 110191
	Nodes searched  : 62019533
	Nodes/second    : 562836

	何も速くなってない。なんなん…。

	まだいろいろ指し手生成にバグがあるようだ。
	random playerでデバッグ。

		#if 0
			  cout << pos;
			  for (auto m : mg)
			  {
				auto pc = pos.moved_piece_after_ex(m);
				cout << (Move)m << " " << pc << endl;
			  }
			  cout << endl;
		#endif

		  // ここで生成された指し手がすべて合法手であるかテストをする
		  for (auto m : mg)
		  {
			if (!pos.pseudo_legal(m))
			{
			  auto pc = pos.moved_piece_after_ex(m);
			  cout << pos << (Move)m << " " << pc;
			  pos.pseudo_legal(m);
			}

			ASSERT_LV3(pos.pseudo_legal(m));
			ASSERT_LV2(pos.legal(m));
		  }
		  →　やっとtest通った。

	===========================
	Total time (ms) : 185363
	Nodes searched  : 106442741
	Nodes/second    : 574239

	ほぼ高速化していないというのは指し手生成で余分なコストがかかった分を
	回収できていないのか。MovePickerはシンプルになったが…。

		秒読み100[ms]

		51.6%	
		#218
		やねうら王2016mid V311h
		指し手生成大改造。1スレッド
		#210
		やねうら王2016mid V311
		新基準。1スレッド

		1079-34-1013(7.5% R11.0)	

	悪くはなっていなさそうなので良し。

	V3.11i
		piece_on()使っているところを置き換え。

	      Piece prevPc = pos.moved_piece_after_ex((ss - 1)->currentMove));

			秒読み100[ms]

			52.0%	
			#219
			やねうら王2016mid V311i
			指し手生成大改造。1スレッド
			#210
			やねうら王2016mid V311
			新基準。1スレッド

			727-20-670(6.4% R14.2)	

	・clangでのコンパイル通るようにしてUbuntu×AWSで動くようにする。→　tanuki-さんにお願い中。
	→ 魔女ではgccでコンパイルするとVS2015でコンパイルするより15%ぐらい速くなる模様。
	→ gcc + PGOで1,2%ぐらい速くなる模様。VS2015のほうはちっとも..。
		gccでコンパイルしてリリースするか…。

	・classic-tceをビルドして、比較。
		classic-tceのほうがnpsが高い。
		Stockfish7でorderingがすこぶる重くなってnpsが下がったが、長い時間ではそちらのほうが良いようだ。

			秒読み100[ms]

			54.2%	
			#220
			やねうら王classic-tce V311i
			比較基準用。1スレッド
			#219
			やねうら王2016mid V311i
			指し手生成大改造。1スレッド

			230-1-194(3.6% R29.6)	


			秒読み1000[ms]

			45.4%	
			#220
			やねうら王classic-tce V311i
			比較基準用。1スレッド
			#219
			やねうら王2016mid V311i
			指し手生成大改造。1スレッド

			108-5-130(93.2% R-32.2)	



■　2016/06/18

] PGO

・PGOかける

	Visual Studio Community 2015でK-Shogiをビルドしてみた
	http://blog.studiok-i.net/shogi/1272.html

		「デバッグ」メニュー ⇒ 「XXXのプロパティ」を選択 ※XXXはプロジェクト名
		「全般」 – 「プログラム全体の最適化」に「ガイド付き最適化のプロファイル – インストルメント」を選択
		リビルドする
		「デバッグ」メニュー ⇒ 「デバッグの開始」
		適当に動かす（最適化してほしいところを集中的に動かすとよい）
		「デバッグ」メニュー ⇒ 「XXXのプロパティ」を選択
		「全般」 – 「プログラム全体の最適化」に「ガイド付き最適化のプロファイル – 最適化」を選択
		ビルドする（リビルドではない）

	PGO前
	===========================
	Total time (ms) : 126895
	Nodes searched  : 79320741
	Nodes/second    : 625089

	PGO後
	===========================
	Total time (ms) : 124923
	Nodes searched  : 79320741
	Nodes/second    : 634957

	1%ほどしか変わらない。おかしい…。仮想環境だからな..

] V3.10

	・5,10秒で魔女と対戦

	5秒→10秒で勝率が低下する。長い持ち時間になったときに勝率が低下するファクターが
	まだ何か残っているのだと思う。静止探索での一手詰めとかあのへん怪しい。
	assert復活させてPGOなしにしてもう少し実験せねば。

		秒読み5000[ms]
		38.8%	
		#192
		やねうら王2016mid V310
		利きなしsmate/qmate PGO。1スレッド
		#0
		silent_majority_V1.1公式
		1スレッド

		85-7-134(100.0% R-79.1)	


		秒読み10000[ms]
		32.9%	
		#192
		やねうら王2016mid V310
		利きなしsmate/qmate PGO。1スレッド
		#0
		silent_majority_V1.1公式
		1スレッド

		199-28-406(100.0% R-123.9)	

	利き更新なし＋1手詰めなしにしたときの10秒での勝率とほぼ変わらない。
	静止探索での1手詰めが長い持ち時間において足を引っ張っている気がする。
	しかし、静止探索のオーバーヘッドだけでそんなに勝率が変わるとは考えにくいので
	他の要因があるはず。

	5秒対戦だとnpsの差で負けている可能性とかもあって、原因がよくわからない。
	10秒対戦での勝率を見ながらチューンするしかない。

		
	短い時間では静止探索での1手詰めの効果は顕著なのだが…。

		秒読み100[ms]

		43.9%	
		#193
		やねうら王2016mid V310a
		利きなしsmate。1スレッド
		#192
		やねうら王2016mid V310
		利きなしsmate/qmate PGO。1スレッド

		723-24-923(100.0% R-42.4)	



	静止探索での1手詰めを入れないと弱くなった。
	やはり意味があるように思える。

		秒読み10000[ms]

		27.0%	
		#193
		やねうら王2016mid V310a
		利きなしsmate。1スレッド
		#0
		silent_majority_V1.1公式
		1スレッド

		31-1-84(100.0% R-173.2)	


	まさかと思うがONE_PLY = 1で試す。
	そうか。futility margin、ONE_PLYで割られていないのでONE_PLY = 2でやっていると
	半分の値でやっていることになるのか…そうか…。
	ならStockfishのfutility margin = 200は100相当なので、わりといまの値に近いのか…。


		秒読み100[ms]

		45.1%	
		#194
		やねうら王2016mid V310b
		ONE_PLY=1。1スレッド
		#192
		やねうら王2016mid V310
		利きなしsmate/qmate PGO。1スレッド

		352-13-429(99.7% R-34.4)	

	少し弱くなった。ONE_PLYの値に影響を受けている何かがあるのか…。
	PGOの差かも知れない。reduction table絡みかも知れない。

		秒読み500[ms]

		49.8%	
		#194
		やねうら王2016mid V310b
		ONE_PLY=1。1スレッド
		#192
		やねうら王2016mid V310
		利きなしsmate/qmate PGO。1スレッド

		138-1-139(54.8% R-1.3)	

	500[ms]だとほぼ変わらずっぽいのでONE_PLY=1のままちょっといろいろいじる。

	V3.10c
	reduction量を変えてみる。

		  for (int imp = 0; imp <= 1; ++imp)
			for (int d = 1; d < 64; ++d)
			  for (int mc = 1; mc < 64; ++mc)
			  {
				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);

				if (!imp && reduction_table[NonPV][imp][d][mc] >= 2 * ONE_PLY)
				  reduction_table[NonPV][imp][d][mc] += ONE_PLY;
			  }

	ONE_PLY = 1と2の差は関係なくて、reductionテーブルは後者のほうが理想に近いのが、
	長時間において差が出る要因なのだろう…。ONE_PLY = 2のほうが各種パラメーターを
	調整しやすいので良いはずなのだが、現状、そこまで細かく調整する価値のあるパラメーターが
	なくて、ONE_PLYで割るコストのほうが高くついているのかも知れない。

		秒読み500[ms]

		49.1%	
		#195
		やねうら王2016mid V310c
		ONE_PLY=1,reduction変更。1スレッド
		#193
		やねうら王2016mid V310a
		利きなしsmate。1スレッド

		276-8-286(67.9% R-6.2)	

	ほぼ互角。3秒でも変わらなければこちらを採用したほうが良いのでは…。


		秒読み3000[ms]
		59.1%	
		#195
		やねうら王2016mid V310c
		ONE_PLY=1,reduction変更。1スレッド
		#193
		やねうら王2016mid V310a
		利きなしsmate。1スレッド

		65-3-45(2.2% R63.9)	

	どうも長い時間では新しいreduction tableのほうが有利くさい。(もう少しやったほうが良い)
	長い時間で魔女と勝率に差があく原因の一つはこれなのか？

	魔女と5秒でやらせてみる。


		秒読み5000[ms]

		31.1%	
		#195
		やねうら王2016mid V310c
		ONE_PLY=1,reduction変更。1スレッド
		#0
		silent_majority_V1.1公式
		1スレッド

		66-9-146(100.0% R-137.9)	

	前よりたくさん負け越した。そんな馬鹿な…。
	この際、魔女に近づけて行って、勝率どこで回復するか見たほうが良いのでは..

	V3.10d
	LMR新テーブル + qsearchでのmateなしとのコンボ。
	
		秒読み5000[ms]

		31.7%	
		#196
		やねうら王2016mid V310d
		ONE_PLY=1,reduction変更,qmateなし。1スレッド
		#0
		silent_majority_V1.1公式
		1スレッド

		33-2-71(100.0% R-133.1)	

	よく見たら魔女もqsearchでmate1呼んでた。置換表に書き出していないが…。

	V3.10e
	qmate復活。qmateのタイミングをもう少し早めに変更。
	mate1を見つけたときに置換表に書き出す処理、やめる。

		秒読み5000[ms]

		29.4%	
		#197
		やねうら王2016mid V310e
		qmate復活。呼び出しタイミング調整。1スレッド
		#0
		silent_majority_V1.1公式
		1スレッド

		55-5-132(100.0% R-152.1)	

	どんどん弱くなっててワロタ。


	V3.10f
	aspirationの幅40->18,深さ7->5

		秒読み5000[ms]

		34.4%	
		#198
		やねうら王2016mid V310f
		aspiration幅変更。1スレッド
		#0
		silent_majority_V1.1公式
		1スレッド

		77-8-147(100.0% R-112.3)	

	aspirationまわり変えたら、少し強くなった。
	そうか。Apery向けのaspirationではないので少し損をしていたのか…。

	Aperyのコード以下の部分、fall throughなのか。怖すぎワロタ。
		switch (pos.isDraw(16)) {
		case NotRepetition      : if (!Signals.stop.load(std::memory_order_relaxed) && ss->ply <= MaxPly) { break; }
		case RepetitionDraw     : return ScoreDraw;

	V3.10g
	update_stats()するの、capture or pawn promotionであるべき。

	V3.10h
	すべて↑であるべき。


		秒読み5000[ms]

		36.4%	
		#200
		やねうら王2016mid V310h
		update_stats()呼び出し修正。1スレッド
		#0
		silent_majority_V1.1公式
		1スレッド

		68-2-119(100.0% R-97.2)	

	R15ぐらい違うのかな？

		秒読み10000[ms]

		34.7%	
		#200
		やねうら王2016mid V310h
		update_stats()呼び出し修正。1スレッド
		#0
		silent_majority_V1.1公式
		1スレッド

		114-14-215(100.0% R-110.2)	

	10秒でもそんなにRは下がらなくなってきた。よしよし。


	USE_DROPBIT_IN_STATS、もしかして無駄である可能性…。
	まあいいや。いまそこが問題ではない。

	あとどこだろ。

	・指し手生成で何か抜けている可能性
	→　quiet + capture = all になるかとかテストすべき。

	・SEE()がおかしい可能性
	→　簡単な探索部と合致するかテストすべき

	・新しく書いたmate1ply()がおかしい可能性
	・評価関数が重い可能性
	
	V3.10i
	利き有効にしてのmate1ply()

		秒読み1000[ms]

		49.4%	
		#201
		やねうら王2016mid V310i
		利き使ったmate1ply()。1スレッド
		#200
		やねうら王2016mid V310h
		update_stats()呼び出し修正。1スレッド

		170-6-174(60.6% R-4.0)	


		秒読み3000[ms]

		42.0%	
		#201
		やねうら王2016mid V310i
		利き使ったmate1ply()。1スレッド
		#200
		やねうら王2016mid V310h
		update_stats()呼び出し修正。1スレッド

		42-4-58(95.6% R-56.1)	

	はやり遅い分だけやや損なのかも。

	see()書きなおしてみるか。

	V3.10j
	USE_SIMPLE_SEEを用意した。

		bench
		===========================
		Total time (ms) : 442722
		Nodes searched  : 308535061
		Nodes/second    : 696904

	だいぶ速くなった気がする。
	SEE、もう少し速くできる気がする。

		秒読み1000[ms]

		6.7%	
		#202
		やねうら王2016mid V310j
		simple see()。1スレッド
		#200
		やねうら王2016mid V310h
		update_stats()呼び出し修正。1スレッド

		2-0-28(100.0% R-458.5)	

	20連敗した。SEE、これじゃない感。

	turn間違えてる。
	  Color turn = ~(is_drop(move) ? sideToMove : color_of(piece_on(move_from(move))));
	いま、seeの順番、金があとになってるのよくない気はする。
	あと、攻撃の有無間違えてた。あれだけでこんなに勝率下がるのか。そうか…。

		秒読み100[ms]

		22.7%	
		#202
		やねうら王2016mid V310j
		simple see()。1スレッド
		#200
		やねうら王2016mid V310h
		update_stats()呼び出し修正。1スレッド

		20-0-68(100.0% R-212.6)	

	めっちゃ弱くなっとる。よく調べる。
	see()の前提処理まちごてた。修正した。

	see()前のコードも最後KING+1を返しているの、これおかしい気がしてきた。そうか…。
	と金で何かを取るとき、これがKING扱いになっていたのか。修正した。

		===========================
		Total time (ms) : 189502
		Nodes searched  : 108434227
		Nodes/second    : 572206

	
		秒読み300[ms]

		39.3%	
		#202
		やねうら王2016mid V310j
		simple see()。1スレッド
		#200
		やねうら王2016mid V310h
		update_stats()呼び出し修正。1スレッド

		132-5-204(100.0% R-75.6)	

	新SEE、バグってるんやろか。元のSEEに戻してテスト。

	V3.10k

		秒読み300[ms]

		49.8%	
		#203
		やねうら王2016mid V310k
		see() fix。1スレッド
		#200
		やねうら王2016mid V310h
		update_stats()呼び出し修正。1スレッド

		311-10-313(54.8% R-1.1)	

	SEE直したはずなのだが、勝率に影響がない。そんなもんなのか…。
	
	min_attacker()さらになおした。orderingも改善したはず…だが？

	V3.10l

		// 歩、香、桂、銀、金、角、飛…の順で取るのに使う駒を調べる。

		Bitboard b;
		b = stmAttackers & pos.piece_bb[PIECE_TYPE_BITBOARD_PAWN  ][stm]; if (b) goto found;
		b = stmAttackers & pos.piece_bb[PIECE_TYPE_BITBOARD_LANCE ][stm]; if (b) goto found;
		b = stmAttackers & pos.piece_bb[PIECE_TYPE_BITBOARD_KNIGHT][stm]; if (b) goto found;
		b = stmAttackers & pos.piece_bb[PIECE_TYPE_BITBOARD_SILVER][stm]; if (b) goto found;
		b = stmAttackers & pos.piece_bb[PIECE_TYPE_BITBOARD_GOLD  ][stm]; if (b) goto found;
		b = stmAttackers & pos.piece_bb[PIECE_TYPE_BITBOARD_BISHOP][stm]; if (b) goto found;
		b = stmAttackers & pos.piece_bb[PIECE_TYPE_BITBOARD_ROOK  ][stm]; if (b) goto found;
		b = stmAttackers & pos.piece_bb[PIECE_TYPE_BITBOARD_HDK][stm] & ~(pos.piece_bb[PIECE_TYPE_BITBOARD_ROOK  ][stm] | pos.king_square(stm)); if (b) goto found;
		b = stmAttackers & pos.piece_bb[PIECE_TYPE_BITBOARD_HDK][stm] & ~(pos.piece_bb[PIECE_TYPE_BITBOARD_BISHOP][stm] | pos.king_square(stm)); if (b) goto found;

		// ここでサイクルは停止するのだ。
	#ifndef USE_SIMPLE_SEE
		uncapValue = VALUE_ZERO;
	#endif
		return KING;

	わりとわかりやすい気がする。


		秒読み300[ms]

		48.7%	
		#204
		やねうら王2016mid V310l
		see() fix。1スレッド
		#200
		やねうら王2016mid V310h
		update_stats()呼び出し修正。1スレッド

		364-13-383(76.8% R-8.8)	

	わずかに遅くなった分、回収できていないのか…？

	// この駒が成れるなら、成りの値を返すべき。
	// ※　最後にこの地点に残る駒を返すべきなのか。相手が取る/取らないを選択するので。
	Piece pt = type_of(pos.piece_on(sq));
	if (!(pt & PIECE_PROMOTE) && (pt != GOLD)
		&& (canPromote(stm, to) || canPromote(stm,sq)))
		// 成りは敵陣へと、敵陣からの二種類あるので…。
	{

#ifndef USE_SIMPLE_SEE
		uncapValue = ProDiffPieceValue[pt]; // この駒が取り返せなかったときこの分、最後に損をする。
#endif
		return pt;
	}

	→　ちゃんと書いた。

		秒読み300[ms]

		50.0%	
		#204
		やねうら王2016mid V310l
		see() fix。1スレッド
		#200
		やねうら王2016mid V310h
		update_stats()呼び出し修正。1スレッド

		525-19-524(48.8% R0.3)	

	やっと前のものと等価ぐらいになった。

	新see()なおってたりしないのか。
	V3.10m

		秒読み300[ms]

		41.8%	
		#205
		やねうら王2016mid V310m
		see() fix。1スレッド
		#200
		やねうら王2016mid V310h
		update_stats()呼び出し修正。1スレッド

		147-5-205(99.9% R-57.8)	

	落ちなくはなったが弱い。まだ何かバグがある模様。
	まあいいや。これはまた時間あるときにデバッグしよう。
	
	V3.10n
	futility margin = 200など

		秒読み3000[ms]

		42.1%	
		#206
		やねうら王2016mid V310n
		see() fix。1スレッド
		#0
		silent_majority_V1.1公式
		1スレッド

		174-12-239(99.9% R-55.1)	

	差が縮まってきた…？

	V3.10o

	// 捕獲から逃れる指し手はreduction量を減らす。
	→　これ意味不明だった。どういうトリックかよくわからない。
	これ、コメントアウトしたほうがよさげ。
	see()の仕様がこちらの想定と違うのだが、それを考慮しても、
	Stockfishのコードはバグっているとしか思えない。

	null moveのreduction等を戻す。

		秒読み3000[ms]

		41.8%	
		#207
		やねうら王2016mid V310o
		see() fix。1スレッド
		#0
		silent_majority_V1.1公式
		1スレッド

		46-2-64(96.5% R-57.4)	


	V3.10p

-        pv[0] = MOVE_NONE;
+        (ss+1)->pv[0] = MOVE_NONE;

	なんぞこれ。間違えてた。

	魔女、fail lowたときに直前の指し手にボーナスを与える条件、間違っているような…。
		else if (depth >= 3 * OnePly
		  && bestMove.isNone() //!bestMove
		  && !inCheck
-		  && !ttMove.isCapture()//!move.cap()
+		  && !pos.captured_piece_type()
		  && (ss-1)->currentMove.is_ok())

	historyのupdateで打ち駒を+32してないところがあった。修正した。
	
	魔女より15%ぐらい遅いのかも知れない。(R40相当？)
	評価関数の差分計算とMoveの構造体、考えなおしたほうがよさ気。

		秒読み3000[ms]

		43.9%	
		#208
		やねうら王2016mid V310p
		see() fix。1スレッド
		#0
		silent_majority_V1.1公式
		1スレッド

		47-5-60(91.2% R-42.4)	

	npsの差程度に落ち着いてきた？寝る前に10秒で回しておく。
	せっかくなのでfutilityの幅を変える実験でもしておく。

	V3.10q
		  Value futility_margin(Depth d, int game_ply) {
			return Value(d * (PARAM_FUTILITY_MARGIN_ALPHA + param1 * 10 - 20) / ONE_PLY);
		  }

	Move32bit化、bit layout考えなおしたほうがよさ気。
	移動させる駒、上位16bitに格納するなら、駒打ちをそのbit5に格納したほうがいいような。
	historyで打ち駒を本当に分けたほうがいいのかはよくわからないが。
	historyにおいて、移動させる元の駒でorderingすべきなのか、そのあとの駒でorderingすべきか。
	指し手生成のときにそこまで生成すべきかどうか悩むな。


		秒読み10000[ms]

		41.1%	37.2%	37.5%	36.3%	39.6%	
		#209
		やねうら王2016mid V310q
		futility実験。1スレッド
		#0
		silent_majority_V1.1公式
		1スレッド

		129-18-185(99.9% R-62.6)	110-16-186(100.0% R-91.2)	112-13-187(100.0% R-89.0)	110-9-193(100.0% R-97.7)	120-9-183(100.0% R-73.3)	

	futility margin 180にしておくか。

