示例#1
0
 /// <summary>
 /// Parses a move string from a specified starting position
 /// (either algebraic or SAN format is accepted).
 /// </summary>
 /// <param name="pos"></param>
 /// <param name="moveStr"></param>
 /// <returns></returns>
 public static MGMove ParseMove(MGPosition pos, string moveStr)
 {
     if (!TryParseMoveCoordinateOrAlgebraic(pos, moveStr, out MGMove move))
     {
         Position         position = MGChessPositionConverter.PositionFromMGChessPosition(in pos);
         PositionWithMove mfp      = SANParser.FromSAN(moveStr, position);
         return(MGMoveConverter.MGMoveFromPosAndMove(position, mfp.Move));
     }
     else
     {
         return(move);
     }
 }
示例#2
0
        MovesAndProbabilities(Position startPosition,
                              float minProbability = 0.0f, int topN = int.MaxValue)
        {
//      (EncodedMove bestMoveEncoded, float probability) = result.Policy.PolicyInfoAtIndex(posIndex);

            MGPosition mgPos = MGPosition.FromPosition(in startPosition);

            foreach ((EncodedMove move, float probability) in ProbabilitySummary(minProbability, topN))
            {
                MGMove mgMove  = ConverterMGMoveEncodedMove.EncodedMoveToMGChessMove(move, in mgPos);
                Move   moveRet = MGMoveConverter.ToMove(mgMove);
                yield return(moveRet, probability);
            }
        }
示例#3
0
        /// <summary>
        /// Returns a PositionWithHistory from a specified starting FEN and sequence of move strings in SAN format.
        /// </summary>
        /// <param name="fen"></param>
        /// <param name="sanMoves"></param>
        /// <returns></returns>
        public static PositionWithHistory FromFENAndMovesSAN(string fen, params string[] sanMoves)
        {
            Position            pos = Position.FromFEN(fen);
            PositionWithHistory ret = new PositionWithHistory(pos);

            if (sanMoves != null)
            {
                foreach (string sanMoveString in sanMoves)
                {
                    Move move = pos.MoveSAN(sanMoveString);
                    ret.AppendMove(MGMoveConverter.MGMoveFromPosAndMove(pos, move));
                    pos = pos.AfterMove(move);
                }
            }

            return(ret);
        }
