yapf_base.hpp

Go to the documentation of this file.
00001 /* $Id: yapf_base.hpp 12190 2008-02-20 12:31:28Z smatz $ */
00002 
00005 #ifndef  YAPF_BASE_HPP
00006 #define  YAPF_BASE_HPP
00007 
00008 #include "../debug.h"
00009 
00010 extern int _total_pf_time_us;
00011 
00041 template <class Types>
00042 class CYapfBaseT {
00043 public:
00044   typedef typename Types::Tpf Tpf;           
00045   typedef typename Types::TrackFollower TrackFollower;
00046   typedef typename Types::NodeList NodeList; 
00047   typedef typename NodeList::Titem Node;     
00048   typedef typename Node::Key Key;            
00049 
00050 
00051   NodeList             m_nodes;              
00052 protected:
00053   Node*                m_pBestDestNode;      
00054   Node*                m_pBestIntermediateNode; 
00055   const YapfSettings  *m_settings;           
00056   int                  m_max_search_nodes;   
00057   const Vehicle*       m_veh;                
00058 
00059   int                  m_stats_cost_calcs;   
00060   int                  m_stats_cache_hits;   
00061 
00062 public:
00063   CPerformanceTimer    m_perf_cost;          
00064   CPerformanceTimer    m_perf_slope_cost;    
00065   CPerformanceTimer    m_perf_ts_cost;       
00066   CPerformanceTimer    m_perf_other_cost;    
00067 
00068 public:
00069   int                  m_num_steps;          
00070 
00071 public:
00073   FORCEINLINE CYapfBaseT()
00074     : m_pBestDestNode(NULL)
00075     , m_pBestIntermediateNode(NULL)
00076     , m_settings(&_patches.yapf)
00077     , m_max_search_nodes(PfGetSettings().max_search_nodes)
00078     , m_veh(NULL)
00079     , m_stats_cost_calcs(0)
00080     , m_stats_cache_hits(0)
00081     , m_num_steps(0)
00082   {
00083   }
00084 
00086   ~CYapfBaseT() {}
00087 
00088 protected:
00090   FORCEINLINE Tpf& Yapf() {return *static_cast<Tpf*>(this);}
00091 
00092 public:
00094   FORCEINLINE const YapfSettings& PfGetSettings() const
00095   {
00096     return *m_settings;
00097   }
00098 
00106   inline bool FindPath(const Vehicle *v)
00107   {
00108     m_veh = v;
00109 
00110 #ifndef NO_DEBUG_MESSAGES
00111     CPerformanceTimer perf;
00112     perf.Start();
00113 #endif /* !NO_DEBUG_MESSAGES */
00114 
00115     Yapf().PfSetStartupNodes();
00116 
00117     while (true) {
00118       m_num_steps++;
00119       Node *n = m_nodes.GetBestOpenNode();
00120       if (n == NULL)
00121         break;
00122 
00123       // if the best open node was worse than the best path found, we can finish
00124       if (m_pBestDestNode != NULL && m_pBestDestNode->GetCost() < n->GetCostEstimate())
00125         break;
00126 
00127       Yapf().PfFollowNode(*n);
00128       if (m_max_search_nodes == 0 || m_nodes.ClosedCount() < m_max_search_nodes) {
00129         m_nodes.PopOpenNode(n->GetKey());
00130         m_nodes.InsertClosedNode(*n);
00131       } else {
00132         m_pBestDestNode = m_pBestIntermediateNode;
00133         break;
00134       }
00135     }
00136 
00137     bool bDestFound = (m_pBestDestNode != NULL) && (m_pBestDestNode != m_pBestIntermediateNode);
00138 
00139 #ifndef NO_DEBUG_MESSAGES
00140     perf.Stop();
00141     if (_debug_yapf_level >= 2) {
00142       int t = perf.Get(1000000);
00143       _total_pf_time_us += t;
00144 
00145       if (_debug_yapf_level >= 3) {
00146         UnitID veh_idx = (m_veh != NULL) ? m_veh->unitnumber : 0;
00147         char ttc = Yapf().TransportTypeChar();
00148         float cache_hit_ratio = (m_stats_cache_hits == 0) ? 0.0f : ((float)m_stats_cache_hits / (float)(m_stats_cache_hits + m_stats_cost_calcs) * 100.0f);
00149         int cost = bDestFound ? m_pBestDestNode->m_cost : -1;
00150         int dist = bDestFound ? m_pBestDestNode->m_estimate - m_pBestDestNode->m_cost : -1;
00151 
00152         DEBUG(yapf, 3, "[YAPF%c]%c%4d- %d us - %d rounds - %d open - %d closed - CHR %4.1f%% - c%d(sc%d, ts%d, o%d) -- ",
00153           ttc, bDestFound ? '-' : '!', veh_idx, t, m_num_steps, m_nodes.OpenCount(), m_nodes.ClosedCount(),
00154           cache_hit_ratio, cost, dist, m_perf_cost.Get(1000000), m_perf_slope_cost.Get(1000000),
00155           m_perf_ts_cost.Get(1000000), m_perf_other_cost.Get(1000000)
00156         );
00157       }
00158     }
00159 #endif /* !NO_DEBUG_MESSAGES */
00160     return bDestFound;
00161   }
00162 
00166   FORCEINLINE Node* GetBestNode()
00167   {
00168     return (m_pBestDestNode != NULL) ? m_pBestDestNode : m_pBestIntermediateNode;
00169   }
00170 
00174   FORCEINLINE Node& CreateNewNode()
00175   {
00176     Node& node = *m_nodes.CreateNewNode();
00177     return node;
00178   }
00179 
00181   FORCEINLINE void AddStartupNode(Node& n)
00182   {
00183     Yapf().PfNodeCacheFetch(n);
00184     // insert the new node only if it is not there
00185     if (m_nodes.FindOpenNode(n.m_key) == NULL) {
00186       m_nodes.InsertOpenNode(n);
00187     } else {
00188       // if we are here, it means that node is already there - how it is possible?
00189       //   probably the train is in the position that both its ends point to the same tile/exit-dir
00190       //   very unlikely, but it happened
00191     }
00192   }
00193 
00195   FORCEINLINE void AddMultipleNodes(Node* parent, const TrackFollower &tf)
00196   {
00197     bool is_choice = (KillFirstBit(tf.m_new_td_bits) != TRACKDIR_BIT_NONE);
00198     for (TrackdirBits rtds = tf.m_new_td_bits; rtds != TRACKDIR_BIT_NONE; rtds = KillFirstBit(rtds)) {
00199       Trackdir td = (Trackdir)FindFirstBit2x64(rtds);
00200       Node& n = Yapf().CreateNewNode();
00201       n.Set(parent, tf.m_new_tile, td, is_choice);
00202       Yapf().AddNewNode(n, tf);
00203     }
00204   }
00205 
00208   void AddNewNode(Node &n, const TrackFollower &tf)
00209   {
00210     // evaluate the node
00211     bool bCached = Yapf().PfNodeCacheFetch(n);
00212     if (!bCached) {
00213       m_stats_cost_calcs++;
00214     } else {
00215       m_stats_cache_hits++;
00216     }
00217 
00218     bool bValid = Yapf().PfCalcCost(n, &tf);
00219 
00220     if (bCached) {
00221       Yapf().PfNodeCacheFlush(n);
00222     }
00223 
00224     if (bValid) bValid = Yapf().PfCalcEstimate(n);
00225 
00226     // have the cost or estimate callbacks marked this node as invalid?
00227     if (!bValid) return;
00228 
00229     // detect the destination
00230     bool bDestination = Yapf().PfDetectDestination(n);
00231     if (bDestination) {
00232       if (m_pBestDestNode == NULL || n < *m_pBestDestNode) {
00233         m_pBestDestNode = &n;
00234       }
00235       m_nodes.FoundBestNode(n);
00236       return;
00237     }
00238 
00239     if (m_max_search_nodes > 0 && (m_pBestIntermediateNode == NULL || (m_pBestIntermediateNode->GetCostEstimate() - m_pBestIntermediateNode->GetCost()) > (n.GetCostEstimate() - n.GetCost()))) {
00240       m_pBestIntermediateNode = &n;
00241     }
00242 
00243     // check new node against open list
00244     Node* openNode = m_nodes.FindOpenNode(n.GetKey());
00245     if (openNode != NULL) {
00246       // another node exists with the same key in the open list
00247       // is it better than new one?
00248       if (n.GetCostEstimate() < openNode->GetCostEstimate()) {
00249         // update the old node by value from new one
00250         m_nodes.PopOpenNode(n.GetKey());
00251         *openNode = n;
00252         // add the updated old node back to open list
00253         m_nodes.InsertOpenNode(*openNode);
00254       }
00255       return;
00256     }
00257 
00258     // check new node against closed list
00259     Node* closedNode = m_nodes.FindClosedNode(n.GetKey());
00260     if (closedNode != NULL) {
00261       // another node exists with the same key in the closed list
00262       // is it better than new one?
00263       int node_est = n.GetCostEstimate();
00264       int closed_est = closedNode->GetCostEstimate();
00265       if (node_est < closed_est) {
00266         // If this assert occurs, you have probably problem in
00267         // your Tderived::PfCalcCost() or Tderived::PfCalcEstimate().
00268         // The problem could be:
00269         //  - PfCalcEstimate() gives too large numbers
00270         //  - PfCalcCost() gives too small numbers
00271         //  - You have used negative cost penalty in some cases (cost bonus)
00272         assert(0);
00273 
00274         return;
00275       }
00276       return;
00277     }
00278     // the new node is really new
00279     // add it to the open list
00280     m_nodes.InsertOpenNode(n);
00281   }
00282 
00283   const Vehicle* GetVehicle() const {return m_veh;}
00284 
00285   void DumpBase(DumpTarget &dmp) const
00286   {
00287     dmp.WriteStructT("m_nodes", &m_nodes);
00288     dmp.WriteLine("m_num_steps = %d", m_num_steps);
00289   }
00290 
00291   // methods that should be implemented at derived class Types::Tpf (derived from CYapfBaseT)
00292 
00293 #if 0
00294 
00295   FORCEINLINE void PfSetStartupNodes()
00296   {
00297     // example:
00298     Node& n1 = *base::m_nodes.CreateNewNode();
00299     .
00300     . // setup node members here
00301     .
00302     base::m_nodes.InsertOpenNode(n1);
00303   }
00304 
00306   FORCEINLINE void PfFollowNode(Node& org)
00307   {
00308     for (each follower of node org) {
00309       Node& n = *base::m_nodes.CreateNewNode();
00310       .
00311       . // setup node members here
00312       .
00313       n.m_parent   = &org; // set node's parent to allow back tracking
00314       AddNewNode(n);
00315     }
00316   }
00317 
00319   FORCEINLINE bool PfCalcCost(Node& n)
00320   {
00321     // evaluate last step cost
00322     int cost = ...;
00323     // set the node cost as sum of parent's cost and last step cost
00324     n.m_cost = n.m_parent->m_cost + cost;
00325     return true; // true if node is valid follower (i.e. no obstacle was found)
00326   }
00327 
00329   FORCEINLINE bool PfCalcEstimate(Node& n)
00330   {
00331     // evaluate the distance to our destination
00332     int distance = ...;
00333     // set estimate as sum of cost from origin + distance to the target
00334     n.m_estimate = n.m_cost + distance;
00335     return true; // true if node is valid (i.e. not too far away :)
00336   }
00337 
00339   FORCEINLINE bool PfDetectDestination(Node& n)
00340   {
00341     bool bDest = (n.m_key.m_x == m_x2) && (n.m_key.m_y == m_y2);
00342     return bDest;
00343   }
00344 #endif
00345 };
00346 
00347 #endif /* YAPF_BASE_HPP */

Generated on Wed Oct 1 17:03:25 2008 for openttd by  doxygen 1.5.6