aima.core.search.uninformed.IterativeDeepeningSearch Maven / Gradle / Ivy
package aima.core.search.uninformed;
import java.util.List;
import aima.core.agent.Action;
import aima.core.search.framework.Metrics;
import aima.core.search.framework.Node;
import aima.core.search.framework.NodeExpander;
import aima.core.search.framework.SearchForActions;
import aima.core.search.framework.SearchForStates;
import aima.core.search.framework.SearchUtils;
import aima.core.search.framework.problem.Problem;
import aima.core.util.CancelableThread;
/**
* Artificial Intelligence A Modern Approach (3rd Edition): Figure 3.18, page
* 89.
*
*
*
* function ITERATIVE-DEEPENING-SEARCH(problem) returns a solution, or failure
* for depth = 0 to infinity do
* result <- DEPTH-LIMITED-SEARCH(problem, depth)
* if result != cutoff then return result
*
*
* Figure 3.18 The iterative deepening search algorithm, which repeatedly
* applies depth-limited search with increasing limits. It terminates when a
* solution is found or if the depth- limited search returns failure, meaning
* that no solution exists.
*
* @author Ravi Mohan
* @author Ciaran O'Reilly
* @author Ruediger Lunde
*/
public class IterativeDeepeningSearch implements SearchForActions, SearchForStates {
public static final String METRIC_NODES_EXPANDED = "nodesExpanded";
public static final String METRIC_PATH_COST = "pathCost";
private final NodeExpander nodeExpander;
private final Metrics metrics;
public IterativeDeepeningSearch() {
this(new NodeExpander());
}
public IterativeDeepeningSearch(NodeExpander nodeExpander) {
this.nodeExpander = nodeExpander;
this.metrics = new Metrics();
}
// function ITERATIVE-DEEPENING-SEARCH(problem) returns a solution, or
// failure
@Override
public List findActions(Problem p) {
nodeExpander.useParentLinks(true);
Node node = findNode(p);
return node == null ? SearchUtils.failure() : SearchUtils.getSequenceOfActions(node);
}
@Override
public Object findState(Problem p) {
nodeExpander.useParentLinks(false);
Node node = findNode(p);
return node == null ? null : node.getState();
}
// Java 8: Use Optional as return value...
private Node findNode(Problem p) {
clearInstrumentation();
// for depth = 0 to infinity do
for (int i = 0; !CancelableThread.currIsCanceled(); i++) {
// result <- DEPTH-LIMITED-SEARCH(problem, depth)
DepthLimitedSearch dls = new DepthLimitedSearch(i, nodeExpander);
Node result = dls.findNode(p);
updateMetrics(dls.getMetrics());
// if result != cutoff then return result
if (result != DepthLimitedSearch.CUTOFF_NODE)
return result;
}
return null;
}
@Override
public NodeExpander getNodeExpander() {
return nodeExpander;
}
@Override
public Metrics getMetrics() {
return metrics;
}
/**
* Sets the nodes expanded and path cost metrics to zero.
*/
private void clearInstrumentation() {
metrics.set(METRIC_NODES_EXPANDED, 0);
metrics.set(METRIC_PATH_COST, 0);
}
//
// PRIVATE METHODS
//
private void updateMetrics(Metrics dlsMetrics) {
metrics.set(METRIC_NODES_EXPANDED,
metrics.getInt(METRIC_NODES_EXPANDED) + dlsMetrics.getInt(METRIC_NODES_EXPANDED));
metrics.set(METRIC_PATH_COST, dlsMetrics.getDouble(METRIC_PATH_COST));
}
}