public void SingleThreadedForwardSolver_TreePoolPerformance()
        {
            // IDEA: This puzzle has a relatively large amount of FLOOR space, which will create lots of Nodes in the TreePool

            // arrange
            var solver = new SingleThreadedForwardSolver();
            var command = new SolverCommand()
            {
                Puzzle = new Puzzle(new String[]
                {
                    "##########",
                    "#O.......#",
                    "#O.......#",
                    "#O.......#",
                    "#....X...#",
                    "#...XPX..#",
                    "#........#",
                    "##########"
                }),
                Report = Console.Out,
                ExitConditions = ExitConditions.OneMinute
            };

            // act
            var result = solver.Init(command) as SolverBase.CommandResult;
            solver.Solve(result);
            Console.WriteLine(result.ExitDescription);
            Console.WriteLine(SolverHelper.Summary(result));
            result.ThrowErrors();

            // assert
            Assert.That(result, Is.Not.Null);
        }
        public void SingleThreadedForwardSolver_BaseLine_Quick()
        {
            // arrange
            var solver = new SingleThreadedForwardSolver();
            var command = new SolverCommand()
            {
                Puzzle = new Puzzle(),
                Report = Console.Out,
                ExitConditions = new ExitConditions()
                {
                    Duration = TimeSpan.FromSeconds(10),
                    StopOnSolution = true,
                    TotalNodes = 10000
                }
            };

            // act
            var result = solver.Init(command) as SolverBase.CommandResult;
            solver.Solve(result);
            Console.WriteLine(result.ExitDescription);
            Console.WriteLine(SolverHelper.Summary(result));
            result.ThrowErrors();

            // assert
            Assert.That(result, Is.Not.Null);
        }
        public void BasicThreading()
        {
            var pTxt =
                @"###########~
            #P..#..#..#~
            #..X#X...X#~
            ##..#OO#..#~
            ~#..#OO#..#~
            ~#..#OO#..##
            ~#X...X#X..#
            ~#..#..#...#
            ~###########";
            var puzzle = new Puzzle(pTxt);

            var exit = new ExitConditions()
            {
                Duration = TimeSpan.FromSeconds(60),
                StopOnSolution = true,
                TotalNodes = int.MaxValue,
                TotalDead = int.MaxValue
            };
            // arrange
            var solver = new MultiThreadedForwardReverseSolver();
            var command = new SolverCommand()
            {
                Puzzle = new Puzzle(puzzle),
                Report = Console.Out,
                ExitConditions = exit,
                Progress = new ConsoleProgressNotifier()
            };

            // act
            var result = solver.Init(command);
            solver.Solve(result);
            Assert.That(result, Is.Not.Null);
            Console.WriteLine(result.ExitDescription);
            Console.WriteLine(SolverHelper.Summary(result));
            result.ThrowErrors();

            // assert
            Assert.That(result, Is.Not.Null);
        }
        private SolverCommandResult PerformStandardTest(Puzzle puzzle, ExitConditions exit = null)
        {
            exit = exit ?? new ExitConditions()
            {
                Duration = TimeSpan.FromSeconds(60),
                StopOnSolution = true,
                TotalNodes = int.MaxValue,
                TotalDead = int.MaxValue
            };
            // arrange
            var solver = new SingleThreadedForwardReverseSolver();
            var command = new SolverCommand()
            {
                Puzzle = new Puzzle(puzzle),
                Report = Console.Out,
                ExitConditions = exit
            };

            // act
            var result = solver.Init(command);
            solver.Solve(result);
            Console.WriteLine(result.ExitDescription);
            Console.WriteLine(SolverHelper.Summary(result));
            result.ThrowErrors();

            // assert
            Assert.That(result, Is.Not.Null);

            Assert.That(result.HasSolution, Is.True);
            Assert.That(result.GetSolutions(), Is.Not.Null);
            Assert.That(result.GetSolutions(), Is.Not.Empty);

            foreach (var sol in result.GetSolutions())
            {
                Console.WriteLine("Path: {0}", sol);
                string error = null;
                Assert.That(SolverHelper.CheckSolution(command.Puzzle, sol, out error), "Solution is INVALID! " + error);
            }
            return result;
        }
        public virtual SolverCommandResult Init(SolverCommand command)
        {
            var state = new CommandResult()
            {
                Command = command,
                Solutions = new List<SolverNode>(),
                SolutionsWithReverse = new List<SolutionChain>(),
                Forward = new SolverData()
                {
                    Evaluator = new ForwardEvaluator(),
                    Queue = new SolverQueue(),
                    PoolForward = new SolverNodeLookup()
                },
                Reverse = new SolverData()
                {
                    Evaluator = new ReverseEvaluator(),
                    Queue = new SolverQueue(),
                    PoolReverse = new SolverNodeLookup()
                }
            };
            state.Forward.PoolReverse = state.Reverse.PoolReverse;
            state.Reverse.PoolForward = state.Forward.PoolForward;

            state.StaticMaps = StaticAnalysis.Generate(command.Puzzle);
            state.StaticMaps.DeadMap = DeadMapAnalysis.FindDeadMap(state.StaticMaps);

            state.Forward.Root = state.Forward.Evaluator.Init(command.Puzzle, state.Forward.Queue);
            state.Reverse.Root = state.Reverse.Evaluator.Init(command.Puzzle, state.Reverse.Queue);
            Statistics = new SolverStatistics[]
            {
                state.Statistics,
                state.Forward.PoolForward.Statistics,
                state.Reverse.PoolReverse.Statistics,
                state.Forward.Queue.Statistics,
                state.Reverse.Queue.Statistics
            };

            return state;
        }
