001 /* 002 * Created on Sep 14, 2004 003 * 004 */ 005 package aima.search.informed; 006 007 import java.util.ArrayList; 008 import java.util.List; 009 import java.util.Random; 010 011 import aima.search.framework.Node; 012 import aima.search.framework.NodeExpander; 013 import aima.search.framework.Problem; 014 import aima.search.framework.Search; 015 import aima.search.framework.SearchUtils; 016 import aima.util.Util; 017 018 /** 019 * Artificial Intelligence A Modern Approach (2nd Edition): Figure 4.14, page 020 * 116. 021 * 022 * <code> 023 * function SIMULATED-ANNEALING(problem, schedule) returns a solution state 024 * inputs: problem, a problem 025 * schedule, a mapping from time to "temperature" 026 * local variables: current, a node 027 * next, a node 028 * T, a "temperature" controlling the probability of downward steps 029 * 030 * current <- MAKE-NODE(INITIAL-STATE[problem]) 031 * for t <- 1 to INFINITY do 032 * T <- schedule[t] 033 * if T = 0 then return current 034 * next <- a randomly selected successor of current 035 * /\E <- VALUE[next] - VALUE[current] 036 * if /\E > 0 then current <- next 037 * else current <- next only with probablity e^(/\E/T) 038 * </code> 039 * Figure 4.14 The simulated annealing search algorithm, a version of the 040 * stochastic hill climbing where some downhill moves are allowed. Downhill 041 * moves are accepted readily early in the annealing schedule and then less 042 * often as time goes on. The schedule input determines the value of T as a 043 * function of time. 044 */ 045 046 /** 047 * @author Ravi Mohan 048 * 049 */ 050 public class SimulatedAnnealingSearch extends NodeExpander implements Search { 051 052 public enum SearchOutcome { 053 FAILURE, SOLUTION_FOUND 054 }; 055 056 private final Scheduler scheduler; 057 058 private SearchOutcome outcome = SearchOutcome.FAILURE; 059 060 private Object lastState = null; 061 062 public SimulatedAnnealingSearch() { 063 this.scheduler = new Scheduler(); 064 } 065 066 // function SIMULATED-ANNEALING(problem, schedule) returns a solution state 067 // inputs: problem, a problem 068 // schedule, a mapping from time to "temperature" 069 public List<String> search(Problem p) throws Exception { 070 // local variables: current, a node 071 // next, a node 072 // T, a "temperature" controlling the probability of downward steps 073 clearInstrumentation(); 074 outcome = SearchOutcome.FAILURE; 075 lastState = null; 076 // current <- MAKE-NODE(INITIAL-STATE[problem]) 077 Node current = new Node(p.getInitialState()); 078 Node next = null; 079 List<String> ret = new ArrayList<String>(); 080 // for t <- 1 to INFINITY do 081 int timeStep = 0; 082 while (true) { 083 // temperature <- schedule[t] 084 double temperature = scheduler.getTemp(timeStep); 085 timeStep++; 086 // if temperature = 0 then return current 087 if (temperature == 0.0) { 088 if (p.isGoalState(current.getState())) { 089 outcome = SearchOutcome.SOLUTION_FOUND; 090 } 091 ret = SearchUtils.actionsFromNodes(current.getPathFromRoot()); 092 lastState = current.getState(); 093 break; 094 } 095 096 List<Node> children = expandNode(current, p); 097 if (children.size() > 0) { 098 // next <- a randomly selected successor of current 099 next = Util.selectRandomlyFromList(children); 100 // /\E <- VALUE[next] - VALUE[current] 101 double deltaE = getValue(p, next) - getValue(p, current); 102 103 if (shouldAccept(temperature, deltaE)) { 104 current = next; 105 } 106 } 107 } 108 109 return ret; 110 } 111 112 // if /\E > 0 then current <- next 113 // else current <- next only with probablity e^(/\E/T) 114 private boolean shouldAccept(double temperature, double deltaE) { 115 return (deltaE > 0.0) 116 || (new Random().nextDouble() <= probabilityOfAcceptance( 117 temperature, deltaE)); 118 } 119 120 public double probabilityOfAcceptance(double temperature, double deltaE) { 121 return Math.exp(deltaE / temperature); 122 } 123 124 public SearchOutcome getOutcome() { 125 return outcome; 126 } 127 128 public Object getLastSearchState() { 129 return lastState; 130 } 131 132 private double getValue(Problem p, Node n) { 133 return -1 * getHeuristic(p, n); // assumption greater heuristic value => 134 // HIGHER on hill; 0 == goal state; 135 // SA deals with gardient DESCENT 136 } 137 138 private double getHeuristic(Problem p, Node aNode) { 139 return p.getHeuristicFunction().getHeuristicValue(aNode.getState()); 140 } 141 }