private double getValue(Node n) { // assumption greater heuristic value => // HIGHER on hill; 0 == goal state; return -1 * hf.h(n.getState()); }
// function HILL-CLIMBING(problem) returns a state that is a local maximum public List<Action> search(Problem p) { clearInstrumentation(); outcome = SearchOutcome.FAILURE; lastState = null; // current <- MAKE-NODE(problem.INITIAL-STATE) Node current = new Node(p.getInitialState()); Node neighbor = null; // loop do while (!CancelableThread.currIsCanceled()) { List<Node> children = expandNode(current, p); // neighbor <- a highest-valued successor of current neighbor = getHighestValuedNodeFrom(children, p); // if neighbor.VALUE <= current.VALUE then return current.STATE if ((neighbor == null) || (getValue(neighbor) <= getValue(current))) { if (SearchUtils.isGoalState(p, current)) { outcome = SearchOutcome.SOLUTION_FOUND; } lastState = current.getState(); return SearchUtils.actionsFromNodes(current.getPathFromRoot()); } // current <- neighbor current = neighbor; } return new List<Action>(); }
public override bool removeNodeFromFrontier(Node toRemove) { bool removed = base.removeNodeFromFrontier(toRemove); if (removed) { frontierState.Remove(toRemove.getState()); } return removed; }
public void testRootNode() { Node node1 = new Node("state1"); Assert.IsTrue(node1.isRootNode()); Node node2 = new Node("state2", node1, null, 1.0); Assert.IsTrue(node1.isRootNode()); Assert.IsFalse(node2.isRootNode()); Assert.AreEqual(node1, node2.getParent()); }
public void testGetPathFromRoot() { Node node1 = new Node("state1"); Node node2 = new Node("state2", node1, null, 1.0); Node node3 = new Node("state3", node2, null, 1.0); List<Node> path = node3.getPathFromRoot(); Assert.Equals(node1, path[0]); Assert.Equals(node2, path[1]); Assert.Equals(node3, path[2]); }
/** * * @param problem * @param frontier * @return if goal found, the list of actions to the Goal. If already at the * goal you will receive a List with a single NoOp Action in it. If * fail to find the Goal, an empty list will be returned to indicate * that the search failed. */ public virtual List<Action> search(Problem problem, Queue<Node> frontier) { this.frontier = frontier; clearInstrumentation(); // initialize the frontier using the initial state of the problem Node root = new Node(problem.getInitialState()); if (isCheckGoalBeforeAddingToFrontier()) { if (SearchUtils.isGoalState(problem, root)) { return SearchUtils.actionsFromNodes(root.getPathFromRoot()); } } frontier.Enqueue(root); setQueueSize(frontier.Count); while (!(frontier.Count==0)) { // choose a leaf node and remove it from the frontier Node nodeToExpand = popNodeFromFrontier(); setQueueSize(frontier.Count); // Only need to check the nodeToExpand if have not already // checked before adding to the frontier if (!isCheckGoalBeforeAddingToFrontier()) { // if the node contains a goal state then return the // corresponding solution if (SearchUtils.isGoalState(problem, nodeToExpand)) { setPathCost(nodeToExpand.getPathCost()); return SearchUtils.actionsFromNodes(nodeToExpand .getPathFromRoot()); } } // expand the chosen node, adding the resulting nodes to the // frontier foreach (Node fn in getResultingNodesToAddToFrontier(nodeToExpand, problem)) { if (isCheckGoalBeforeAddingToFrontier()) { if (SearchUtils.isGoalState(problem, fn)) { setPathCost(fn.getPathCost()); return SearchUtils.actionsFromNodes(fn .getPathFromRoot()); } } frontier.Enqueue(fn); } setQueueSize(frontier.Count); } // if the frontier is empty then return failure return failure(); }
// function RECURSIVE-BEST-FIRST-SEARCH(problem) returns a solution, or // failure public List<Action> search(Problem p) { List<Action> actions = new List<Action>(); clearInstrumentation(); // RBFS(problem, MAKE-NODE(INITIAL-STATE[problem]), infinity) Node n = new Node(p.getInitialState()); SearchResult sr = rbfs(p, n, evaluationFunction.f(n), INFINITY, 0); if (sr.getOutcome() == SearchResult.SearchOutcome.SOLUTION_FOUND) { Node s = sr.getSolution(); actions = SearchUtils.actionsFromNodes(s.getPathFromRoot()); setPathCost(s.getPathCost()); } // Empty List can indicate already at Goal // or unable to find valid set of actions return actions; }
public override List<Node> getResultingNodesToAddToFrontier(Node nodeToExpand, Problem problem) { addToFrontier.Clear(); // add the node to the explored set explored.Add(nodeToExpand.getState()); // expand the chosen node, adding the resulting nodes to the frontier foreach (Node cfn in expandNode(nodeToExpand, problem)) { Node frontierNode = frontierState[cfn.getState()]; bool yesAddToFrontier = false; // only if not in the frontier or explored set if (null == frontierNode && !explored.Contains(cfn.getState())) { yesAddToFrontier = true; } else if (null != frontierNode && null != replaceFrontierNodeAtStateCostFunction && replaceFrontierNodeAtStateCostFunction.Compare(cfn, frontierNode) < 0) { // child.STATE is in frontier with higher cost // replace that frontier node with child yesAddToFrontier = true; // Want to replace the current frontier node with the child // node therefore mark the child to be added and remove the // current fontierNode removeNodeFromFrontier(frontierNode); // Ensure removed from add to frontier as well // as 1 or more may reach the same state at the same time addToFrontier.Remove(frontierNode); } if (yesAddToFrontier) { addToFrontier.Add(cfn); frontierState.Add(cfn.getState(), cfn); } } return addToFrontier; }
public static bool isGoalState(Problem p, Node n) { bool isGoal = false; GoalTest gt = p.getGoalTest(); if (gt.isGoalState(n.getState())) { if (gt is SolutionChecker) { isGoal = ((SolutionChecker)gt).isAcceptableSolution( SearchUtils.actionsFromNodes(n.getPathFromRoot()), n .getState()); } else { isGoal = true; } } return isGoal; }
public List<Node> expandNode(Node node, Problem problem) { List<Node> childNodes = new List<Node>(); ActionsFunction actionsFunction = problem.getActionsFunction(); ResultFunction resultFunction = problem.getResultFunction(); StepCostFunction stepCostFunction = problem.getStepCostFunction(); foreach (Action action in actionsFunction.actions(node.getState())) { System.Object successorState = resultFunction.result(node.getState(), action); double stepCost = stepCostFunction.c(node.getState(), action, successorState); childNodes.Add(new Node(successorState, node, action, stepCost)); } metrics.set(METRIC_NODES_EXPANDED, metrics .getInt(METRIC_NODES_EXPANDED) + 1); return childNodes; }
// function SIMULATED-ANNEALING(problem, schedule) returns a solution state public List<Action> search(Problem p) { clearInstrumentation(); outcome = SearchOutcome.FAILURE; lastState = null; // current <- MAKE-NODE(problem.INITIAL-STATE) Node current = new Node(p.getInitialState()); Node next = null; List<Action> ret = new List<Action>(); // for t = 1 to INFINITY do int timeStep = 0; while (!CancelableThread.currIsCanceled()) { // temperature <- schedule(t) double temperature = scheduler.getTemp(timeStep); timeStep++; // if temperature = 0 then return current if (temperature == 0.0) { if (SearchUtils.isGoalState(p, current)) { outcome = SearchOutcome.SOLUTION_FOUND; } ret = SearchUtils.actionsFromNodes(current.getPathFromRoot()); lastState = current.getState(); break; } List<Node> children = expandNode(current, p); if (children.Count > 0) { // next <- a randomly selected successor of current next = Util.selectRandomlyFromList(children); // /\E <- next.VALUE - current.value double deltaE = getValue(p, next) - getValue(p, current); if (shouldAccept(temperature, deltaE)) { current = next; } } } return ret; }
public double f(Node n) { // f(n) = g(n) + h(n) return gf.g(n) + hf.h(n.getState()); }
public abstract List<Node> getResultingNodesToAddToFrontier( Node nodeToExpand, Problem p);
public virtual bool removeNodeFromFrontier(Node toRemove) { return false; // TODO }
private double getValue(Problem p, Node n) { // assumption greater heuristic value => // HIGHER on hill; 0 == goal state; // SA deals with gardient DESCENT return -1 * hf.h(n.getState()); }
public Node(System.Object state, Node parent, Action action, double stepCost) : this(state) { this.parent = parent; this.action = action; this.pathCost = parent.pathCost + stepCost; }
/** * * @param n * @return the cost, traditionally denoted by g(n), of the path from the * initial state to the node, as indicated by the parent pointers. */ public double g(Node n) { return n.getPathCost(); }
// // PRIVATE METHODS // // function RBFS(problem, node, f_limit) returns a solution, or failure and // a new f-cost limit private SearchResult rbfs(Problem p, Node n, double node_f, double fLimit, int recursiveDepth) { setMaxRecursiveDepth(recursiveDepth); // if problem.GOAL-TEST(node.STATE) then return SOLUTION(node) if (SearchUtils.isGoalState(p, n)) { return new SearchResult(n, fLimit); } // successors <- [] // for each action in problem.ACTION(node.STATE) do // add CHILD-NODE(problem, node, action) into successors List<Node> successors = expandNode(n, p); // if successors is empty then return failure, infinity if (0 == successors.Count) { return new SearchResult(null, INFINITY); } double[] f = new double[successors.Count]; // for each s in successors do // update f with value from previous search, if any int size = successors.Count; for (int s = 0; s < size; s++) { // s.f <- max(s.g + s.h, node.f) f[s] = Math.max(evaluationFunction.f(successors.get(s)), node_f); } // repeat while (true) { // best <- the lowest f-value node in successors int bestIndex = getBestFValueIndex(f); // if best.f > f_limit then return failure, best.f if (f[bestIndex] > fLimit) { return new SearchResult(null, f[bestIndex]); } // if best.f > f_limit then return failure, best.f int altIndex = getNextBestFValueIndex(f, bestIndex); // result, best.f <- RBFS(problem, best, min(f_limit, alternative)) SearchResult sr = rbfs(p, successors.get(bestIndex), f[bestIndex], Math.min(fLimit, f[altIndex]), recursiveDepth + 1); f[bestIndex] = sr.getFCostLimit(); // if result != failure then return result if (sr.getOutcome() == SearchResult.SearchOutcome.SOLUTION_FOUND) { return sr; } } }
public double f(Node n) { // f(n) = h(n) return hf.h(n.getState()); }
public override List<Node> getResultingNodesToAddToFrontier(Node nodeToExpand, Problem problem) { // expand the chosen node, adding the resulting nodes to the frontier return expandNode(nodeToExpand, problem); }
// // PRIVATE METHODS // // function RECURSIVE-DLS(node, problem, limit) returns a solution, or // failure/cutoff private List<Action> recursiveDLS(Node node, Problem problem, int limit) { // if problem.GOAL-TEST(node.STATE) then return SOLUTION(node) if (SearchUtils.isGoalState(problem, node)) { setPathCost(node.getPathCost()); return SearchUtils.actionsFromNodes(node.getPathFromRoot()); } else if (0 == limit) { // else if limit = 0 then return cutoff return cutoff(); } else { // else // cutoff_occurred? <- false bool cutoff_occurred = false; // for each action in problem.ACTIONS(node.STATE) do foreach (Node child in this.expandNode(node, problem)) { // child <- CHILD-NODE(problem, node, action) // result <- RECURSIVE-DLS(child, problem, limit - 1) List<Action> result = recursiveDLS(child, problem, limit - 1); // if result = cutoff then cutoff_occurred? <- true if (isCutOff(result)) { cutoff_occurred = true; } else if (!isFailure(result)) { // else if result != failure then return result return result; } } // if cutoff_occurred? then return cutoff else return failure if (cutoff_occurred) { return cutoff(); } else { return failure(); } } }
public SearchResult(Node solution, Double fCostLimit) { if (null == solution) { this.outcome = SearchOutcome.FAILURE; } else { this.outcome = SearchOutcome.SOLUTION_FOUND; this.solution = solution; } this.fCostLimit = fCostLimit; }