示例#6
0
 public SolverCommand(SolverCommand rhs)
 {
     if (rhs == null) throw new ArgumentNullException("rhs");
     Puzzle = rhs.Puzzle;
     Report = rhs.Report;
     ExitConditions = rhs.ExitConditions;
     CheckAbort = rhs.CheckAbort;
     Progress = rhs.Progress;
     Debug = rhs.Debug;
 }
        public List<Result> Run(SolverRun run, SolverCommand baseCommand, ISolver solver = null)
        {
            if (solver == null)
            {
                solver = new SingleThreadedForwardSolver();
            }

            Report.WriteLine("Puzzle Exit Conditions: {0}", run.PuzzleExit);
            Report.WriteLine("Batch Exit Conditions : {0}", run.BatchExit);
            Report.WriteLine("Solver                : {0}", SolverHelper.Describe(solver));
            Report.WriteLine("CPU                   : {0}", DebugHelper.GetCPUDescription());
            Report.WriteLine("Machine               : {0} {1}", Environment.MachineName, Environment.Is64BitProcess ? "x64" : "x32");

            Report.WriteLine();

            var res = new List<Result>();
            var start = new SolverStatistics()
            {
                Started = DateTime.Now
            };
            SolverCommandResult result = null;
            int pp = 0;
            int consecutiveFails = 0;
            foreach (var puzzle in run)
            {
                if (baseCommand.CheckAbort(baseCommand))
                {
                    Progress.WriteLine("EXITING...");
                    break;
                }
                try
                {
                    pp++;
                    Progress.WriteLine("Attempting: {0} ({2}/{3}); Rating: {1}", PuzzleHelper.GetName(puzzle), StaticAnalysis.CalculateRating(puzzle), pp, run.Count);

                    var libPuzzle = puzzle as LibraryPuzzle;
                    Report.WriteLine("           Name: {0}", PuzzleHelper.GetName(puzzle));
                    Report.WriteLine("          Ident: {0}", libPuzzle != null ? libPuzzle.Ident : null);
                    Report.WriteLine("         Rating: {0}", StaticAnalysis.CalculateRating(puzzle));
                    Report.WriteLine("Starting Memory: {0}", Environment.WorkingSet);
                    Report.WriteLine(puzzle.ToString());

                    PuzzleDTO dto = null;
                    if (Repository != null)
                    {
                        dto = Repository.Get(puzzle);
                        if (dto == null)
                        {
                            dto = Repository.ToDTO(puzzle);
                            Repository.Store(dto);
                        }
                        dto.Solutions = Repository.GetSolutions(dto.PuzzleId);
                    }

                    if (SkipPuzzlesWithSolutions)
                    {
                        if (dto != null &&
                            dto.Solutions.Exists(x=>x.HostMachine == Environment.MachineName && x.SolverType == solver.GetType().Name))
                        {
                            Progress.WriteLine("Skipping... (SkipPuzzlesWithSolutions)");
                            continue;
                        }
                    }

                    Report.WriteLine();

                    result = solver.Init(new SolverCommand(baseCommand)
                    {
                        Report = Report,
                        ExitConditions = run.PuzzleExit,
                        Puzzle = puzzle,

                    });
                    if (Tracking != null) Tracking.Begin(result);

                    solver.Solve(result);
                    var r = new Result()
                    {
                        Summary = SolverHelper.Summary(result),
                        Exited = result.Exit,
                        Solutions = result.GetSolutions()
                    };
                    res.Add(r);

                    start.TotalNodes += result.Statistics.TotalNodes;
                    start.TotalDead += result.Statistics.TotalDead;

                    if (r.Solutions.Any())
                    {
                        int cc = 0;
                        foreach (var p in r.Solutions.ToArray())
                        {
                            string error = null;
                            var check = SolverHelper.CheckSolution(puzzle, p, out error);
                            Report.WriteLine("Solution #{0} [{1}] =>\n{2}", cc++, check ? "Valid":"INVALID!"+error, p);
                            if (!check)
                            {
                                r.Solutions.Remove(p);
                                r.Summary += " (INVALID SOLUTION)";
                            }
                        }
                        // Write to DB?
                        if (dto != null)
                        {
                            if (Repository != null)
                            {
                                StoreSolution(solver, dto, r.Solutions);
                            }
                        }
                    }

                    if (r.Solutions.Any()) // May have been removed above
                    {
                        consecutiveFails = 0;
                    }
                    else
                    {
                        consecutiveFails++;
                        if (StopOnConsecutiveFails != 0 && consecutiveFails > StopOnConsecutiveFails)
                        {
                            Progress.WriteLine("ABORTING... StopOnConsecutiveFails");
                            break;
                        }
                    }

                    var finalStats = solver.Statistics;
                    if (finalStats != null)
                    {
                        foreach (var fs in finalStats)
                        {
                            Report.WriteLine("Statistics | {0}", fs);
                        }
                    }

                    if (Tracking != null) Tracking.End(result);

                    Report.WriteLine("[DONE] {0}", r.Summary);
                    if (result.Exception != null)
                    {
                        Report.WriteLine("[EXCEPTION]");
                        WriteException(Report, result.Exception);
                    }

                    Progress.WriteLine();
                    Progress.WriteLine("Completed: {0} ==> {1}", PuzzleHelper.GetName(puzzle), r.Summary);
                    Progress.WriteLine();

                    if (result.Exit == ExitConditions.Conditions.Aborted)
                    {
                        Progress.WriteLine("ABORTING...");
                        WriteSummary(res, start);
                        return res;
                    }

                    if (start.DurationInSec > run.BatchExit.Duration.TotalSeconds)
                    {
                        Progress.WriteLine("BATCH TIMEOUT...");
                        WriteSummary(res, start);
                        return res;
                    }

                    Progress.WriteLine();
                }
                catch (Exception ex)
                {
                    if (result != null) result.Exception = ex;
                    Progress.WriteLine("ERROR: "+ex.Message);
                    WriteException(Report, ex);
                }
                finally
                {
                    result = null;
                    Report.WriteLine("Ending Memory: {0}", Environment.WorkingSet);
                    GC.Collect();
                    Report.WriteLine("Post-GC Memory: {0}", Environment.WorkingSet);
                    Report.WriteLine("===================================");
                    Report.WriteLine();
                }

                Report.Flush();
            }
            WriteSummary(res, start);
            return res;
        }
