diff --git a/core/src/main/java/aima/core/search/basic/uninformed/GraphSearch.java b/core/src/main/java/aima/core/search/basic/uninformed/GraphSearch.java
index 4a42f267f0..3a81d56d99 100644
--- a/core/src/main/java/aima/core/search/basic/uninformed/GraphSearch.java
+++ b/core/src/main/java/aima/core/search/basic/uninformed/GraphSearch.java
@@ -1,19 +1,11 @@
package aima.core.search.basic.uninformed;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Queue;
-import java.util.Set;
-
-import aima.core.search.api.Node;
-import aima.core.search.api.NodeFactory;
-import aima.core.search.api.Problem;
-import aima.core.search.api.SearchController;
-import aima.core.search.api.SearchForActionsFunction;
+import aima.core.search.api.*;
import aima.core.search.basic.support.BasicNodeFactory;
import aima.core.search.basic.support.BasicSearchController;
+import java.util.*;
+
/**
* Artificial Intelligence A Modern Approach (4th Edition): Figure ??, page ??.
*
@@ -31,84 +23,84 @@
* expand the chosen node, adding the resulting nodes to the frontier
* only if not in the frontier or explored set
*
- *
+ *
* Figure ?? An informal description of the general graph-search algorithm.
*
- *
* @author Ciaran O'Reilly
*/
public class GraphSearch implements SearchForActionsFunction {
-
+
+ protected NodeFactory nodeFactory = new BasicNodeFactory<>();
+ protected SearchController searchController = new BasicSearchController();
+
+ public GraphSearch() {
+ //empty constructor
+ }
+
// function GRAPH-SEARCH(problem) returns a solution, or failure
@Override
public List apply(Problem problem) {
// initialize the frontier using the initial state of problem
Queue explored = newExploredSet();
+ // initialize the reached table to be empty
+ Map> reached = new HashMap<>();
+ // initialize the solution
+ List solution = failure();
+
+ // if the frontier is empty then return failure
+ if (frontier.isEmpty()) {
+ return failure();
+ }
// loop do
- while (true) {
- // if the frontier is empty then return failure
- if (frontier.isEmpty()) {
- return failure();
- }
+ while (!frontier.isEmpty()) {
// choose a leaf node and remove it from the frontier
- Node node = frontier.remove();
- // if the node contains a goal state then return the corresponding
- // solution
- if (isGoalState(node, problem)) {
- return solution(node);
- }
- // add the node to the explored set
- explored.add(node.state());
- // expand the chosen node, adding the resulting nodes to the
- // frontier
- for (A action : problem.actions(node.state())) {
- Node child = newChildNode(problem, node, action);
- // only if not in the frontier or explored set
- if (!(containsState(frontier, child) || explored.contains(child.state()))) {
+ Node parent = frontier.remove();
+ // expand the chosen node
+ for (Node child : expand(problem, parent)) {
+ // only if the child is not in reached or child is a cheaper path than reached[child.state()]
+ if (!reached.containsKey(child.state()) || child.pathCost() < reached.get(child.state()).pathCost()) {
+ // add child in reached and frontier
+ reached.put(child.state(), child);
frontier.add(child);
+ // if child is a goal and is cheaper than the best solution found so far then update the solution
+ if (isGoalState(child, problem)) {
+ solution = getSolution(child);
+ }
}
}
}
+ return solution;
}
-
- //
- // Supporting Code
- protected NodeFactory nodeFactory = new BasicNodeFactory<>();
- protected SearchController searchController = new BasicSearchController();
-
- public GraphSearch() {
+
+ public List newExploredSet() {
- return new HashSet<>();
- }
-
+
public List failure() {
return searchController.failure();
}
-
- public List solution(Node node) {
+
+ public List getSolution(Node node) {
return searchController.solution(node);
}
-
+
public boolean isGoalState(Node node, Problem problem) {
return searchController.isGoalState(node, problem);
}
-
- public boolean containsState(Queue