/// <summary> /// Runs CPU benchmark and outputs summary results, /// with an overall statistic provided (index to 100 on a Intel Skylake 6142). /// </summary> /// <returns>Relative CPU index (baseline 100)</returns> static int DumpCPUBenchmark() { Console.WriteLine("-----------------------------------------------------------------------------------"); Console.WriteLine("CPU BENCHMARK"); Position ps = Position.StartPosition; EncodedPositionBoard zb = default; MGMove nmove = ConverterMGMoveEncodedMove.EncodedMoveToMGChessMove(new EncodedMove("e2e4"), MGChessPositionConverter.MGChessPositionFromFEN(ps.FEN)); float ops1 = Benchmarking.DumpOperationTimeAndMemoryStats(() => MGPosition.FromPosition(ps), "MGPosition.FromPosition"); float ops2 = Benchmarking.DumpOperationTimeAndMemoryStats(() => MGChessPositionConverter.MGChessPositionFromFEN(ps.FEN), "MGChessPositionFromFEN"); float ops3 = Benchmarking.DumpOperationTimeAndMemoryStats(() => ConverterMGMoveEncodedMove.MGChessMoveToEncodedMove(nmove), "MGChessMoveToLZPositionMove"); float ops4 = Benchmarking.DumpOperationTimeAndMemoryStats(() => EncodedBoardZobrist.ZobristHash(zb), "ZobristHash"); // Performance metric is against a baseline system (Intel Skylake 6142) const float REFERENCE_BM1_OPS = 2160484; const float REFERENCE_BM2_OPS = 448074; const float REFERENCE_BM3_OPS = 157575582; const float REFERENCE_BM4_OPS = 112731351; float relative1 = ops1 / REFERENCE_BM1_OPS; float relative2 = ops2 / REFERENCE_BM2_OPS; float relative3 = ops3 / REFERENCE_BM3_OPS; float relative4 = ops4 / REFERENCE_BM4_OPS; float avg = StatUtils.Average(relative1, relative2, relative3, relative4); Console.WriteLine(); Console.WriteLine($"CERES CPU BENCHMARK SCORE: {avg*100,4:F0}"); return((int)MathF.Round(avg * 100, 0)); }
/// <summary> /// /// </summary> /// <param name="node"></param> /// <param name="parentAnnotation">optionally a precomputed parent annotation (otherwise computed)</param> /// <returns></returns> public unsafe void Annotate(MCTSNode node) { if (node.Annotation.IsInitialized) { return; } NumAnnotations++; // Get the position corresponding to this node MGPosition newPos; if (!node.IsRoot) { // Apply move for this node to the prior position node.Parent.Annotate(); newPos = node.Parent.Annotation.PosMG; newPos.MakeMove(ConverterMGMoveEncodedMove.EncodedMoveToMGChessMove(node.PriorMove, in newPos, true)); } else { newPos = PriorMoves.FinalPosMG; } MGMove priorMoveMG = default; if (!node.IsRoot) { priorMoveMG = ConverterMGMoveEncodedMove.EncodedMoveToMGChessMove(node.PriorMove, in node.Parent.Annotation.PosMG, true); } bool isRoot = node.IsRoot; Position newPosAsPos = newPos.ToPosition; // Create history, with prepended move representing this move Span <Position> posHistory = GetPriorHistoryPositions(node.Parent, in newPosAsPos, PosScratchBuffer, node.Context.ParamsSearch.DrawByRepetitionLookbackPlies, true); // Determine the set (possibly a subset) of positions over which to compute hash Span <Position> posHistoryForCaching = posHistory; int numCacheHashPositions = node.Context.EvaluatorDef.NumCacheHashPositions; if (posHistory.Length > numCacheHashPositions) { posHistoryForCaching = posHistory.Slice(posHistory.Length - numCacheHashPositions, numCacheHashPositions); } // Compute the actual hash ulong zobristHashForCaching = EncodedBoardZobrist.ZobristHash(posHistoryForCaching, node.Context.EvaluatorDef.HashMode); node.LastAccessedSequenceCounter = node.Context.Tree.SEQUENCE_COUNTER++; node.Annotation.PriorMoveMG = priorMoveMG; node.Annotation.Pos = posHistory[^ 1]; // this will have had its repetition count set
/// <summary> /// Attempts to find a subnode by following specified moves from root. /// </summary> /// <param name="priorRoot"></param> /// <param name="movesMade"></param> /// <returns></returns> static MCTSNode FollowMovesToNode(MCTSNode priorRoot, IEnumerable <MGMove> movesMade) { PositionWithHistory startingPriorMove = priorRoot.Context.StartPosAndPriorMoves; MGPosition position = startingPriorMove.FinalPosMG; MCTSIterator context = priorRoot.Context; // Advance root node and update prior moves MCTSNode newRoot = priorRoot; foreach (MGMove moveMade in movesMade) { bool foundChild = false; // Find this new root node (after these moves) foreach (MCTSNodeStructChild child in newRoot.Ref.Children) { if (child.IsExpanded) { MGMove thisChildMove = ConverterMGMoveEncodedMove.EncodedMoveToMGChessMove(child.Move, in position); if (thisChildMove == moveMade) { // Advance new root to reflect this move newRoot = context.Tree.GetNode(child.ChildIndex, newRoot); // Advance position position.MakeMove(thisChildMove); // Done looking for match foundChild = true; break; } } } if (!foundChild) { return(null); } } // Found it return(newRoot); }