/// <summary> /// Virtual worker method that attempts to resolve the evaluation of a specified node from the cache. /// </summary> /// <param name="node"></param> /// <returns></returns> protected override LeafEvaluationResult DoTryEvaluate(MCTSNode node) { PositionEvalCacheEntry cacheEntry = default; bool inCache = cache.TryLookupFromHash(node.Annotation.PositionHashForCaching, ref cacheEntry); if (inCache) { if (CeresEnvironment.MONITORING_METRICS) { NumCacheHits++; } Debug.Assert(!float.IsNaN(cacheEntry.WinP + cacheEntry.LossP)); LeafEvaluationResult result = new LeafEvaluationResult(cacheEntry.TerminalStatus, cacheEntry.WinP, cacheEntry.LossP, cacheEntry.M); result.PolicySingle = cacheEntry.Policy; return(result); } else { if (CeresEnvironment.MONITORING_METRICS) { NumCacheMisses++; } return(default);
/// <summary> /// /// TODO: this method similar to one below, try to unify them /// </summary> /// <param name="nodes"></param> /// <param name="results"></param> void RetrieveResults(Span <MCTSNode> nodes, IPositionEvaluationBatch results, EvalResultTarget resultTarget) { for (int i = 0; i < nodes.Length; i++) { MCTSNode node = nodes[i]; FP16 winP; FP16 lossP; FP16 rawM = results.GetM(i); // Copy WinP FP16 rawWinP = results.GetWinP(i); Debug.Assert(!float.IsNaN(rawWinP)); // Copy LossP FP16 rawLossP = results.GetLossP(i); Debug.Assert(!float.IsNaN(rawLossP)); // Assign win and loss probabilities // If they look like non-WDL result, try to rewrite them // in equivalent way that avoids negative probabilities if (rawWinP < 0 && rawLossP == 0) { winP = 0; lossP = -rawWinP; } else { winP = rawWinP; lossP = rawLossP; } LeafEvaluationResult evalResult = new LeafEvaluationResult(GameResult.Unknown, winP, lossP, rawM); evalResult.PolicyInArray = results.GetPolicy(i); // Copy policy if (resultTarget == EvalResultTarget.PrimaryEvalResult) { node.EvalResult = evalResult; } else if (resultTarget == EvalResultTarget.SecondaryEvalResult) { node.EvalResultSecondary = evalResult; } else { throw new Exception("Internal error: unexpected EvalResultTarget"); } // Save back to cache if (SaveToCache) { Cache.Store(node.Annotation.PositionHashForCaching, GameResult.Unknown, rawWinP, rawLossP, rawM, in node.EvalResult.PolicyRef); } } }
/// <summary> /// Attempts to evaluate node immediately and returns if successful (else default). /// </summary> /// <param name="node"></param> public LeafEvaluationResult TryEvaluate(MCTSNode node) { LeafEvaluationResult result = DoTryEvaluate(node); if (!result.IsNull) { Interlocked.Increment(ref CountHits); } return(result); }
private static LeafEvaluationResult ExtractTranspositionNodesFromSubtree(MCTSNode node, ref MCTSNodeStruct transpositionRootNode, ref int numAlreadyLinked, MCTSNodeTranspositionVisitor linkedVisitor) { LeafEvaluationResult result = default; // Determine how many evaluations we should extract (based on number requested and number available) int numAvailable = linkedVisitor.TranspositionRootNWhenVisitsStarted - numAlreadyLinked; int numDesired = node.NInFlight + node.NInFlight2; if (numDesired > numAvailable && WARN_COUNT < 10) { Console.WriteLine(numDesired + " Warning: multiple nodes were requested from the transposition subtree, available " + numAvailable); WARN_COUNT++; } int numToFetch = Math.Min(numDesired, numAvailable); Debug.Assert(numToFetch > 0); // Extract each evaluation for (int i = 0; i < numToFetch; i++) { MCTSNodeStructIndex transpositionSubnodeIndex = linkedVisitor.Visitor.GetNext(); Debug.Assert(!transpositionSubnodeIndex.IsNull); NumExtractedAndNeverCloned++; numAlreadyLinked++; // Prepare the result to return ref MCTSNodeStruct transpositionSubnode = ref node.Context.Tree.Store.Nodes.nodes[transpositionSubnodeIndex.Index]; LeafEvaluationResult thisResult = new LeafEvaluationResult(transpositionSubnode.Terminal, transpositionRootNode.WinP, transpositionRootNode.LossP, transpositionRootNode.MPosition); // Update our result node to include this node result = AddResultToResults(result, numToFetch, i, thisResult); if (VERBOSE) { Console.WriteLine($"ProcessAlreadyLinked {node.Index} yields {result.WinP} {result.LossP} via linked subnode root {transpositionRootNode.Index.Index} {transpositionRootNode} chose {transpositionSubnode.Index.Index}"); } node.Ref.NumNodesTranspositionExtracted++; }