001 /* 002 * Created on Sep 8, 2004 003 * 004 */ 005 package aima.search.uninformed; 006 007 import java.util.ArrayList; 008 import java.util.List; 009 010 import aima.search.framework.Node; 011 import aima.search.framework.NodeExpander; 012 import aima.search.framework.Problem; 013 import aima.search.framework.Search; 014 import aima.search.framework.SearchUtils; 015 016 /** 017 * Artificial Intelligence A Modern Approach (2nd Edition): Figure 3.13, page 018 * 77. 019 * 020 * <code> 021 * function DEPTH-LIMITED-SEARCH(problem, limit) returns a solution, or failure/cutoff 022 * return RECURSIVE-DLS(MAKE-NODE(INITIAL-STATE[problem]), problem, limit) 023 * 024 * function RECURSIVE-DLS(node, problem, limit) returns a solution, or failure/cutoff 025 * cutoff_occurred? <- false 026 * if GOAL-TEST[problem](STATE[node]) then return SOLUTION(node) 027 * else if DEPTH[node] = limit then return cutoff 028 * else for each successor in EXPAND(node, problem) do 029 * result <- RECURSIVE-DLS(successor, problem, limit) 030 * if result = cutoff then cutoff_occurred? <- true 031 * else if result != failure then return result 032 * if cutoff_occurred? then return cutoff else return failure 033 * </code> 034 * Figure 3.13 A recursive implementation of depth-limited search. 035 */ 036 037 /** 038 * @author Ravi Mohan 039 * 040 */ 041 public class DepthLimitedSearch extends NodeExpander implements Search { 042 private static String PATH_COST = "pathCost"; 043 044 private final int limit; 045 046 public DepthLimitedSearch(int limit) { 047 this.limit = limit; 048 049 } 050 051 // function DEPTH-LIMITED-SEARCH(problem, limit) returns a solution, or 052 // failure/cutoff 053 public List search(Problem p) throws Exception { 054 clearInstrumentation(); 055 // return RECURSIVE-DLS(MAKE-NODE(INITIAL-STATE[problem]), problem, 056 // limit) 057 return recursiveDLS(new Node(p.getInitialState()), p, limit); 058 } 059 060 // function RECURSIVE-DLS(node, problem, limit) returns a solution, or 061 // failure/cutoff 062 private List recursiveDLS(Node node, Problem problem, int limit) { 063 // cutoff_occurred? <- false 064 boolean cutOffOccured = false; 065 // if GOAL-TEST[problem](STATE[node]) then return SOLUTION(node) 066 if (problem.isGoalState(node.getState())) { 067 setPathCost(node.getPathCost()); 068 return SearchUtils.actionsFromNodes(node.getPathFromRoot()); 069 // else if DEPTH[node] = limit then return cutoff 070 } else if (node.getDepth() == limit) { 071 return createCutOffResult(); 072 } else { 073 // else for each successor in EXPAND(node, problem) do 074 List children = expandNode(node, problem); 075 for (int i = 0; i < children.size(); i++) { 076 Node child = (Node) children.get(i); 077 // result <- RECURSIVE-DLS(successor, problem, limit) 078 List result = recursiveDLS(child, problem, limit); 079 // if result = cutoff then cutoff_occurred? <- true 080 if (cutoffResult(result)) { 081 cutOffOccured = true; 082 // else if result != failure then return result 083 } else if (!(failure(result))) { 084 return result; 085 } 086 } 087 // if cutoff_occurred? then return cutoff else return failure 088 if (cutOffOccured) { 089 return createCutOffResult(); 090 } else { 091 return new ArrayList(); 092 } 093 094 } 095 096 } 097 098 @Override 099 public void clearInstrumentation() { 100 super.clearInstrumentation(); 101 metrics.set(PATH_COST, 0); 102 } 103 104 public double getPathCost() { 105 return metrics.getDouble(PATH_COST); 106 } 107 108 public void setPathCost(Double pathCost) { 109 metrics.set(PATH_COST, pathCost); 110 } 111 112 private boolean failure(List result) { 113 114 return result.size() == 0; 115 } 116 117 private boolean cutoffResult(List result) { 118 119 return result.size() == 1 && result.get(0).equals("cutoff"); 120 } 121 122 private List createCutOffResult() { 123 List result = new ArrayList(); 124 result.add("cutoff"); 125 return result; 126 } 127 128 }