// optimal cost of -1 represents no solution! private void TestSolver <TProblemState>(ISearchAlgorithm <TProblemState> solver, IProblem <TProblemState> problem, double optimalCost) where TProblemState : IProblemState <TProblemState> { output.WriteLine(solver.ToString()); var timer = new Stopwatch(); double lastTotalS = 0d; ulong lastEvals = 0UL; // https://docs.microsoft.com/en-us/dotnet/api/system.timers.timer?view=netframework-4.7.2 var reportingTimer = new Timer(10_000); Action reportingHeartbeat = () => { var currentTotalS = timer.Elapsed.TotalSeconds; var currentEvals = solver.StatesEvaluated; var statesPerSecond = (currentEvals - lastEvals) / (currentTotalS - lastTotalS); output.WriteLine($"evals: {solver.StatesEvaluated:#,0} ms: {timer.Elapsed.TotalMilliseconds} S/s: {statesPerSecond:#,#.###} cost: {solver.MaxCostEvaulated}"); lastTotalS = currentTotalS; lastEvals = currentEvals; }; reportingTimer.Elapsed += (Object source, ElapsedEventArgs e) => reportingHeartbeat(); reportingTimer.AutoReset = true; reportingTimer.Enabled = true; timer.Start(); var solution = solver.Solve(problem); timer.Stop(); reportingTimer.Enabled = false; reportingHeartbeat(); output.WriteLine("Time: {0}", timer.Elapsed); if (solution == null) { Assert.True(optimalCost == -1d, "Found no solution but one should exist."); } else { var state = problem.GetInitialState(); output.WriteLine("Initial State ----------------"); output.WriteLine(state.ToString()); int i = 0; double stepCost, totalCost = 0d; foreach (var move in solution) { i++; (state, stepCost) = problem.ApplyAction(state, move); totalCost += stepCost; //output.WriteLine(state.ToString()); } output.WriteLine("Final State ({0} moves, {1} cost) ----------------", i, totalCost); output.WriteLine(state.ToString()); Assert.True(problem.IsGoal(state), "Non-goal state claimed to be goal."); Assert.True(Math.Abs(optimalCost - totalCost) < 1e-8, "Found a non optimal cost: expected = " + optimalCost + "; actual = " + totalCost); } }
public IProblemAction[] Solve(IProblem <TState> problem) { StatesEvaluated = 0UL; MaxCostEvaulated = 0; var openSet = new OpenSet <double, StateCost <TState> >(); var closedSet = new HashSet <TState>(); var cameFrom = new Dictionary <TState, (TState parent, IProblemAction move)>(); var initialState = problem.GetInitialState(); openSet.PushOrImprove(0, new StateCost <TState>(initialState, 0)); cameFrom.Add(initialState, (default(TState), null)); while (!openSet.IsEmpty) { var next = openSet.PopMin(); var state = next.State; var cost = next.Cost; closedSet.Add(state); StatesEvaluated++; MaxCostEvaulated = Math.Max(MaxCostEvaulated, cost); if (problem.IsGoal(state)) { return(RebuildSolution(cameFrom, state)); } foreach (var move in problem.Expand(state)) { var(successor, stepCost) = problem.ApplyAction(state, move); if (closedSet.Contains(successor)) { continue; } var wasImprovement = openSet.PushOrImprove( cost + stepCost + heuristic(successor), new StateCost <TState>(successor, cost + stepCost) ); if (wasImprovement) { cameFrom[successor] = (state, move); } } } return(null); }
public IProblemAction[] Solve(IProblem <TState> problem) { StatesEvaluated = 0UL; MaxCostEvaulated = 0; var openSet = new OpenSet <double, StateCost <TState> >(); var closedSet = new HashSet <TState>(); var cameFrom = new Dictionary <TState, (TState parent, IProblemAction move)>(); var initialState = problem.GetInitialState(); openSet.PushOrImprove(0, new StateCost <TState>(initialState, 0)); cameFrom.Add(initialState, (default(TState), null)); while (!openSet.IsEmpty) { var stateCost = openSet.PopMin(); var state = stateCost.State; var cost = stateCost.Cost; closedSet.Add(state); StatesEvaluated++; MaxCostEvaulated = Math.Max(MaxCostEvaulated, cost); if (problem.IsGoal(state)) { return(RebuildSolution(cameFrom, state)); } foreach (var move in problem.Expand(state)) { var(successor, stepCost) = problem.ApplyAction(state, move); if (closedSet.Contains(successor)) { continue; } // why is this 1 and not step cost? because that's how we enforce // the BFS property of exploring on level fully before starting the next var wasImprovement = openSet.PushOrImprove(cost + 1, new StateCost <TState>(successor, cost + 1)); if (wasImprovement) { cameFrom[successor] = (state, move); } } } return(null); }
private double Search(TState state, TState parent, double pathCost, Stack <IProblemAction> path, double bound) { var f = pathCost + heuristic(state); StatesEvaluated++; if (f > bound) { return(f); } if (problem.IsGoal(state)) { return(FOUND); } var min = double.MaxValue; var actions = problem.Expand(state); foreach (var action in actions) { var(successor, stepCost) = problem.ApplyAction(state, action); var successorPathCost = pathCost + stepCost; // TODO: so many assumptions here if (successor.Equals(parent)) { continue; } path.Push(action); var result = Search(successor, state, successorPathCost, path, bound); if (result == FOUND) { return(FOUND); } min = Math.Min(min, result); path.Pop(); } return(min); }