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    }