示例#4
0
        void ProcessEPD(int epdNum, EPDEntry epd, bool outputDetail, ObjectPool <object> otherEngines)
        {
            UCISearchInfo otherEngineAnalysis2 = default;

            EPDEntry epdToUse = epd;

            Task RunNonCeres()
            {
                if (Def.ExternalEngineDef != null)
                {
                    object engineObj = otherEngines.GetFromPool();

                    if (engineObj is LC0Engine)
                    {
                        LC0Engine le = (LC0Engine)engineObj;

                        // Run test 2 first since that's the one we dump in detail, to avoid any possible caching effect from a prior run
                        otherEngineAnalysis2 = le.AnalyzePositionFromFEN(epdToUse.FEN, epdToUse.StartMoves, Def.ExternalEngineDef.SearchLimit);
                        //            leelaAnalysis2 = le.AnalyzePositionFromFEN(epdToUse.FEN, new SearchLimit(SearchLimit.LimitType.NodesPerMove, 2)); // **** TEMP
                        otherEngines.RestoreToPool(le);
                    }
                    else
                    {
                        UCIGameRunner runner = (engineObj is UCIGameRunner) ? (engineObj as UCIGameRunner)
            : (engineObj as GameEngineUCI).UCIRunner;
                        string moveType  = Def.ExternalEngineDef.SearchLimit.Type == SearchLimitType.NodesPerMove ? "nodes" : "movetime";
                        int    moveValue = moveType == "nodes" ? (int)Def.ExternalEngineDef.SearchLimit.Value : (int)Def.ExternalEngineDef.SearchLimit.Value * 1000;
                        runner.EvalPositionPrepare();
                        otherEngineAnalysis2 = runner.EvalPosition(epdToUse.FEN, epdToUse.StartMoves, moveType, moveValue, null);
                        otherEngines.RestoreToPool(runner);
                        //          public UCISearchInfo EvalPosition(int engineNum, string fenOrPositionCommand, string moveType, int moveMetric, bool shouldCache = false)
                    }
                }
                return(Task.CompletedTask);
            }

            bool EXTERNAL_CONCURRENT = numConcurrentSuiteThreads > 1;

            Task lzTask = EXTERNAL_CONCURRENT ? Task.Run(RunNonCeres) : RunNonCeres();

            // Comptue search limit
            // If possible, adjust for the fact that LC0 "cheats" by going slightly over node budget
            SearchLimit ceresSearchLimit1 = Def.CeresEngine1Def.SearchLimit;
            SearchLimit ceresSearchLimit2 = Def.CeresEngine2Def?.SearchLimit;

            if (Def.CeresEngine1Def.SearchLimit.Type == SearchLimitType.NodesPerMove &&
                otherEngineAnalysis2 != null &&
                !Def.Engine1Def.SearchParams.FutilityPruningStopSearchEnabled)
            {
                if (Def.CeresEngine1Def.SearchLimit.Type == SearchLimitType.NodesPerMove)
                {
                    ceresSearchLimit1 = new SearchLimit(SearchLimitType.NodesPerMove, otherEngineAnalysis2.Nodes);
                }
                if (Def.CeresEngine1Def.SearchLimit.Type == SearchLimitType.NodesPerMove)
                {
                    ceresSearchLimit2 = new SearchLimit(SearchLimitType.NodesPerMove, otherEngineAnalysis2.Nodes);
                }
            }

            PositionWithHistory pos = PositionWithHistory.FromFENAndMovesSAN(epdToUse.FEN, epdToUse.StartMoves);

            // TODO: should this be switched to GameEngineCeresInProcess?

            // Note that if we are running both Ceres1 and Ceres2 we alternate which search goes first.
            // This prevents any systematic difference/benefit that might come from order
            // (for example if we reuse position evaluations from the other tree, which can benefit only one of the two searches).
            MCTSearch search1 = null;
            MCTSearch search2 = null;

            if (epdNum % 2 == 0 || Def.CeresEngine2Def == null)
            {
                search1 = new MCTSearch();
                search1.Search(evaluatorSet1, Def.Engine1Def.SelectParams, Def.Engine1Def.SearchParams, null, null, null,
                               pos, ceresSearchLimit1, false, DateTime.Now, null, null, true);

                MCTSIterator shareContext = null;
                if (Def.RunCeres2Engine)
                {
                    if (Def.Engine2Def.SearchParams.ReusePositionEvaluationsFromOtherTree)
                    {
                        shareContext = search1.Manager.Context;
                    }

                    search2 = new MCTSearch();
                    search2.Search(evaluatorSet2, Def.Engine2Def.SelectParams, Def.Engine2Def.SearchParams, null, null, shareContext,
                                   pos, ceresSearchLimit2, false, DateTime.Now, null, null, true);
                }
            }
            else
            {
                search2 = new MCTSearch();
                search2.Search(evaluatorSet2, Def.Engine2Def.SelectParams, Def.Engine2Def.SearchParams, null, null, null,
                               pos, ceresSearchLimit2, false, DateTime.Now, null, null, true);

                MCTSIterator shareContext = null;
                if (Def.Engine1Def.SearchParams.ReusePositionEvaluationsFromOtherTree)
                {
                    shareContext = search2.Manager.Context;
                }

                search1 = new MCTSearch();
                search1.Search(evaluatorSet1, Def.Engine1Def.SelectParams, Def.Engine1Def.SearchParams, null, null, shareContext,
                               pos, ceresSearchLimit1, false, DateTime.Now, null, null, true);
            }

            // Wait for LZ analysis
            if (EXTERNAL_CONCURRENT)
            {
                lzTask.Wait();
            }

            Move bestMoveOtherEngine = default;

            if (Def.ExternalEngineDef != null)
            {
                MGPosition thisPosX = PositionWithHistory.FromFENAndMovesUCI(epdToUse.FEN, epdToUse.StartMoves).FinalPosMG;

                MGMove lzMoveMG1 = MGMoveFromString.ParseMove(thisPosX, otherEngineAnalysis2.BestMove);
                bestMoveOtherEngine = MGMoveConverter.ToMove(lzMoveMG1);
            }

            Move bestMoveCeres1 = MGMoveConverter.ToMove(search1.BestMove);

            Move bestMoveCeres2 = search2 == null ? default : MGMoveConverter.ToMove(search2.BestMove);

                                  char CorrectStr(Move move) => epdToUse.CorrectnessScore(move, 10) == 10 ? '+' : '.';

                                  int scoreCeres1      = epdToUse.CorrectnessScore(bestMoveCeres1, 10);
                                  int scoreCeres2      = epdToUse.CorrectnessScore(bestMoveCeres2, 10);
                                  int scoreOtherEngine = epdToUse.CorrectnessScore(bestMoveOtherEngine, 10);

                                  SearchResultInfo result1 = new SearchResultInfo(search1.Manager, search1.BestMove);
                                  SearchResultInfo result2 = search2 == null ? null : new SearchResultInfo(search2.Manager, search2.BestMove);

                                  accCeres1 += scoreCeres1;
                                  accCeres2 += scoreCeres2;

                                  // Accumulate how many nodes were required to find one of the correct moves
                                  // (in the cases where both succeeded)
                                  if (scoreCeres1 > 0 && (search2 == null || scoreCeres2 > 0))
                                  {
                                      accWCeres1 += (scoreCeres1 == 0) ? result1.N : result1.NumNodesWhenChoseTopNNode;
                                      if (search2 != null)
                                      {
                                          accWCeres2 += (scoreCeres2 == 0) ? result2.N : result2.NumNodesWhenChoseTopNNode;
                                      }
                                      numSearchesBothFound++;
                                  }
                                  this.avgOther += scoreOtherEngine;

                                  numSearches++;

                                  float avgCeres1  = (float)accCeres1 / numSearches;
                                  float avgCeres2  = (float)accCeres2 / numSearches;
                                  float avgWCeres1 = (float)accWCeres1 / numSearchesBothFound;
                                  float avgWCeres2 = (float)accWCeres2 / numSearchesBothFound;

                                  float avgOther = (float)this.avgOther / numSearches;

                                  string MoveIfWrong(Move m) => m.IsNull || epdToUse.CorrectnessScore(m, 10) == 10 ? "    " : m.ToString().ToLower();

                                  int diff1 = scoreCeres1 - scoreOtherEngine;

                                  //NodeEvaluatorNeuralNetwork
                                  int evalNumBatches1 = result1.NumNNBatches;
                                  int evalNumPos1     = result1.NumNNNodes;
                                  int evalNumBatches2 = search2 == null ? 0 : result2.NumNNBatches;
                                  int evalNumPos2     = search2 == null ? 0 : result2.NumNNNodes;

                                  string correctMove = null;

                                  if (epdToUse.AMMoves != null)
                                  {
                                      correctMove = "-" + epdToUse.AMMoves[0];
                                  }
                                  else if (epdToUse.BMMoves != null)
                                  {
                                      correctMove = epdToUse.BMMoves[0];
                                  }

                                  float otherEngineTime = otherEngineAnalysis2 == null ? 0 : (float)otherEngineAnalysis2.EngineReportedSearchTime / 1000.0f;

                                  totalTimeOther  += otherEngineTime;
                                  totalTimeCeres1 += (float)search1.TimingInfo.ElapsedTimeSecs;

                                  totalNodesOther += otherEngineAnalysis2 == null ? 0 : (int)otherEngineAnalysis2.Nodes;
                                  totalNodes1     += (int)result1.N;

                                  sumEvalNumPosOther += otherEngineAnalysis2 == null ? 0 : (int)otherEngineAnalysis2.Nodes;
                                  sumEvalNumBatches1 += evalNumBatches1;
                                  sumEvalNumPos1     += evalNumPos1;

                                  if (Def.RunCeres2Engine)
                                  {
                                      totalTimeCeres2    += (float)search2.TimingInfo.ElapsedTimeSecs;
                                      totalNodes2        += (int)result2.N;
                                      sumEvalNumBatches2 += evalNumBatches2;
                                      sumEvalNumPos2     += evalNumPos2;
                                  }

                                  float Adjust(int score, float frac) => score == 0 ? 0 : Math.Max(1.0f, MathF.Round(frac * 100.0f, 0));

                                  string worker1PickedNonTopNMoveStr = result1.PickedNonTopNMoveStr;
                                  string worker2PickedNonTopNMoveStr = result2?.PickedNonTopNMoveStr;

                                  bool ex = otherEngineAnalysis2 != null;
                                  bool c2 = search2 != null;

                                  Writer writer = new Writer(epdNum == 0);

                                  writer.Add("#", $"{epdNum,4}", 6);

                                  if (ex)
                                  {
                                      writer.Add("CEx", $"{avgOther,5:F2}", 7);
                                  }
                                  writer.Add("CC", $"{avgCeres1,5:F2}", 7);
                                  if (c2)
                                  {
                                      writer.Add("CC2", $"{avgCeres2,5:F2}", 7);
                                  }

                                  writer.Add("P", $" {0.001f * avgWCeres1,7:f2}", 9);
                                  if (c2)
                                  {
                                      writer.Add("P2", $" {0.001f * avgWCeres2,7:f2}", 9);
                                  }

                                  if (ex)
                                  {
                                      writer.Add("SEx", $"{scoreOtherEngine,3}", 5);
                                  }
                                  writer.Add("SC", $"{scoreCeres1,3}", 5);
                                  if (c2)
                                  {
                                      writer.Add("SC2", $"{scoreCeres2,3}", 5);
                                  }

                                  if (ex)
                                  {
                                      writer.Add("MEx", $"{otherEngineAnalysis2.BestMove,7}", 9);
                                  }
                                  writer.Add("MC", $"{search1.Manager.BestMoveMG,7}", 9);
                                  if (c2)
                                  {
                                      writer.Add("MC2", $"{search2.Manager.BestMoveMG,7}", 9);
                                  }

                                  writer.Add("Fr", $"{worker1PickedNonTopNMoveStr}{ 100.0f * result1.TopNNodeN / result1.N,3:F0}%", 9);
                                  if (c2)
                                  {
                                      writer.Add("Fr2", $"{worker2PickedNonTopNMoveStr}{ 100.0f * result2?.TopNNodeN / result2?.N,3:F0}%", 9);
                                  }

                                  writer.Add("Yld", $"{result1.NodeSelectionYieldFrac,6:f3}", 9);
                                  if (c2)
                                  {
                                      writer.Add("Yld2", $"{result2.NodeSelectionYieldFrac,6:f3}", 9);
                                  }

                                  // Search time
                                  if (ex)
                                  {
                                      writer.Add("TimeEx", $"{otherEngineTime,7:F2}", 9);
                                  }
                                  writer.Add("TimeC", $"{search1.TimingInfo.ElapsedTimeSecs,7:F2}", 9);
                                  if (c2)
                                  {
                                      writer.Add("TimeC2", $"{search2.TimingInfo.ElapsedTimeSecs,7:F2}", 9);
                                  }

                                  writer.Add("Dep", $"{result1.AvgDepth,5:f1}", 7);
                                  if (c2)
                                  {
                                      writer.Add("Dep2", $"{result2.AvgDepth,5:f1}", 7);
                                  }

                                  // Nodes
                                  if (ex)
                                  {
                                      writer.Add("NEx", $"{otherEngineAnalysis2.Nodes,12:N0}", 14);
                                  }
                                  writer.Add("Nodes", $"{result1.N,12:N0}", 14);
                                  if (c2)
                                  {
                                      writer.Add("Nodes2", $"{result2.N,12:N0}", 14);
                                  }

                                  // Fraction when chose top N
                                  writer.Add("Frac", $"{Adjust(scoreCeres1, result1.FractionNumNodesWhenChoseTopNNode),4:F0}", 6);
                                  if (c2)
                                  {
                                      writer.Add("Frac2", $"{Adjust(scoreCeres2, result2.FractionNumNodesWhenChoseTopNNode),4:F0}", 6);
                                  }

                                  // Score (Q)
                                  if (ex)
                                  {
                                      writer.Add("QEx", $"{otherEngineAnalysis2.ScoreLogistic,6:F3}", 8);
                                  }
                                  writer.Add("QC", $"{result1.Q,6:F3}", 8);
                                  if (c2)
                                  {
                                      writer.Add("QC2", $"{result2.Q,6:F3}", 8);
                                  }

                                  // Num batches&positions
                                  writer.Add("Batches", $"{evalNumBatches1,8:N0}", 10);
                                  writer.Add("NNEvals", $"{evalNumPos1,11:N0}", 13);
                                  if (c2)
                                  {
                                      writer.Add("Batches2", $"{evalNumBatches2,8:N0}", 10);
                                      writer.Add("NNEvals2", $"{evalNumPos2,11:N0}", 13);
                                  }

                                  // Tablebase hits
                                  writer.Add("TBase", $"{(search1.CountSearchContinuations > 0 ? 0 : search1.Manager.CountTablebaseHits),8:N0}", 10);
                                  if (c2)
                                  {
                                      writer.Add("TBase2", $"{(search2.CountSearchContinuations > 0 ? 0 : search2.Manager.CountTablebaseHits),8:N0}", 10);
                                  }

//      writer.Add("EPD", $"{epdToUse.ID,-30}", 32);

                                  if (outputDetail)
                                  {
                                      if (epdNum == 0)
                                      {
                                          Def.Output.WriteLine(writer.ids.ToString());
                                          Def.Output.WriteLine(writer.dividers.ToString());
                                      }
                                      Def.Output.WriteLine(writer.text.ToString());
                                  }

                                  //      MCTSNodeStorageSerialize.Save(worker1.Context.Store, @"c:\temp", "TESTSORE");

                                  search1?.Manager?.Dispose();
                                  if (!object.ReferenceEquals(search1?.Manager, search2?.Manager))
                                  {
                                      search2?.Manager?.Dispose();
                                  }
        }
