KrisLibrary  1.0.0
GeneralizedAStar.h
1 #ifndef AI_GENERALIZED_ASTAR_H
2 #define AI_GENERALIZED_ASTAR_H
3 
4 #include <vector>
5 #include <map>
6 #include <KrisLibrary/utils/stl_tr1.h>
7 #include <KrisLibrary/structs/IndexedPriorityQueue.h>
8 
9 namespace AI {
10 
33 template <class S,class C>
35 {
36  //a node in the tree
37  struct Node
38  {
39  Node():parent(NULL) {}
40  ~Node() { for(size_t i=0;i<children.size();i++) delete children[i]; }
41 
43  C g;
45  C f;
47  S data;
51  std::vector<Node*> children;
52  };
53 
55  GeneralizedAStar(const S& start);
56  virtual ~GeneralizedAStar() {}
58  void SetStart(const S& start);
60  bool Search();
62  bool SearchStep();
64  bool SearchFailed();
66  int NumNodes() const;
68  int NumExpanded() const;
70  int NumDescendents(const Node& n) const;
72  C TopPriority() const;
73 
75  inline bool GoalFound() const { return !path.empty(); }
78  inline C GoalCost() const { if(goal != NULL) return goal->g; return zero; }
80  inline const std::vector<S>& GoalPath() const { return path; }
81 
83  virtual bool IsGoal(const S& s) =0;
84  virtual void Successors(const S& s,std::vector<S>& successors,std::vector<C>& costs) =0;
85  virtual C Heuristic(const S& s) { return zero; }
88  virtual void ClearVisited() {}
89  virtual void Visit(const S& s,Node* n) {}
90  virtual Node* VisitedStateNode(const S& s) { return NULL; }
94  virtual bool OnExpand(Node* n) { return true; }
95 
99 
102  C zero;
103 
106 
112  std::vector<S> successors;
113  std::vector<C> costs;
114  int numNodes;
115 
119  std::vector<S> path;
120 };
121 
124 template <class S>
125 struct AStar : public GeneralizedAStar<S,double>
126 {
127  typedef struct GeneralizedAStar<S,double>::Node Node;
128  AStar() { this->zero = 0.0; }
129  virtual ~AStar() {}
130 };
131 
134 template <class S>
135 struct IntegerAStar : public GeneralizedAStar<S,int>
136 {
137  typedef struct GeneralizedAStar<S,int>::Node Node;
138  IntegerAStar() { this->zero = 0; }
139  virtual ~IntegerAStar() {}
140 };
141 
144 template <class S,class C>
146 {
147  public:
148  typedef struct GeneralizedAStar<S,C>::Node Node;
149  std::map<S,Node*> visited;
150  virtual ~GeneralizedAStarWithMap() {}
151  virtual void ClearVisited() { visited.clear(); }
152  virtual void Visit(const S& s,Node* n) { visited[s]=n;}
153  virtual Node* VisitedStateNode(const S& s) {
154  typename std::map<S,Node*>::const_iterator i=visited.find(s);
155  if(i==visited.end()) return NULL;
156  return i->second;
157  }
158 };
159 
162 template <class S,class C>
164 {
165  public:
166  typedef struct GeneralizedAStar<S,C>::Node Node;
167  UNORDERED_MAP_TEMPLATE<S,Node*> visited;
168  virtual ~GeneralizedAStarWithHashMap() {}
169  virtual void ClearVisited() { visited.clear(); }
170  virtual void Visit(const S& s,Node* n) { visited[s]=n;}
171  virtual Node* VisitedStateNode(const S& s) {
172  typename UNORDERED_MAP_TEMPLATE<S,Node*>::const_iterator i=visited.find(s);
173  if(i==visited.end()) return NULL;
174  return i->second;
175  }
176 };
177 
178 
179 template <class S,class C>
181  :testGoalOnGeneration(false),numNodes(0),goal(NULL)
182 {
183 }
184 
185 template <class S,class C>
187  :testGoalOnGeneration(false),numNodes(0),goal(NULL)
188 {
189  SetStart(start);
190 }
191 
192 template <class S,class C>
194 {
195  ClearVisited();
196  fringe.clear();
197  goal = NULL;
198  path.resize(0);
199  numNodes = 1;
200 
202  if(IsGoal(start)) {
203  path.push_back(start);
204  return;
205  }
206  }
207 
208  //initialize with the root node
209  root.g=zero;
210  root.f=Heuristic(start);
211  root.data = start;
212  root.parent = NULL;
213  for(size_t i=0;i<root.children.size();i++)
214  delete root.children[i];
215  root.children.clear();
216  fringe.insert(&root,std::pair<C,C>(root.f,-root.g));
217  Visit(start,&root);
218 }
219 
220 template <class S,class C>
222 {
223  while(!fringe.empty()) {
224  bool res=SearchStep();
225  if(res) return true;
226  }
227  return false;
228 }
229 
230 template <class S,class C>
232 {
233  if(fringe.empty()) return false;
234 
235  Node* n = fringe.top().second;
236  fringe.pop();
237 
238  //give the subclass optional feedback
239  if(!OnExpand(n)) return false;
240 
241  if(!testGoalOnGeneration) {
242  if(IsGoal(n->data)) { //reached the goal!
243  goal = n;
244  path.resize(0);
245  while(n != NULL) {
246  path.push_back(n->data);
247  n = n->parent;
248  }
249  //path is in backwards order, reverse it
250  std::reverse(path.begin(),path.end());
251  return true;
252  }
253  }
254 
255  successors.resize(0);
256  costs.resize(0);
257  Successors(n->data,successors,costs);
258  Assert(successors.size()==costs.size());
259  /*
260  for(size_t i=0;i<costs.size();i++)
261  Assert(costs[i] >= zero);
262  */
263 
264  n->children.resize(0);
265  n->children.reserve(successors.size());
266  for(size_t i=0;i<successors.size();i++) {
268  if(IsGoal(successors[i])) { //reached the goal!
269  goal = NULL;
270  path.resize(0);
271  path.push_back(successors[i]);
272  while(n != NULL) {
273  path.push_back(n->data);
274  n = n->parent;
275  }
276  //path is in backwards order, reverse it
277  std::reverse(path.begin(),path.end());
278  return true;
279  }
280  }
281  Node* visited = VisitedStateNode(successors[i]);
282  if(visited) {
283  if(n->g + costs[i] < visited->g) {
284  //cost is lower than previous, keep new state
285  //reparent the node
286  Node* p=visited->parent;
287  Assert(p!=NULL);
288  for(size_t c=0;c<p->children.size();c++)
289  if(visited == p->children[c]) {
290  p->children[c] = p->children.back();
291  p->children.resize(p->children.size()-1);
292  break;
293  }
294  n->children.push_back(visited);
295  visited->g = n->g + costs[i];
296  visited->f = visited->g + Heuristic(successors[i]);
297  visited->parent = n;
298  fringe.refresh(visited,std::pair<C,C>(visited->f,-visited->g));
299  }
300  }
301  else {
302  //add successors[i] to the child list
303  numNodes ++;
304  n->children.push_back(new Node);
305  Node* child = n->children.back();
306  child->data = successors[i];
307  child->parent = n;
308  child->g = n->g + costs[i];
309  child->f = child->g + Heuristic(successors[i]);
310 
311  //add successors[i] to the fringe and mark as visited
312  fringe.insert(child,std::pair<C,C>(child->f,-child->g));
313  Visit(successors[i],child);
314  }
315  }
316  return false;
317 }
318 
319 template <class S,class C>
321 {
322  return fringe.empty();
323 }
324 
325 template <class S,class C>
327 {
328  return numNodes;
329  //return 1 + NumDescendents(root);
330 }
331 
332 template <class S,class C>
334 {
335  return NumNodes()-(int)fringe.size();
336 }
337 
338 template <class S,class C>
340 {
341  int count=(int)n.children.size();
342  for(size_t i=0;i<n.children.size();i++)
343  count += NumDescendents(*n.children[i]);
344  return count;
345 }
346 
347 template <class S,class C>
349 {
350  if(fringe.empty()) return zero;
351  return fringe.top().first.first;
352 }
353 
354 } //namespace AI
355 
356 #endif
virtual bool OnExpand(Node *n)
Definition: GeneralizedAStar.h:94
Node root
The A* search tree.
Definition: GeneralizedAStar.h:105
std::vector< S > path
Upon successful termination, path contains the path from start to goal.
Definition: GeneralizedAStar.h:119
Contains a priority queue with an associated index, allowing updates of the priority value...
Definition: IndexedPriorityQueue.h:36
Node * goal
Upon successful termination, goal contains the goal node.
Definition: GeneralizedAStar.h:117
virtual void ClearVisited()
Definition: GeneralizedAStar.h:169
std::vector< S > successors
Temporary variables – slightly reduces the number of memory allocations.
Definition: GeneralizedAStar.h:112
Definition: GeneralizedAStar.h:163
Definition: GeneralizedAStar.h:9
std::vector< Node * > children
list of pointers to children
Definition: GeneralizedAStar.h:51
C zero
Definition: GeneralizedAStar.h:102
bool testGoalOnGeneration
Definition: GeneralizedAStar.h:98
S data
state data
Definition: GeneralizedAStar.h:47
void SetStart(const S &start)
Resets the search from the given start state.
Definition: GeneralizedAStar.h:193
Definition: GeneralizedAStar.h:37
C TopPriority() const
Returns the priority of the next node to be expanded.
Definition: GeneralizedAStar.h:348
int NumDescendents(const Node &n) const
Returns the number of descendents of n.
Definition: GeneralizedAStar.h:339
Definition: GeneralizedAStar.h:145
C g
cost from start
Definition: GeneralizedAStar.h:43
virtual void ClearVisited()
Definition: GeneralizedAStar.h:151
A tree graph structure, represented directly at the node level.
Definition: Tree.h:25
bool GoalFound() const
Returns true if the goal has been found.
Definition: GeneralizedAStar.h:75
int NumNodes() const
Returns the number of nodes in the tree.
Definition: GeneralizedAStar.h:326
int NumExpanded() const
Returns the number of previously expanded nodes.
Definition: GeneralizedAStar.h:333
Definition: GeneralizedAStar.h:34
Node * parent
pointer to parent
Definition: GeneralizedAStar.h:49
virtual void ClearVisited()
Definition: GeneralizedAStar.h:88
Definition: GeneralizedAStar.h:125
bool SearchStep()
Performs a single iteration of search.
Definition: GeneralizedAStar.h:231
C GoalCost() const
Definition: GeneralizedAStar.h:78
virtual bool IsGoal(const S &s)=0
The following must be overloaded by the subclass.
IndexedPriorityQueue< Node *, std::pair< C, C > > fringe
Definition: GeneralizedAStar.h:110
bool SearchFailed()
Returns true if search failed.
Definition: GeneralizedAStar.h:320
bool Search()
Performs search until a goal is reached.
Definition: GeneralizedAStar.h:221
Definition: GeneralizedAStar.h:135
const std::vector< S > & GoalPath() const
Returns path of states to the goal.
Definition: GeneralizedAStar.h:80
C f
cost from start + heuristic
Definition: GeneralizedAStar.h:45