/** AStarSearch.java * Created on Apr 16, 2005 * * @author imran * @version 1.3 */ package iitb.AStar; import java.util.ArrayList; import java.util.Collection; import java.util.NoSuchElementException; import java.util.TreeSet; /** * @author imran * */ public class AStarSearch { State startState, goalState; TreeSet<State> stateQueue; long numExpansions = 0; boolean profiling = false, debug = false; private ArrayList<State> expansionList; long maxExapnsions = Long.MAX_VALUE; int avgStatesPerExpansion = 100; int lowBoundCalStep = 50; int curLowBoundCalStep = 0; int numBoundUpdate = 0; long maxQueueSize = Long.MAX_VALUE; double lowBoundCalStepIncrFactor = 0.5; private BoundUpdate boundUpdate = null; double lowerBound = Long.MIN_VALUE; public AStarSearch() { init(); } /* public AStarSearch(BoundUpdate boundUpdate){ this(boundUpdate, Long.MAX_VALUE, false); } public AStarSearch(long maxExpansions) { this(null, maxExpansions, false); } public AStarSearch(boolean profiling) { this(null, Long.MAX_VALUE, profiling); } public AStarSearch(long maxExpansions, boolean profiling){ this(null, maxExpansions, profiling); } public AStarSearch(BoundUpdate boundUpdate,long maxExpansions, boolean profiling){ this(boundUpdate, 100, maxExpansions, Long.MAX_VALUE, profiling); } */ public AStarSearch(BoundUpdate boundUpdate,int avgStatePerExpansion, long maxExpansions, long maxQueueSize, boolean profiling){ this.boundUpdate = boundUpdate; this.avgStatesPerExpansion = avgStatePerExpansion; this.maxExapnsions = maxExpansions; this.profiling = profiling; this.maxQueueSize = maxQueueSize; init(); } void init(){ stateQueue = new TreeSet<State>(); } private void initSearch(State startState) { this.startState = startState; goalState = null; stateQueue.clear(); stateQueue.add(startState); numExpansions = 0; lowerBound = Long.MIN_VALUE; numBoundUpdate = 0; curLowBoundCalStep = lowBoundCalStep; if (profiling) expansionList = new ArrayList<State>(); else expansionList = null; } public State performAStarSearch(State startState){ initSearch(startState); State curState = null, successors[], lastState = null; //A* search algorithm while(numExpansions < maxExapnsions && stateQueue.size() < maxQueueSize){ try{ curState = stateQueue.first(); stateQueue.remove(curState); }catch(NoSuchElementException nsee){ System.err.println("Exception in AStar loop::" + nsee); curState = null; } if(curState == null || curState.goalState()) //failure or sucess? break; successors = curState.getSuccessors(); numExpansions++; //only for measuring performance if(successors != null){ for(int i = 0; i < successors.length; i++){ if(successors[i] != null && successors[i].validState()) stateQueue.add(successors[i]); } }else if(debug) System.err.println("Null sucessors:" + curState); if(profiling){ expansionList.add(curState); if(debug) System.out.print(numExpansions + "\t" + stateQueue.size() + "\t"); } if(shouldUpdateBound()){ numBoundUpdate++; updateBound(curState); } lastState = curState; } //System.out.print(numExpansions + "\t" + stateQueue.size() + "\t"); if(debug && profiling) System.out.println("NumExpansions:" + numExpansions + " " + (Math.log(numExpansions)/Math.log(2)) + " :" + stateQueue.size() + " " + (Math.log(stateQueue.size())/Math.log(2))); if(debug && curState != null && !curState.goalState()) System.err.println("Expansion limit reached"); return (goalState = (curState != null ? curState : lastState)); } /** * */ private void updateBound(State curState) { double lb = boundUpdate.getLowerBound(curState); if(lb > this.lowerBound){ pruneQueue(new State(lb, 0)); this.lowerBound = lb; curLowBoundCalStep += curLowBoundCalStep * lowBoundCalStepIncrFactor; }else curLowBoundCalStep += curLowBoundCalStep * 2 * lowBoundCalStepIncrFactor; } private void pruneQueue(State state) { Collection<State> headSet = stateQueue.headSet(state); if(headSet.size() < stateQueue.size()){ //System.out.println("HeadSetSize:" + headSet.size() + "Reduction in queueSize:" + (stateQueue.size() - headSet.size())); TreeSet<State> tempQueue = new TreeSet<State>(); tempQueue.addAll(headSet); stateQueue.clear(); stateQueue = tempQueue; } } private boolean shouldUpdateBound() { return (boundUpdate != null && (numExpansions % curLowBoundCalStep == 0) && ( numExpansions * avgStatesPerExpansion < stateQueue.size() || stateQueue.size() > maxQueueSize ) ); } public State getGoalState() { return goalState; } public State getStartState() { return startState; } public void setStartState(State startState) { this.startState = startState; } public ArrayList<State> getExpansionList() { return expansionList; } public long getNumExapansions(){ return (profiling ? numExpansions : -1); } public boolean isProfiling() { return profiling; } public void setProfiling(boolean profiling) { this.profiling = profiling; } public long getMaxExapnsions() { return maxExapnsions; } public void setMaxExapnsions(long maxExapnsions) { this.maxExapnsions = maxExapnsions; } public boolean isDebug() { return debug; } public void setDebug(boolean debug) { this.debug = debug; } public static void main(String[] args) { } public boolean boundUpdate() { return boundUpdate != null; } }