00001
00002
00003
00004
00005
00006
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
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
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
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