root/trunk/AStarSearch.java

Revision 3, 6.2 kB (checked in by dpaola2, 1 week ago)

old pathways project added

Line 
1 // AStarSearch - copyright Tom Felker, <tfelker2@uiuc.edu>, December 2004
2 // implements an A* search algorithm
3 // fits into the UIUC pathways system
4
5 import java.util.*;
6
7 public class AStarSearch extends Search {
8
9         // construct ourselves
10         public AStarSearch() {
11                 super();
12                 open = new TreeSet();
13                 searchNodes = new HashMap();
14         }
15
16         // note that this method contains many println's, which can be comented
17         // out in normal use, but are left in now to clarify what happens
18         // and when comparisons are performed.  They are not indented so they
19         // can be easily seen and commented out
20
21         // this returns the lowest-cost path between the origin and destination
22         // nodes (which were set earlier), or null if no path is found.
23         public Path computeBestPath() {
24
25                 // for now, don't try to optimize by saving old searchnodes
26                 open.clear();
27                 searchNodes.clear();
28
29                 // put the start node on the open list
30                 SearchNode current = new SearchNode(origin);
31                 current.isOpen = true;
32                 searchNodes.put(current.node, current);
33                 open.add(current);
34
35                 // repeat as long as the open list isn't empty
36                 while(open.size() != 0) {
37
38                         // set current to the node with the lowest f cost on open list
39
40                         // we use an iterator, because this way, we can remove the lowest
41                         // element with zero comparisons (possibly lg(n) pointer dereferences,
42                         // though, depending on Java's TreeMap implementation).
43
44                         Iterator iter = open.iterator();
45                         current = (SearchNode)iter.next();
46                         iter.remove();
47                         current.isOpen = false;
48
49                         // were we successful?  maybe.  hooray!
50                         if(current.node == destination) break;
51
52                         // for each node n adjacent to current (by edge e)...
53                         iter = current.node.edges.iterator();
54                         while(iter.hasNext()) {
55                                 Edge e = (Edge)iter.next();
56
57                                 // This is a hash, so the membership test runs in O(1) time
58                                 // Note that we never have to perform a membership test on the open list,
59                                 // which would be O(lg(n)), because if a node is in the open list, it's
60                                 // also in searchNodes and its isOpen property is true.
61                                 SearchNode n = (SearchNode)searchNodes.get(e.getOtherNode(current.node));
62
63                                 if(n == null) {
64                                         // n wasn't on any list, so we calculate
65                                         // its costs and add it to open
66                                         n = new SearchNode(e.getOtherNode(current.node));
67
68                                         // note that we cache h costs - memory access
69                                         // is probably cheaper than the Pythagorean formula
70
71
72                                         //changed for bus nodes!
73                                         //g cost is already traversed cost. could represent
74                                         // absolute time(ie, 3:30 pm). This is needed in H
75                                         // cost for absolute time bus schedules
76                                         // h cost is hard to envision as absolute.
77
78                                         //cleanup SearchNode!!
79                                         n.h = n.node.computeHCost(this, current.node);
80                                         n.g = e.computeDeltaGCost(current.node, current.g, this);
81                                         n.g.add(current.g);
82                                         n.f = Cost.add(n.g, n.h);
83                                         n.parent = e;
84                                         n.isOpen = true;
85                                         searchNodes.put(n.node, n);
86
87                                         // we keep track of this to ensure that the open list grows
88                                         // when we add to it, to ensure that the horrible hack we
89                                         // do actually works.
90
91                                         int oldOpenSize = open.size();
92                                         open.add(n);
93
94                                         if(open.size() != oldOpenSize + 1)
95                                                 throw new RuntimeException("Open list didn't grow!!!");
96
97                                         continue;
98                                 }
99
100                                 // After some exerimentation, it seems that when the heuristic is
101                                 // nonzero, and only when the graph is relatively large, we
102                                 // do need to checked nodes on the closed list.  Whatever.
103
104                                 // in other words, don't uncomment the following line:
105                                 // if(!n.isOpen) continue;
106
107                                 Cost possibleG = e.computeDeltaGCost(current.node, current.g, this);
108                                 possibleG.add(current.g);
109                                 if(possibleG.compareTo(n.g) < 0) {
110
111                                         // we must remove and re-add to the open list
112                                         // otherwise, the list will get unsorted
113                                         // This could be optimized, but java won't let us
114                                         // get close enough to the tree to only compare
115                                         // with parents.  Time is still O(lg(n)).
116                                         if(n.isOpen) open.remove(n);
117                                         n.g = possibleG;
118                                         n.f = Cost.add(n.g, n.h);
119                                         n.parent = e;
120
121                                         int oldOpenSize = open.size();
122                                         open.add(n);
123                                         if(open.size() != oldOpenSize + 1)
124                                                 throw new RuntimeException("Open list didn't grow!!!");
125                                 }
126
127                         } // end for(all current's neighbors)
128                 } // end while(open is nonempty)
129
130                 // if we didn't reach the destination, we probably didn't
131                 // have a path to it.
132                 if(current.node != destination) return null;
133
134                 // trace backwards, populating our path
135                 Path path = new Path();
136                 path.setTotalCost( current.g );
137                 for(; current.parent != null;
138                     current = (SearchNode)searchNodes.get(current.parent.getOtherNode(current.node))) {
139                         path.nodes.addFirst(current.node);
140                         path.edges.addFirst(current.parent);
141                 }
142
143                 // Our loop will have left out the origin...
144                 path.nodes.addFirst(origin);
145
146                 // yay, we're done!
147                 return path;
148         }
149
150         // returns all the nodes that were searched in the last search.
151         public Collection getSearchedNodes() {
152                 return searchNodes.keySet();
153         }
154
155         public Collection getOpenNodes() {
156                 Collection openNodes = new LinkedList();
157                 Iterator i = open.iterator();
158                 while(i.hasNext()) {
159                         openNodes.add(((SearchNode)i.next()).node);
160                 }
161                 return openNodes;
162         }
163
164         // Data structures:
165         //
166         // We have searchNodes, which we create from nodes, and we want there
167         // to be only one SearchNode per Node per AStarSearch.  So, we keep
168         // a hashmap (O(1) addition, lookup, and deletion).  Because of the way
169         // the algorithm works, as soon as we need to make a SearchNode, it will
170         // be on either the open list or the closed list.  Therefore, we don't
171         // need an explicit closed-list - anything that's not in the hash is known
172         // to not be on either list
173
174         // TreeSet is used because it has O(log n) running time for:
175         // containsKey, get, put and remove, and it maintains the list sorted
176         // so it has O(1) getting of the lowest cost element.
177
178         SortedSet open;
179
180         // maps Nodes to SearchNodes
181         // A hashmap is used here, because it has constant time for get and put,
182         // which will be done alot here.
183
184         Map searchNodes;
185
186         // Note - SortedMap and Map are used, because they are more general - we
187         // can then choose which implementation we want at runtime.
188
189 }
Note: See TracBrowser for help on using the browser.