00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #ifndef PATHFIND_FRINGESEARCH_H
00011 #define PATHFIND_FRINGESEARCH_H
00012
00013 #include <vector>
00014 #include "marker.h"
00015 #include "search.h"
00016
00017
00018
00019 namespace PathFind
00020 {
00021 using namespace std;
00022
00023
00024 class Fringe
00025 {
00026 public:
00027 Fringe();
00028
00029 int getCurrentNode() const
00030 {
00031 return m_currentNode;
00032 }
00033
00034 void init(int numberNodes);
00035
00036 void insertNode(int nodeId);
00037
00038 void nextNode();
00039
00040 void print(ostream& o) const;
00041
00042 void removeCurrentNode()
00043 {
00044 removeNode(m_currentNode);
00045 }
00046
00047 void startIteration();
00048
00049 private:
00050
00051 class Node
00052 {
00053 public:
00054 int m_next;
00055
00056 int m_previous;
00057 };
00058
00059
00060 int m_currentNode;
00061
00062 int m_numberNodes;
00063
00064 int m_headNode;
00065
00066 vector<bool> m_isInList;
00067
00068 vector<Node> m_nodes;
00069
00070
00071 Node& getNode(int nodeId)
00072 {
00073 assert(nodeId >= 0 && nodeId < m_numberNodes);
00074 return m_nodes[nodeId];
00075 }
00076
00077 const Node& getNode(int nodeId) const
00078 {
00079 assert(nodeId >= 0 && nodeId < m_numberNodes);
00080 return m_nodes[nodeId];
00081 }
00082
00083 void removeNode(int nodeId);
00084 };
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098 template<class MARKER = MarkerFastClear>
00099 class FringeSearch
00100 : public Search
00101 {
00102 public:
00103 FringeSearch();
00104
00105 StatisticsCollection createStatistics();
00106
00107 bool findPath(const Environment& env, int start, int target);
00108
00109 const vector<int>& getPath() const
00110 {
00111 return m_path;
00112 }
00113
00114 const StatisticsCollection& getStatistics() const;
00115
00116 const vector<char>& getVisitedNodes() const
00117 {
00118 return m_visitedNodes;
00119 }
00120
00121 private:
00122
00123 class CacheElement
00124 {
00125 public:
00126 int m_gValue;
00127
00128 int m_iteration;
00129
00130 int m_parent;
00131 };
00132
00133
00134 int m_nodesExpanded;
00135
00136 int m_nodesVisited;
00137
00138 int m_target;
00139
00140 const Environment* m_env;
00141
00142 Fringe m_fringe;
00143
00144 StatisticsCollection m_statistics;
00145
00146 vector<CacheElement> m_cache;
00147
00148 MARKER m_isCacheValid;
00149
00150 vector<char> m_visitedNodes;
00151
00152 vector<int> m_path;
00153
00154
00155 void addCache(int nodeId, int gValue, int iteration, int parent);
00156
00157 bool checkCache(int nodeId, int gValue, int iteration) const;
00158
00159 void constructPath(int start);
00160
00161 void getFromCache(int nodeId, int& gValue, int& parent) const;
00162
00163 void doIteration(int iteration, int fLimit, int& fMin);
00164
00165 void init(int numberNodes);
00166
00167 void markVisitedNode(int nodeId, int iteration);
00168 };
00169
00170 }
00171
00172
00173
00174 namespace PathFind
00175 {
00176 using namespace std;
00177
00178 template<class MARKER>
00179 FringeSearch<MARKER>::FringeSearch()
00180 : m_statistics(createStatistics())
00181 {
00182 }
00183
00184 template<class MARKER>
00185 void FringeSearch<MARKER>::addCache(int nodeId, int gValue, int iteration,
00186 int parent)
00187 {
00188 CacheElement& cacheElement = m_cache[nodeId];
00189 cacheElement.m_gValue = gValue;
00190 cacheElement.m_iteration = iteration;
00191 cacheElement.m_parent = parent;
00192 m_isCacheValid.set(nodeId);
00193 }
00194
00195 template<class MARKER>
00196 bool FringeSearch<MARKER>::checkCache(int nodeId, int gValue,
00197 int iteration) const
00198 {
00199 if (! m_isCacheValid.get(nodeId))
00200 return false;
00201 const CacheElement& cacheElement = m_cache[nodeId];
00202 int gValueCached = cacheElement.m_gValue;
00203 return (gValue > gValueCached
00204 || (gValue == gValueCached
00205 && iteration == cacheElement.m_iteration));
00206 }
00207
00208 template<class MARKER>
00209 void FringeSearch<MARKER>::constructPath(int start)
00210 {
00211 m_path.clear();
00212 if (! m_isCacheValid.get(m_target))
00213 return;
00214 int nodeId = m_target;
00215 do
00216 {
00217 m_path.push_back(nodeId);
00218 nodeId = m_cache[nodeId].m_parent;
00219 assert(m_isCacheValid.get(nodeId));
00220 }
00221 while (nodeId != start);
00222 m_path.push_back(nodeId);
00223 }
00224
00225 template<class MARKER>
00226 StatisticsCollection FringeSearch<MARKER>::createStatistics()
00227 {
00228 StatisticsCollection collection;
00229 collection.create("cpu_time");
00230 collection.create("iterations");
00231 collection.create("nodes_expanded");
00232 collection.create("nodes_visited");
00233 collection.create("path_cost");
00234 collection.create("path_length");
00235 return collection;
00236 }
00237
00238 template<class MARKER>
00239 void FringeSearch<MARKER>::doIteration(int iteration, int fLimit,
00240 int& fMin)
00241 {
00242 m_fringe.startIteration();
00243 vector<Environment::Successor> successors;
00244 while (true)
00245 {
00246 int nodeId = m_fringe.getCurrentNode();
00247 if (nodeId == NO_NODE)
00248 return;
00249 ++m_nodesVisited;
00250 markVisitedNode(nodeId, iteration);
00251 int gValue;
00252 int lastNode;
00253 getFromCache(nodeId, gValue, lastNode);
00254 if (nodeId == m_target)
00255 {
00256 m_statistics.get("path_cost").add(gValue);
00257 return;
00258 }
00259 int fValue = gValue + m_env->getHeuristic(nodeId, m_target);
00260 if (fValue > fLimit)
00261 {
00262 if (fValue < fMin)
00263 fMin = fValue;
00264 m_fringe.nextNode();
00265 continue;
00266 }
00267 m_env->getSuccessors(nodeId, lastNode, successors);
00268 int numberSuccessors = successors.size();
00269
00270 for (int i = numberSuccessors; i--; )
00271 {
00272 const Environment::Successor& successor = successors[i];
00273 int targetNodeId = successor.m_target;
00274 int targetGValue = gValue + successor.m_cost;
00275 if (checkCache(targetNodeId, targetGValue, iteration))
00276 continue;
00277 m_fringe.insertNode(targetNodeId);
00278 addCache(targetNodeId, targetGValue, iteration, nodeId);
00279 ++m_nodesExpanded;
00280 }
00281 m_fringe.removeCurrentNode();
00282 m_fringe.nextNode();
00283 }
00284 }
00285
00286 template<class MARKER>
00287 bool FringeSearch<MARKER>::findPath(const Environment& env, int start,
00288 int target)
00289 {
00290 assert(env.isValidNodeId(start));
00291 assert(env.isValidNodeId(target));
00292 clock_t startTime = clock();
00293 m_env = &env;
00294 m_target = target;
00295 int numberNodes = env.getNumberNodes();
00296 init(numberNodes);
00297 m_nodesExpanded = 0;
00298 m_nodesVisited = 0;
00299 int iteration = 1;
00300 int fLimit = env.getHeuristic(start, target);
00301 m_fringe.insertNode(start);
00302 addCache(start, 0, 0, NO_NODE);
00303 while (! m_isCacheValid.get(m_target))
00304 {
00305
00306 int fMin = INT_MAX;
00307 doIteration(iteration, fLimit, fMin);
00308 fLimit = fMin;
00309 ++iteration;
00310
00311 }
00312 constructPath(start);
00313 m_statistics.get("iterations").add(iteration);
00314 double timeDiff =
00315 static_cast<double>(clock() - startTime) / CLOCKS_PER_SEC;
00316 m_statistics.get("nodes_visited").add(m_nodesVisited);
00317 m_statistics.get("nodes_expanded").add(m_nodesExpanded);
00318 m_statistics.get("path_length").add(m_path.size());
00319 m_statistics.get("cpu_time").add(timeDiff);
00320 return true;
00321 }
00322
00323 template<class MARKER>
00324 void FringeSearch<MARKER>::getFromCache(int nodeId, int& gValue,
00325 int& parent) const
00326 {
00327 assert(m_isCacheValid.get(nodeId));
00328 const CacheElement& cacheElement = m_cache[nodeId];
00329 parent = cacheElement.m_parent;
00330 gValue = cacheElement.m_gValue;
00331 }
00332
00333 template<class MARKER>
00334 const StatisticsCollection& FringeSearch<MARKER>::getStatistics() const
00335 {
00336 return m_statistics;
00337 }
00338
00339 template<class MARKER>
00340 void FringeSearch<MARKER>::init(int numberNodes)
00341 {
00342 m_visitedNodes.resize(numberNodes);
00343 fill(m_visitedNodes.begin(), m_visitedNodes.end(), ' ');
00344 m_isCacheValid.init(numberNodes);
00345 m_cache.resize(numberNodes);
00346 m_fringe.init(numberNodes);
00347 m_statistics.clear();
00348 }
00349
00350 template<class MARKER>
00351 void FringeSearch<MARKER>::markVisitedNode(int nodeId, int iteration)
00352 {
00353 if (m_visitedNodes[nodeId] != ' ')
00354 return;
00355 m_visitedNodes[nodeId] = getVisitedNodeLabel(iteration);
00356 }
00357
00358 }
00359
00360
00361 #endif