Ejemplo n.º 1
0
        void OutputUCIInfo(MCTSManager manager, MCTSNode searchRootNode, bool isFinalInfo = false)
        {
            BestMoveInfo best = searchRootNode.BestMoveInfo(false);

            if (numPV == 1)
            {
                UCIWriteLine(UCIInfo.UCIInfoString(manager, searchRootNode, best?.BestMoveNode,
                                                   showWDL: showWDL, scoreAsQ: scoreAsQ));
            }
            else
            {
                // Send top move
                UCIWriteLine(UCIInfo.UCIInfoString(manager, searchRootNode, best.BestMoveNode, 1,
                                                   showWDL: showWDL, useParentN: !perPVCounters, scoreAsQ: scoreAsQ));

                // Send other moves visited
                MCTSNode[] sortedN      = searchRootNode.ChildrenSorted(s => - (float)s.N);
                int        multiPVIndex = 2;
                for (int i = 0; i < sortedN.Length && i < numPV; i++)
                {
                    if (!object.ReferenceEquals(sortedN[i], best.BestMoveNode))
                    {
                        UCIWriteLine(UCIInfo.UCIInfoString(manager, searchRootNode, sortedN[i], multiPVIndex,
                                                           showWDL: showWDL, useParentN: !perPVCounters, scoreAsQ: scoreAsQ));
                        multiPVIndex++;
                    }
                }

                // Finally show moves that had no visits
                float  elapsedTimeSeconds = (float)(DateTime.Now - manager.StartTimeThisSearch).TotalSeconds;
                string timeStr            = $"{ elapsedTimeSeconds * 1000.0f:F0}";
                for (int i = multiPVIndex - 1; i < searchRootNode.NumPolicyMoves; i++)
                {
                    (MCTSNode node, EncodedMove move, FP16 p)info = searchRootNode.ChildAtIndexInfo(i);
                    if (info.node == null)
                    {
                        bool        isWhite = searchRootNode.Annotation.Pos.MiscInfo.SideToMove == SideType.White;
                        EncodedMove moveCorrectPerspective = isWhite ? info.move : info.move.Flipped;
                        string      str = $"info depth 0 seldepth 0 time { timeStr } nodes 1 score cp 0 tbhits 0 "
                                          + $"multipv {multiPVIndex} pv {moveCorrectPerspective.AlgebraicStr} ";
                        UCIWriteLine(str);
                        multiPVIndex++;
                    }
                }
            }
            if (verboseMoveStats && (logLiveStats || isFinalInfo))
            {
                OutputVerboseMoveStats(CeresEngine.Search.SearchRootNode);
            }
        }
Ejemplo n.º 2
0
        static void MCTSProgressCallback(MCTSManager manager)
        {
            int numUpdatesSent = 0;

            DateTime now = DateTime.Now;
            float    timeSinceLastUpdate = (float)(now - lastInfoUpdate).TotalSeconds;

            bool  isFirstUpdate           = numUpdatesSent == 0;
            float UPDATE_INTERVAL_SECONDS = 1;// isFirstUpdate ? 0.1f : 3f;

            if (timeSinceLastUpdate > UPDATE_INTERVAL_SECONDS && manager.Root.N > 0)
            {
                Console.WriteLine(UCIInfo.UCIInfoString(manager));
                lastInfoUpdate = now;
            }
        }
