00001 //----------------------------------------------------------------------------- 00002 /** @file idastar.cpp 00003 @see idastar.h 00004 00005 $Id: idastar_8cpp-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/idastar_8cpp-source.html,v $ 00007 */ 00008 //----------------------------------------------------------------------------- 00009 00010 #include "idastar.h" 00011 00012 #include <iostream> 00013 #include <math.h> 00014 #include "util.h" 00015 00016 using namespace std; 00017 using namespace PathFind; 00018 00019 //----------------------------------------------------------------------------- 00020 00021 IDAStar::IDAStar(Caching caching) 00022 : m_caching(caching), 00023 m_statistics(createStatistics()), 00024 m_branchingFactor(m_statistics.get("branching_factor")) 00025 { 00026 } 00027 00028 bool IDAStar::checkCache(int nodeId, int f, int g, int iteration, int& fMin) 00029 { 00030 if (m_cache[nodeId].m_iter > 0) 00031 { 00032 if ((m_cache[nodeId].m_g < g) || 00033 ((m_cache[nodeId].m_g == g) && 00034 (m_cache[nodeId].m_iter == iteration))) 00035 { 00036 fMin = INT_MAX; 00037 return true; 00038 } 00039 00040 if ( m_caching == F_CACHING ) 00041 { 00042 // Check if backed-up F-value causes an early termination. 00043 if ( m_cache[nodeId].m_f > m_fLimit ) 00044 { 00045 fMin = m_cache[nodeId].m_f; 00046 return true; 00047 } 00048 } 00049 00050 } 00051 return false; 00052 } 00053 00054 StatisticsCollection IDAStar::createStatistics() 00055 { 00056 StatisticsCollection collection; 00057 collection.create("aborted"); 00058 collection.create("cpu_time"); 00059 collection.create("path_cost"); 00060 collection.create("path_length"); 00061 collection.create("branching_factor"); 00062 collection.create("nodes_expanded"); 00063 collection.create("nodes_visited"); 00064 collection.create("iterations"); 00065 return collection; 00066 } 00067 00068 bool IDAStar::findPath(const Environment& env, int start, int target) 00069 { 00070 assert(env.isValidNodeId(start)); 00071 assert(env.isValidNodeId(target)); 00072 clock_t startTime = clock(); 00073 m_statistics.clear(); 00074 m_nodesExpanded = 0; 00075 m_nodesVisited = 0; 00076 m_env = &env; 00077 m_target = target; 00078 m_path.clear(); 00079 m_abortSearch = false; 00080 m_visitedNodes.resize(env.getNumberNodes()); 00081 fill(m_visitedNodes.begin(), m_visitedNodes.end(), ' '); 00082 if ( m_caching != NO_CACHING ) 00083 { 00084 m_cache.clear(); 00085 m_cache.resize(env.getNumberNodes()); 00086 } 00087 findPathIdaStar(start); 00088 m_statistics.get("aborted").add(m_abortSearch ? 1 : 0); 00089 double timeDiff = 00090 static_cast<double>(clock() - startTime) / CLOCKS_PER_SEC; 00091 m_statistics.get("cpu_time").add(timeDiff); 00092 m_statistics.get("nodes_expanded").add(m_nodesExpanded); 00093 m_statistics.get("nodes_visited").add(m_nodesVisited); 00094 m_statistics.get("path_length").add(m_path.size()); 00095 return true; 00096 } 00097 00098 void IDAStar::findPathIdaStar(int start) 00099 { 00100 const int maxFLimit = m_env->getNumberNodes() * m_env->getMaxCost(); 00101 int heuristic = m_env->getHeuristic(start, m_target); 00102 m_fLimit = heuristic; 00103 int minCost = m_env->getMinCost(); 00104 unsigned int expectedMaxDepth = 00105 static_cast<unsigned int>(heuristic / minCost); 00106 if (m_successorStack.size() < expectedMaxDepth) 00107 m_successorStack.resize(expectedMaxDepth); 00108 int iteration = 1; 00109 00110 while (true) 00111 { 00112 //cerr << "limit = " << m_fLimit << '\n'; 00113 int fMin = INT_MAX; 00114 searchPathIdaStar(iteration, start, NO_NODE, 0, 0, fMin); 00115 if (m_path.size() > 0) 00116 break; 00117 if (fMin > maxFLimit) 00118 break; 00119 m_fLimit = fMin; 00120 ++iteration; 00121 } 00122 m_statistics.get("iterations").add(iteration); 00123 } 00124 00125 const StatisticsCollection& IDAStar::getStatistics() const 00126 { 00127 return m_statistics; 00128 } 00129 00130 void IDAStar::markVisitedNode(int nodeId, int iteration) 00131 { 00132 if (m_visitedNodes[nodeId] != ' ') 00133 return; 00134 m_visitedNodes[nodeId] = getVisitedNodeLabel(iteration); 00135 } 00136 00137 bool IDAStar::searchPathIdaStar(int iteration, int node, int lastNode, 00138 int depth, int g, int& fMin) 00139 { 00140 ++m_nodesVisited; 00141 markVisitedNode(node, iteration); 00142 if (m_nodesLimit >= 0 && m_nodesVisited > m_nodesLimit) 00143 { 00144 m_abortSearch = true; 00145 fMin = INT_MAX; 00146 return false; 00147 } 00148 int f = g + m_env->getHeuristic(node, m_target); 00149 if (f > m_fLimit) 00150 { 00151 fMin = f; 00152 return false; 00153 } 00154 if (node == m_target) 00155 { 00156 m_statistics.get("path_cost").add(f); 00157 m_path.push_back(node); 00158 fMin = f; 00159 return true; 00160 } 00161 00162 if (m_caching != NO_CACHING) 00163 { 00164 if (checkCache(node, f, g, iteration, fMin)) 00165 { 00166 return false; 00167 } 00168 addCache(node, f, g, iteration); 00169 } 00170 00171 ++m_nodesExpanded; 00172 assert(depth >= 0); 00173 if (m_successorStack.size() < static_cast<unsigned int>(depth + 1)) 00174 m_successorStack.resize(depth + 1); 00175 vector<Environment::Successor>& successors = m_successorStack[depth]; 00176 m_env->getSuccessors(node, lastNode, successors); 00177 int numberSuccessors = successors.size(); 00178 m_branchingFactor.add(numberSuccessors); 00179 fMin = INT_MAX; 00180 for (int i = 0; i < numberSuccessors; ++i) 00181 { 00182 // Get reference on edge again, because resize could have changed it. 00183 const Environment::Successor& successor = m_successorStack[depth][i]; 00184 int targetNodeId = successor.m_target; 00185 int fMinChild; 00186 if (targetNodeId == lastNode) 00187 continue; 00188 if (searchPathIdaStar(iteration, targetNodeId, node, depth + 1, 00189 g + successor.m_cost, fMinChild)) 00190 { 00191 if ( fMinChild < fMin ) 00192 fMin = fMinChild; 00193 m_path.push_back(node); 00194 return true; 00195 } 00196 if ( fMinChild < fMin ) 00197 fMin = fMinChild; 00198 00199 if (m_abortSearch) 00200 return false; 00201 } 00202 00203 if ( m_caching == F_CACHING ) 00204 { 00205 if ( fMin > m_cache[node].m_f ) 00206 m_cache[node].m_f = fMin; 00207 } 00208 00209 return false; 00210 } 00211 00212 //-----------------------------------------------------------------------------