Main   Class Hierarchy   Classes   Compound List   Files   Compound Members   File Members   Pages  

fringesearch.h

Go to the documentation of this file.
00001 //-----------------------------------------------------------------------------
00002 /** @file fringesearch.h
00003     IDA* like search keeping a list of the fringe nodes.
00004 
00005     $Id: fringesearch_8h-source.html,v 1.1.1.1 2003/08/07 19:41:39 emarkus Exp $
00006     $Source: /usr/cvsroot/www_pathfind/libpathfind/0.1.0/doc/fringesearch_8h-source.html,v $
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     /** Statically allocated linked list used in FringeSearch. */
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         /** Node used in Fringe. */
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     /** IDA* like search keeping a list of the fringe nodes.
00087         This avoids re-expansion of interior nodes at each new
00088         iteration.
00089 
00090         %Statistics (see Search::createStatistics and Search::getStatistics):
00091         - "cpu_time"
00092         - "iterations"
00093         - "nodes_expanded"
00094         - "nodes_visited"
00095         - "path_cost"
00096         - "path_length"
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         /** Cache element for g-value used in FringeSearch. */
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             // Reverse loop so that nodes are visited in same order as in IDA*
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             //cerr << "limit = " << fLimit << '\n';
00306             int fMin = INT_MAX;
00307             doIteration(iteration, fLimit, fMin);
00308             fLimit = fMin;
00309             ++iteration;
00310             //m_fringe.print(cerr);
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


Generated on Thu Aug 7 13:04:49 2003 by Doxygen1.3.1