Ejemplo n.º 3
0
        public static void Analyze(string fenAndMoves, SearchLimit searchLimit,
                                   NNEvaluatorDef evaluatorDef,
                                   bool forceDisablePruning,
                                   LC0Engine lc0Engine         = null,
                                   GameEngine comparisonEngine = null,
                                   bool verbose = false)
        {
            Console.WriteLine("=============================================================================");
            Console.WriteLine("Analyzing FEN   : " + fenAndMoves);
            Console.WriteLine("Search limit    : " + searchLimit.ToString());
            Console.WriteLine("Ceres evaluator : " + evaluatorDef.ToString());
            if (comparisonEngine != null)
            {
                Console.WriteLine("Opponent      : " + comparisonEngine.ToString());
            }
            Console.WriteLine();
            Console.WriteLine();

            NNEvaluatorSet nnEvaluators = new NNEvaluatorSet(evaluatorDef);

            // Warmup (in parallel)
            lc0Engine?.DoSearchPrepare();
            Parallel.Invoke(
                () => nnEvaluators.Warmup(true),
                () => comparisonEngine?.Warmup());

            bool ceresDone = false;

            lastInfoUpdate = DateTime.Now;

            UCISearchInfo lastCeresInfo = null;

            // Launch Ceres
            MCTSearch ceresResults = null;
            Task      searchCeres  = Task.Run(() =>
            {
                ParamsSearch searchParams = new ParamsSearch();
                searchParams.FutilityPruningStopSearchEnabled = !forceDisablePruning;
                PositionWithHistory positionWithHistory       = PositionWithHistory.FromFENAndMovesUCI(fenAndMoves);
                ceresResults = new MCTSearch();
                ceresResults.Search(nnEvaluators, new ParamsSelect(), searchParams, null, null,
                                    null, positionWithHistory, searchLimit, verbose, DateTime.Now, null,
                                    manager => lastCeresInfo = new UCISearchInfo(UCIInfo.UCIInfoString(manager), null, null), false, true);
            });

            // Possibly launch search for other engine
            Task searchComparison = null;

            if (lc0Engine != null || comparisonEngine != null)
            {
                searchComparison = Task.Run(() =>
                {
                    if (lc0Engine != null)
                    {
                        lc0Engine.DoSearchPrepare();
                        lc0Engine.AnalyzePositionFromFENAndMoves(fenAndMoves, searchLimit);
                    }
                    else
                    {
                        comparisonEngine.Search(PositionWithHistory.FromFENAndMovesUCI(fenAndMoves), searchLimit, verbose: true);
                    }
                });
            }
            ;

            while (!searchCeres.IsCompleted || (searchComparison != null && !searchComparison.IsCompleted))
            {
                Thread.Sleep(1000);
//Console.WriteLine(DateTime.Now + " --> " + lastCeresInfo?.PVString + " OTHER " + comparisonEngine?.UCIInfo?.RawString);

                int numCharactersSame = int.MaxValue;
                if (lastCeresInfo?.PVString != null || comparisonEngine?.UCIInfo?.RawString != null)
                {
                    if (lastCeresInfo != null && comparisonEngine?.UCIInfo != null)
                    {
                        numCharactersSame = 0;
                        string        pv1 = lastCeresInfo.PVString;
                        UCISearchInfo lastComparisonInfo = comparisonEngine.UCIInfo;
                        string        pv2 = lastComparisonInfo.PVString;
                        while (pv1.Length > numCharactersSame &&
                               pv2.Length > numCharactersSame &&
                               pv1[numCharactersSame] == pv2[numCharactersSame])
                        {
                            numCharactersSame++;
                        }
                    }
                }

                if (lastCeresInfo != null)
                {
                    WriteUCI("Ceres", lastCeresInfo, numCharactersSame);
                }

                if (comparisonEngine != null)
                {
                    WriteUCI(comparisonEngine.ID, comparisonEngine.UCIInfo, numCharactersSame);
                }
                Console.WriteLine();
            }

            searchCeres.Wait();
            searchComparison?.Wait();

            string infoUpdate = UCIInfo.UCIInfoString(ceresResults.Manager);

            double q2 = ceresResults.SearchRootNode.Q;

            //SearchPrincipalVariation pv2 = new SearchPrincipalVariation(worker2.Root);
            MCTSPosTreeNodeDumper.DumpPV(ceresResults.SearchRootNode, true);
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Writes extensive descriptive information to a specified TextWriter,
        /// including verbose move statistics, principal variation, and move timing information.
        /// </summary>
        /// <param name="searchRootNode"></param>
        /// <param name="writer"></param>
        /// <param name="description"></param>
        public void DumpFullInfo(MGMove bestMove, MCTSNode searchRootNode = null, TextWriter writer = null, string description = null)
        {
            searchRootNode = searchRootNode ?? Root;
            writer         = writer ?? Console.Out;

            int moveIndex = searchRootNode.Tree.Store.Nodes.PriorMoves.Moves.Count;

            writer.WriteLine();
            writer.WriteLine("=================================================================================");
            writer.Write(DateTime.Now + " SEARCH RESULT INFORMATION,  Move = " + ((1 + moveIndex / 2)));
            writer.WriteLine($" Thread = {Thread.CurrentThread.ManagedThreadId}");
            if (description != null)
            {
                writer.WriteLine(description);
            }
            writer.WriteLine();

            writer.WriteLine("Tree root           : " + Context.Root);
            if (searchRootNode != Root)
            {
                writer.WriteLine("Search root         : " + searchRootNode);
            }
            writer.WriteLine();

            MCTSNode[] nodesSortedN = null;
            MCTSNode[] nodesSortedQ = null;

            string bestMoveInfo = "";

            if (searchRootNode.NumChildrenExpanded > 0 &&
                StopStatus != SearchStopStatus.TablebaseImmediateMove &&
                StopStatus != SearchStopStatus.OnlyOneLegalMove)
            {
                MCTSNode[] childrenSortedN = searchRootNode.ChildrenSorted(node => - node.N);
                MCTSNode[] childrenSortedQ = searchRootNode.ChildrenSorted(node => (float)node.Q);
                bool       isTopN          = childrenSortedN[0].Annotation.PriorMoveMG == bestMove;
                bool       isTopQ          = childrenSortedQ[0].Annotation.PriorMoveMG == bestMove;
                if (isTopN && isTopQ)
                {
                    bestMoveInfo = "(TopN and TopQ)";
                }
                else if (isTopN)
                {
                    bestMoveInfo = "(TopN)";
                }
                else if (isTopQ)
                {
                    bestMoveInfo = "(TopQ)";
                }
            }

            // Output position (with history) information.
            writer.WriteLine("Position            : " + searchRootNode.Annotation.Pos.FEN);
            writer.WriteLine("Tree root position  : " + Context.Tree.Store.Nodes.PriorMoves);
            writer.WriteLine("Search stop status  : " + StopStatus);
            writer.WriteLine("Best move selected  : " + bestMove.MoveStr(MGMoveNotationStyle.LC0Coordinate) + " " + bestMoveInfo);
            writer.WriteLine();

            using (new SearchContextExecutionBlock(Context))
            {
                string infoUpdate = UCIInfo.UCIInfoString(this, searchRootNode);
                writer.WriteLine(infoUpdate);

                writer.WriteLine();
                DumpTimeInfo(writer);

                writer.WriteLine();
                searchRootNode.Dump(1, 1, writer: writer);

                writer.WriteLine();
                MCTSPosTreeNodeDumper.DumpPV(searchRootNode, true, writer);
            }
        }