001 package aima.search.framework; 002 003 import java.util.HashSet; 004 import java.util.List; 005 import java.util.Set; 006 007 /** 008 * @author Ravi Mohan 009 * 010 */ 011 012 /** 013 * Artificial Intelligence A Modern Approach (2nd Edition): Figure 3.19, page 014 * 83. <code> 015 * function GRAPH-SEARCH(problem, fringe) returns a solution, or failure 016 * 017 * closed <- an empty set 018 * fringe <- INSERT(MAKE-NODE(INITIAL-STATE[problem]), fringe) 019 * loop do 020 * if EMPTY?(fringe) then return failure 021 * node <- REMOVE-FIRST(fringe) 022 * if (GOAL-TEST[problem](STATE[node]) then return SOLUTION(node) 023 * if STATE[node] is not in closed then 024 * add STATE[node] to closed 025 * fringe <- INSERT-ALL(EXPAND(node, problem), fringe) 026 * </code> 027 * Figure 3.19 The general graph-search algorithm, The set closed can be 028 * implemented with a hash table to allow efficient checking for repeated 029 * states. This algorithm assumes that the first path to a state s is the 030 * cheapest (see text). 031 */ 032 033 public class GraphSearch extends QueueSearch { 034 035 Set<Object> closed = new HashSet<Object>(); 036 037 // Need to override search() method so that I can re-initialize 038 // the closed list should multiple calls to search be made. 039 @Override 040 public List<String> search(Problem problem, NodeStore fringe) { 041 closed.clear(); 042 return super.search(problem, fringe); 043 } 044 045 @Override 046 public void addExpandedNodesToFringe(NodeStore fringe, Node node, 047 Problem problem) { 048 049 // if STATE[node] is not in closed then 050 if (!(alreadySeen(node))) { 051 // add STATE[node] to closed 052 closed.add(node.getState()); 053 // fringe <- INSERT-ALL(EXPAND(node, problem), fringe) 054 fringe.add(expandNode(node, problem)); 055 056 } 057 } 058 059 private boolean alreadySeen(Node node) { 060 return closed.contains(node.getState()); 061 } 062 }