示例#8
0
        protected virtual bool Tick(SolverCommand command, CommandResult state, ISolverQueue queue, out SolverCommandResult solve)
        {
            state.Statistics.DepthCompleted = queue.Statistics.DepthCompleted;
            state.Statistics.DepthMax = queue.Statistics.DepthMax;

            if (command.Progress != null)
            {
                command.Progress.Update(this, state, state.Statistics);
            }

            if (command.CheckAbort != null)
            {
                if (command.CheckAbort(command))
                {
                    state.Exit = ExitConditions.Conditions.Aborted;
                    state.EarlyExit = true;
                    state.Statistics.Completed = DateTime.Now;
                    solve = state;
                    return true;
                }
            }

            var check = command.ExitConditions.ShouldExit(state);
            if (check != ExitConditions.Conditions.Continue)
            {
                state.EarlyExit = true;
                state.Statistics.Completed = DateTime.Now;
                state.Exit = check;
                solve = state;
                return true;

            }
            solve = null;
            return false;
        }
示例#9
0
        public virtual SolverCommandResult Init(SolverCommand command)
        {
            var state = SolverHelper.Init(new CommandResult(), command);

            state.Statistics.Name = GetType().Name;;
            state.Pool = new SolverNodeLookup()
            {
                Report = command.Report
            };

            state.Evaluator = evaluator;
            state.Queue= new SolverQueue();

            state.Root = state.Evaluator.Init(command.Puzzle, state.Queue);

            Statistics = new SolverStatistics[] { state.Statistics, state.Pool.Statistics, state.Queue.Statistics };
            return state;
        }
        public void SingleThreadedForwardSolver_TreePoolPerformance_Large()
        {
            Console.WriteLine("IDEA: This puzzle has a relatively large amount of FLOOR space, which will create lots of Nodes in the TreePool");
            Console.WriteLine("[WILLOW: Started prep for multi-threading] 52000 nodes at 851.658640168867 nodes/sec. Exited EARLY. Time => Nodes: 52000, Dead: 0, Duration: 61.0573269 sec., Duplicates: 236306");
            Console.WriteLine("[WILLOW: Collection optimistion] 59000 nodes at 980.895125589307 nodes/sec. Exited EARLY. Time => Nodes: 59000, Dead: 0, Duration: 60.1491418 sec., Duplicates: 274401");
            Console.WriteLine("[Added Buffered inserts] 68000 nodes at 1129.36134313775 nodes/sec. Exited EARLY. Time => Nodes: 68000, Dead: 0, Duration: 60.2110214 sec., Duplicates: 476102");

            // arrange
            var solver = new SingleThreadedForwardSolver();
            var command = new SolverCommand()
            {
                Puzzle = new Puzzle(new String[]
                {
                    "##########",
                    "#O.......#",
                    "#O.....X.#",
                    "#O.......#",
                    "#........#",
                    "#........#",
                    "#....X...#",
                    "#...XPX..#",
                    "#....O...#",
                    "##########"
                }),
                Report = Console.Out,
                ExitConditions = new ExitConditions()
                {
                    Duration = TimeSpan.FromMinutes(1),
                    TotalNodes =  int.MaxValue,
                    TotalDead = int.MaxValue,
                    StopOnSolution = false // !!!!!!
                },
                Progress = new ConsoleProgressNotifier()

            };

            // act
            var result = solver.Init(command) as SolverBase.CommandResult;
            solver.Solve(result);
            Console.WriteLine(SolverHelper.Summary(result));
            result.ThrowErrors();

            Console.WriteLine("All Nodes");
            Console.WriteLine( (result as SingleThreadedForwardSolver.CommandResult).Pool.ToString());

            // assert
            Assert.That(result, Is.Not.Null);
        }
        void PuzzleShouldHaveSolution(ISolver solver, Puzzle puzzle, ExitConditions exit = null, bool verbose = false)
        {
            if (exit == null)
            {
                exit = new ExitConditions()
                {
                    Duration = TimeSpan.FromSeconds(60),
                    StopOnSolution = true,
                    TotalNodes = int.MaxValue,
                    TotalDead = int.MaxValue
                };
            }
            var command = new SolverCommand()
            {
                Puzzle = puzzle,
                Report = Console.Out,
                Progress = new ConsoleProgressNotifier(),
                ExitConditions = exit
            };

            // act
            var result = solver.Init(command);
            solver.Solve(result);
            Console.WriteLine(result.ExitDescription);
            Console.WriteLine(SolverHelper.Summary(result));
            result.ThrowErrors();

            // assert
            Assert.That(result, Is.Not.Null);
            Assert.That(result.HasSolution, Is.True);

            foreach (var sol in result.GetSolutions())
            {
                Console.WriteLine("Path: {0}", sol);
                string error = null;

                Assert.That(SolverHelper.CheckSolution(command.Puzzle, sol, out error), "Solution is INVALID! "+error);
            }
        }
        public SolverCommandResult Init(SolverCommand command)
        {
            var prog = command.Progress;
            command.Progress = null;

            var poolForward = new ThreadSafeSolverNodeLookupWrapper();
            poolForward.Statistics.Name = "Forward Pool";
            var poolReverse = new ThreadSafeSolverNodeLookupWrapper();
            poolReverse.Statistics.Name = "Reverse Pool";

            var queueForward = new ThreadSafeSolverQueueWrapper(new SolverQueue());
            queueForward.Statistics.Name = "Forward Queue";

            var queueReverse = new ThreadSafeSolverQueueWrapper(new SolverQueue());
            queueReverse.Statistics.Name = "Reverse Queue";
            current = new CommandResult()
            {
                PoolForward = poolForward,
                PoolReverse = poolReverse,
                Command = command,
                Statistics = new SolverStatistics()
                {
                    Name = GetType().Name,
                    Started = DateTime.Now
                },
                StatsInner = new List<SolverStatistics>(),
                Workers =  new List<Worker>
                {
                    // First Pair
                    new ForwardWorker()
                    {
                        Name = "F1",
                        Command = command,
                        Pool = poolForward,
                        PoolSolution = poolReverse,
                        Queue = queueForward
                    },
                    new ForwardWorker()
                    {
                        Name = "F2",
                        Command = command,
                        Pool = poolForward,
                        PoolSolution = poolReverse,
                        Queue = queueForward
                    },
                    new ForwardWorker()
                    {
                        Name = "F3",
                        Command = command,
                        Pool = poolForward,
                        PoolSolution = poolReverse,
                        Queue = queueForward
                    },
                    new ForwardWorker()
                    {
                        Name = "F4",
                        Command = command,
                        Pool = poolForward,
                        PoolSolution = poolReverse,
                        Queue = queueForward
                    },

                    new ReverseWorker()
                    {
                        Name = "R1",
                        Command = command,
                        Pool = poolReverse,
                        PoolSolution = poolForward,
                        Queue =queueReverse
                    },
                    new ReverseWorker()
                    {
                        Name = "R2",
                        Command = command,
                        Pool = poolReverse,
                        PoolSolution = poolForward,
                        Queue = queueReverse
                    },
                    new ReverseWorker()
                    {
                        Name = "R3",
                        Command = command,
                        Pool = poolReverse,
                        PoolSolution = poolForward,
                        Queue = queueReverse
                    },
                    new ReverseWorker()
                    {
                        Name = "R4",
                        Command = command,
                        Pool = poolReverse,
                        PoolSolution = poolForward,
                        Queue = queueReverse
                    }
                },
            };

            current.StatsInner.Add(current.Statistics);
            current.StatsInner.Add(poolForward.Statistics);
            current.StatsInner.Add(poolReverse.Statistics);
            current.StatsInner.Add(current.Statistics);
            current.StatsInner.Add(queueForward.Statistics);
            current.StatsInner.Add(queueReverse.Statistics);

            var tmp = command.Progress;
            command.Progress = null;
            foreach (var worker in current.Workers)
            {
                worker.Owner = this;
                worker.OwnerState = current;
                worker.Init();
                if (worker.Solver.Statistics != null)
                {
                    current.StatsInner.AddRange(worker.Solver.Statistics);
                }
                worker.Task = new Task<Worker>(x => Execute((Worker)x), worker, TaskCreationOptions.LongRunning);
            }
            command.Progress = tmp;

            // Init queues
            current.Workers.First(X => X.Evaluator is ForwardEvaluator).Evaluator.Init(command.Puzzle, queueForward);
            current.Workers.First(X => X.Evaluator is ReverseEvaluator).Evaluator.Init(command.Puzzle, queueReverse);

            current.Progress = new ProgressUpater(this, current);
            current.ProgressTask = new Task(current.Progress.Worker);

            command.Progress = prog;

            return current;
        }
 private bool CheckWorkerAbort(SolverCommand arg)
 {
     return !Worker.OwnerState.IsRunning;
 }
            public override SolverCommandResult Init(SolverCommand command)
            {
                var state = SolverHelper.Init(new CommandResult(), command);

                state.Command.Progress = null;
                state.Command.Parent = Worker.Owner;
                state.Command.CheckAbort = CheckWorkerAbort;

                state.Statistics.Name = GetType().Name; ;
                state.Pool = Worker.Pool;

                state.Evaluator = new ReverseEvaluator();
                state.Queue = Worker.Queue;

                Statistics = new SolverStatistics[] { state.Statistics };
                return state;
            }
            public override SolverCommandResult Init(SolverCommand command)
            {
                var state = SolverHelper.Init(new CommandResult(), command);

                state.Command.Parent = Worker.Owner;
                state.Command.CheckAbort = x => !Worker.OwnerState.IsRunning;

                state.Statistics.Name = GetType().Name;
                state.Pool = Worker.Pool;

                state.Evaluator = new ForwardEvaluator();
                state.Queue = Worker.Queue;

                Statistics = new SolverStatistics[] { state.Statistics};
                return state;
            }