示例#5
0
        static void DumpNodeStr(PositionWithHistory priorMoves, MCTSNode node, int depth, int countTimesSeen, bool fullDetail)
        {
            node.Context.Tree.Annotate(node);

            char extraChar = ' ';

            if (node.Terminal == GameResult.Checkmate)
            {
                extraChar = 'C';
            }
            else if (node.Terminal == GameResult.Draw)
            {
                extraChar = 'D';
            }
            else if (countTimesSeen > 1)
            {
                extraChar = countTimesSeen > 9 ? '9' : countTimesSeen.ToString()[0];
            }

            float multiplier = depth % 2 == 0 ? 1.0f : -1.0f;

            float pctOfVisits = node.IsRoot ? 100.0f : (100.0f * node.N / node.Parent.N);

            MCTSNode bestMove = null;

// TODO: someday show this too      MCTSNode nextBestMove = null;
            if (!node.IsRoot)
            {
                MCTSNode[] parentsChildrenSortedQ = node.ChildrenSorted(innerNode => - multiplier * (float)innerNode.Q);
                if (parentsChildrenSortedQ.Length > 0)
                {
                    bestMove = parentsChildrenSortedQ[0];
                }
//        if (parentsChildrenSortedQ.Length > 1) nextBestMove = parentsChildrenSortedQ[1];
            }

            // Depth, move
            Console.Write($"{depth,3}. ");
            Console.Write(extraChar);
            Console.Write($" {node.NumPolicyMoves,3} ");

            Console.Write($"{node.Index,13:N0}");

            string san = node.IsRoot ? "" : MGMoveConverter.ToMove(node.Annotation.PriorMoveMG).ToSAN(in node.Parent.Annotation.Pos);

//      string sanNextBest = node.IsRoot ? "" : MGMoveConverter.ToMove(nextBestMove.Annotation.PriorMoveMG).ToSAN(in node.Parent.Annotation.Pos);
            if (node.Annotation.Pos.MiscInfo.SideToMove == SideType.White)
            {
                Console.Write($"      ");
                Console.Write($"{san,6}");
            }
            else
            {
                Console.Write($"{san,6}");
                Console.Write($"      ");
            }

//      float diffBestNextBestQ = 0;
//      if (nextBestMove != null) diffBestNextBestQ = (float)(bestMove.Q - nextBestMove.Q);
//      Console.Write($"{  (nextBestMove?.Annotation == null ? "" : nextBestMove.Annotation.PriorMoveMG.ToString()),8}");
//      Console.Write($"{diffBestNextBestQ,8:F2}");


            Console.Write($"{node.N,13:N0} ");
            Console.Write($" {pctOfVisits,5:F0}%");
            Console.Write($"   {100.0 * node.P,6:F2}%  ");
            DumpWithColor(multiplier * node.V, $" {multiplier * node.V,6:F3}  ", -0.2f, 0.2f);
//      DumpWithColor(multiplier * node.VSecondary, $" {multiplier * node.VSecondary,6:F3} ", -0.2f, 0.2f);
            double q = multiplier * node.Q;

            DumpWithColor((float)q, $" {q,6:F3} ", -0.2f, 0.2f);

            //      float qStdDev = MathF.Sqrt(node.Ref.VVariance);
            //      if (float.IsNaN(qStdDev))
            //        Console.WriteLine("found negative var");
            //      Console.Write($" +/-{qStdDev,5:F2}  ");

            Console.Write($" {node.WinP,5:F2}/{node.DrawP,5:F2}/{node.LossP,5:F2}  ");

            Console.Write($" {node.WAvg,5:F2}/{node.DAvg,5:F2}/{node.LAvg,5:F2}  ");

            //      Console.Write($"   {node.Ref.QUpdatesWtdAvg,5:F2}  ");
            //      Console.Write($" +/-:{MathF.Sqrt(node.Ref.QUpdatesWtdVariance),5:F2}  ");
            //      Console.Write($" {node.Ref.TrendBonusToP,5:F2}  ");

            Console.Write($" {node.MPosition,3:F0} ");
            Console.Write($" {node.MAvg,3:F0}  ");

            if (fullDetail)
            {
                int numPieces = node.Annotation.Pos.PieceCount;

//        Console.Write($" {PosStr(node.Annotation.Pos)} ");
                Console.Write($" {node.Annotation.Pos.FEN}");
            }


            Console.WriteLine();
        }