public override SolverState Init(SolverCommand command) { var state = SolverHelper.Init(new MultiThreadedSolverState(), command); state.Command.Parent = Worker.Owner; state.Command.CheckAbort = x => !Worker.OwnerState.IsRunning; state.Statistics.Name = $"{GetType().Name}:{Worker.Name}"; state.Pool = Worker.Pool; state.Evaluator = new ForwardEvaluator(nodeFactory); state.Queue = Worker.Queue; Statistics = new[] { state.Statistics }; return(state); }
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; Parent = null; ServiceProvider = rhs.ServiceProvider; AggProgress = rhs.AggProgress; CheckAbort = x => CancellationToken.IsCancellationRequested; }
private bool CheckWorkerAbort(SolverCommand arg) { return(!Worker.OwnerState.IsRunning); }
public SolverState Init(SolverCommand command) { if (nodeFactory is ISolveNodeFactoryPuzzleDependant dep) { dep.SetupForPuzzle(command.Puzzle); } var poolForward = command.ServiceProvider.GetInstanceElseDefault <ISolverPool>(() => new SolverPoolSlimRwLock(new SolverPoolBinarySearchTree(new SolverPoolLongTerm()))); var poolReverse = command.ServiceProvider.GetInstanceElseDefault <ISolverPool>(() => new SolverPoolSlimRwLock(new SolverPoolBinarySearchTree(new SolverPoolLongTerm()))); poolForward.Statistics.Name = "Pool (Forward)"; poolReverse.Statistics.Name = "Pool (Reverse)"; var queueForward = command.ServiceProvider.GetInstanceElseDefault <ISolverQueue>(() => new SolverQueueConcurrent()); var queueReverse = command.ServiceProvider.GetInstanceElseDefault <ISolverQueue>(() => new SolverQueueConcurrent()); queueForward.Statistics.Name = "Queue (Forward)"; queueReverse.Statistics.Name = "Queue (Reverse)"; current = new MultiThreadedSolverState { PoolForward = poolForward, PoolReverse = poolReverse, QueueForward = queueForward, QueueReverse = queueReverse, Command = command, Statistics = new SolverStatistics { Name = GetType().Name, Started = DateTime.Now }, StatsInner = new List <SolverStatistics>(), Workers = new List <Worker>(), StaticMaps = new StaticAnalysisMaps(command.Puzzle) }; for (int i = 0; i < ThreadCountForward; i++) { current.Workers.Add(new ForwardWorker(nodeFactory) { Name = $"F{i,00}", Command = command, Pool = poolForward, PoolSolution = poolReverse, Queue = queueForward }); } for (int i = 0; i < ThreadCountReverse; i++) { current.Workers.Add(new ReverseWorker(nodeFactory) { Name = $"R{i,00}", 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(queueForward.Statistics); current.StatsInner.Add(queueReverse.Statistics); 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); } // Init queues current.Root = current.Workers.FirstOrDefault(x => x.Evaluator is ForwardEvaluator).Evaluator.Init(command.Puzzle, queueForward); current.PoolForward.Add(current.Root.Recurse().ToList()); current.RootReverse = current.Workers.FirstOrDefault(x => x.Evaluator is ReverseEvaluator).Evaluator.Init(command.Puzzle, queueReverse); current.PoolReverse.Add(current.RootReverse.Recurse().ToList()); if (queueForward is ReuseTreeSolverQueue tqf) { tqf.Root = current.Root; } if (queueReverse is ReuseTreeSolverQueue tqr) { tqr.Root = current.RootReverse; } return(current); }
public int SolverRun(BatchArgs batchArgs, SolverRun run) { var args = new FluentString(" ") .Append(batchArgs.Puzzle).Sep() .Append($"--solver {batchArgs.Solver}").Sep() .Append($"--pool {batchArgs.Pool}").Sep() .If(batchArgs.Min > 0, $"--min {batchArgs.Min}").Sep() .If(batchArgs.Sec > 0, $"--sec {batchArgs.Sec}").Sep() .If(batchArgs.MinR > 0, $"--min-rating {batchArgs.MinR}").Sep() .If(batchArgs.MaxR < 2000, $"--min-rating {batchArgs.MaxR}"); batchArgs.Console.WriteLine($"Arguments: {args}"); var exitRequested = false; SolverCommand?executing = null; // Setup: Report and cancellation var benchId = DateTime.Now.ToString("s").Replace(':', '-'); var outFile = $"./benchmark--{benchId}.txt"; var outTele = $"./telemetry--{benchId}.csv"; var outFolder = "./results/"; if (!Directory.Exists(outFolder)) { Directory.CreateDirectory(outFolder); } var info = new FileInfo(System.IO.Path.Combine(outFolder, outFile)); var tele = new FileInfo(System.IO.Path.Combine(outFolder, outTele)); using var report = File.CreateText(info.FullName); using var repTele = File.CreateText(tele.FullName); System.Console.CancelKeyPress += (o, e) => { report.Flush(); batchArgs.Console.WriteLine("Ctrl+C detected; cancel requested"); if (executing != null) { executing.ExitConditions.ExitRequested = true; } exitRequested = true; }; ISokobanSolutionRepository?solutionRepo = File.Exists("./solutions.json") && !DevHelper.IsDebug() ? new JsonSokobanSolutionRepository("./solutions.json") : null; ISolverRunTracking?runTracking = null; var results = new List <(Strategy, List <SolverResultSummary>)>(); var perm = GetPermutations(batchArgs.Solver, batchArgs.Pool).ToList(); var countStrat = 0; foreach (var strat in perm) { countStrat++; batchArgs.Console.WriteLine($"(Strategy {countStrat}/{perm.Count}) {strat}"); var ioc = new SolverContainerByType(new Dictionary <Type, Func <Type, object> >() { { typeof(ISolverPool), _ => PoolFactory(strat.Pool) }, { typeof(ISolverQueue), _ => new SolverQueueConcurrent() }, { typeof(ISolverRunTracking), _ => runTracking }, { typeof(ISokobanSolutionRepository), _ => solutionRepo }, }); var solverCommand = new SolverCommand { ServiceProvider = ioc, ExitConditions = new ExitConditions() { Duration = TimeSpan.FromMinutes(batchArgs.Min).Add(TimeSpan.FromSeconds(batchArgs.Sec)), MemAvail = DevHelper.GiB_1 / 2, // Stops the machine hanging / swapping to death StopOnSolution = true, }, AggProgress = new ConsoleProgressNotifier(repTele), CheckAbort = x => exitRequested, }; var runner = new SingleSolverBatchSolveComponent( new TextWriterAdapter(report), batchArgs.Console, solutionRepo, runTracking, 5, false); var solverInstance = SolverFactory(strat.Solver, ioc); var summary = runner.Run(run, solverCommand, solverInstance, false, batchArgs); results.Add((strat, summary)); } // Header var extras = new Dictionary <string, string>() { { "Args", args }, { "Report", info.FullName } }; DevHelper.WriteFullDevelopmentContext(report, extras); DevHelper.WriteFullDevelopmentContext(System.Console.Out, extras); // Body var reportRow = GenerateReport(results).ToList(); MapToReporting.Create <SummaryLine>() .AddColumn("Solver", x => x.Strategy.Solver) .AddColumn("Pool", x => x.Strategy.Pool) .AddColumn("Puzzle", x => x.Result.Puzzle.Ident) .AddColumn("State", x => x.Result.Exited) .AddColumn("Solutions", x => (x.Result.Solutions?.Count ?? 0) == 0 ? null : (int?)x.Result.Solutions.Count) .AddColumn("Statistics", x => x.Result.Exited == ExitConditions.Conditions.Error ? x.Result.Exited.ToString() : x.Result.Statistics?.ToString(false, true) ) .RenderTo(reportRow, new MapToReportingRendererText(), report) .RenderTo(reportRow, new MapToReportingRendererText(), System.Console.Out); return(results.Any(x => x.Item2.Any(y => y.Exited == ExitConditions.Conditions.Error)) ? -1 : 0); // All exceptions }
public List <SolverResultSummary> Run( SolverRun run, SolverCommand baseCommand, ISolver solver, bool showSummary, BatchSolveComponent.BatchArgs?batchArgs = null) { if (run == null) { throw new ArgumentNullException(nameof(run)); } if (baseCommand == null) { throw new ArgumentNullException(nameof(baseCommand)); } if (solver == null) { throw new ArgumentNullException(nameof(solver), "See: " + nameof(SingleThreadedForwardSolver)); } Report.WriteLine("Puzzle Exit Conditions: {0}", run.PuzzleExit); Report.WriteLine("Batch Exit Conditions : {0}", run.BatchExit); Report.WriteLine("Environment : {0}", DevHelper.RuntimeEnvReport()); Report.WriteLine("Solver Environment : v{0} -- {1}", SolverHelper.VersionUniversal, SolverHelper.VersionUniversalText); Report.WriteLine("Started : {0}", DateTime.Now.ToString("u")); Report.WriteLine(); var res = new List <SolverResultSummary>(); var start = new SolverStatistics { Started = DateTime.Now }; SolverState?state = null; var pp = 0; var consecutiveFails = 0; foreach (var puzzle in run) { if (baseCommand.CheckAbort(baseCommand)) { Progress.WriteLine("EXITING..."); break; } try { pp++; Progress.WriteLine($"(Puzzle {pp}/{run.Count}) Attempting: {puzzle.Ident} \"{puzzle.Name}\", R={StaticAnalysis.CalculateRating(puzzle.Puzzle)}. Stopping on [{baseCommand.ExitConditions}] ..."); Report.WriteLine(" Name: {0}", puzzle); Report.WriteLine(" Ident: {0}", puzzle.Ident); Report.WriteLine(" Rating: {0}", StaticAnalysis.CalculateRating(puzzle.Puzzle)); Report.WriteLine(puzzle.Puzzle.ToString()); // Adds 2x line feeds IReadOnlyCollection <SolutionDTO> existingSolutions = null; if (SkipPuzzlesWithSolutions && Repository != null) { existingSolutions = Repository.GetPuzzleSolutions(puzzle.Ident); if (existingSolutions != null && existingSolutions.Any( x => x.MachineName == Environment.MachineName && x.SolverType == solver.GetType().Name)) { Progress.WriteLine("Skipping... (SkipPuzzlesWithSolutions)"); continue; } } // #### Main Block Start -------------------------------------- var memStart = GC.GetTotalMemory(false); var attemptTimer = new Stopwatch(); attemptTimer.Start(); state = solver.Init(new SolverCommand(baseCommand) { Report = Report, Puzzle = puzzle.Puzzle }); var propsReport = GetPropReport(solver, state); Tracking?.Begin(state); try { solver.Solve(state); } catch (Exception e) { state.Exception = e; state.Exit = ExitConditions.Conditions.Error; state.EarlyExit = true; } var memEnd = GC.GetTotalMemory(false); state.Statistics.MemUsed = memEnd; var memDelta = memEnd - memStart; var bytesPerNode = memDelta / state.Statistics.TotalNodes; var maxNodes = (ulong)0; if (DevHelper.TryGetTotalMemory(out var totalMem)) { maxNodes = totalMem / (ulong)bytesPerNode; } Report.WriteLine($"Memory Used: {Humanise.SizeSuffix(memEnd)}, delta: {Humanise.SizeSuffix(memDelta)} ~ {bytesPerNode:#,##0} bytes/node => max nodes:{maxNodes:#,##0}"); attemptTimer.Stop(); // #### Main Block End ------------------------------------------ state.Summary = new SolverResultSummary( puzzle, state.Solutions, state.Exit, SolverHelper.GenerateSummary(state), attemptTimer.Elapsed, state.Statistics ); res.Add(state.Summary); start.TotalNodes += state.Statistics.TotalNodes; start.TotalDead += state.Statistics.TotalDead; Report.WriteLine("[DONE] {0}", state.Summary.Text); Progress.WriteLine($" -> {state.Summary.Text}"); if (batchArgs != null && batchArgs.Save != null) { Console.WriteLine(" -> Saving..."); var binSer = new BinaryNodeSerializer(); var rootForward = state.GetRootForward(); if (rootForward != null) { var outState = System.IO.Path.Combine(batchArgs.Save, $"{puzzle.Ident}-forward.ssbn"); using (var f = File.Create(outState)) { using (var bw = new BinaryWriter(f)) { binSer.WriteTree(bw, rootForward); } } Report.WriteLine($"\tSaving State: {outState}"); Progress.WriteLine($"\tSaving State: {outState}"); } var rootReverse = state.GetRootReverse(); if (rootReverse != null) { var outState = System.IO.Path.Combine(batchArgs.Save, $"{puzzle.Ident}-reverse.ssbn"); using (var f = File.Create(outState)) { using (var bw = new BinaryWriter(f)) { binSer.WriteTree(bw, rootReverse); } } Report.WriteLine($"\tSaving State: {outState}"); Progress.WriteLine($"\tSaving State: {outState}"); } } // Add Depth Reporting Console.WriteLine(" -> Generating Reports..."); GenerateReports(state, solver); if (Repository != null) { var id = StoreAttempt(solver, puzzle, state, propsReport.ToString()); if (id >= 0) { var solTxt = $"Checking against known solutions. SolutionId={id}"; Report.WriteLine(solTxt); Console.WriteLine(solTxt); } } else { Report.WriteLine($"Solution Repository not available: Skipping."); } if (state?.Summary?.Solutions != null && state.Summary.Solutions.Any()) // May have been removed above { consecutiveFails = 0; } else { consecutiveFails++; if (StopOnConsecutiveFails != 0 && consecutiveFails > StopOnConsecutiveFails) { Progress.WriteLine("ABORTING... StopOnConsecutiveFails"); break; } } Tracking?.End(state); if (state.Exception != null) { Report.WriteLine("[EXCEPTION]"); WriteException(Report, state.Exception); } if (state.Exit == ExitConditions.Conditions.Aborted) { Progress.WriteLine("ABORTING..."); if (showSummary) { WriteSummary(res, start); } return(res); } if (start.DurationInSec > run.BatchExit.Duration.TotalSeconds) { Progress.WriteLine("BATCH TIMEOUT..."); if (showSummary) { WriteSummary(res, start); } return(res); } Progress.WriteLine(); } catch (Exception ex) { if (state != null) { state.Exception = ex; } Progress.WriteLine("ERROR: " + ex.Message); WriteException(Report, ex); } finally { state = null; if (puzzle != run.Last()) { GC.Collect(); } } } if (showSummary) { WriteSummary(res, start); } Report.WriteLine("Completed : {0}", DateTime.Now.ToString("u")); return(res); }