MRPT  1.9.9
CAStarAlgorithm.h
Go to the documentation of this file.
1 /* +------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | http://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2018, Individual contributors, see AUTHORS file |
6  | See: http://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See details in http://www.mrpt.org/License |
8  +------------------------------------------------------------------------+ */
9 #ifndef CASTARALGORITHM_H
10 #define CASTARALGORITHM_H
11 #include <map>
12 #include <vector>
13 #include <cmath>
14 #include <mrpt/system/CTicTac.h>
15 
16 namespace mrpt::graphs
17 {
18 /** This class is intended to efficiently solve graph-search problems using
19  * heuristics to determine the best path. To use it, a solution class must be
20  * defined
21  * so that it contains all the information about any partial or complete
22  * solution. Then, a class inheriting from CAStarAlgorithm<Solution class> must
23  * also be
24  * implemented, overriding five virtual methods which define the behaviour of
25  * the solutions. These methods are isSolutionEnded, isSolutionValid,
26  * generateChildren, getHeuristic and getCost.
27  * Once both classes are generated, each object of the class inheriting from
28  * CAStarAlgorithm represents a problem who can be solved by calling
29  * getOptimalSolution. See http://en.wikipedia.org/wiki/A*_search_algorithm for
30  * details about how this algorithm works.
31  * \sa CAStarAlgorithm::isSolutionEnded
32  * \sa CAStarAlgorithm::isSolutionValid
33  * \sa CAStarAlgorithm::generateChildren
34  * \sa CAStarAlgorithm::getHeuristic
35  * \sa CAStarAlgorithm::getCost
36  * \ingroup mrpt_graphs_grp
37  */
38 template <typename T>
40 {
41  public:
42  /**
43  * Client code must implement this method.
44  * Returns true if the given solution is complete.
45  */
46  virtual bool isSolutionEnded(const T& sol) = 0;
47  /**
48  * Client code must implement this method.
49  * Returns true if the given solution is acceptable, that is, doesn't
50  * violate the problem logic.
51  */
52  virtual bool isSolutionValid(const T& sol) = 0;
53  /**
54  * Client code must implement this method.
55  * Given a partial solution, returns all its children solution, regardless
56  * of their validity or completeness.
57  */
58  virtual void generateChildren(const T& sol, std::vector<T>& sols) = 0;
59  /**
60  * Client code must implement this method.
61  * Given a partial solution, estimates the cost of the remaining (unknown)
62  * part.
63  * This cost must always be greater or equal to zero, and not greater than
64  * the actual cost. Thus, must be 0 if the solution is complete.
65  */
66  virtual double getHeuristic(const T& sol) = 0;
67  /**
68  * Client code must implement this method.
69  * Given a (possibly partial) solution, calculates its cost so far.
70  * This cost must not decrease with each step. That is, a solution cannot
71  * have a smaller cost than the previous one from which it was generated.
72  */
73  virtual double getCost(const T& sol) = 0;
74 
75  private:
76  /**
77  * Calculates the total cost (known+estimated) of a solution.
78  */
79  inline double getTotalCost(const T& sol)
80  {
81  return getHeuristic(sol) + getCost(sol);
82  }
83 
84  public:
85  /**
86  * Finds the optimal solution for a problem, using the A* algorithm.
87  * Returns whether an optimal solution was actually found.
88  * Returns 0 if no solution was found, 1 if an optimal solution was found
89  * and 2 if a (possibly suboptimal) solution was found but the time lapse
90  * ended.
91  */
93  const T& initialSol, T& finalSol, double upperLevel = HUGE_VAL,
94  double maxComputationTime = HUGE_VAL)
95  {
96  // Time measuring object is defined.
98  time.Tic();
99  // The partial solution set is initialized with a single element (the
100  // starting solution).
101  std::multimap<double, T> partialSols;
102  partialSols.insert(
103  std::pair<double, T>(getTotalCost(initialSol), initialSol));
104  // The best known solution is set to the upper bound (positive infinite,
105  // if there is no given parameter).
106  double currentOptimal = upperLevel;
107  bool found = false;
108  std::vector<T> children;
109  // Main loop. Each iteration checks an element of the set, with minimum
110  // estimated cost.
111  while (!partialSols.empty())
112  {
113  // Return if elapsed time has been reached.
114  if (time.Tac() >= maxComputationTime) return found ? 2 : 0;
116  partialSols.begin();
117  double tempCost = it->first;
118  // If the minimum estimated cost is higher than the upper bound,
119  // then also is every solution in the set. So the algorithm returns
120  // immediately.
121  if (tempCost >= currentOptimal) return found ? 1 : 0;
122  T tempSol = it->second;
123  partialSols.erase(it);
124  // At this point, the solution cost is lesser than the upper bound.
125  // So, if the solution is complete, the optimal solution and the
126  // upper bound are updated.
127  if (isSolutionEnded(tempSol))
128  {
129  currentOptimal = tempCost;
130  finalSol = tempSol;
131  found = true;
132  continue;
133  }
134  // If the solution is not complete, check for its children. Each one
135  // is included in the set only if it's valid and it's not yet
136  // present in the set.
137  generateChildren(tempSol, children);
138  for (typename std::vector<T>::const_iterator it2 = children.begin();
139  it2 != children.end(); ++it2)
140  if (isSolutionValid(*it2))
141  {
142  bool alreadyPresent = false;
143  double cost = getTotalCost(*it2);
144  typename std::pair<
147  range = partialSols.equal_range(cost);
148  for (typename std::multimap<double, T>::const_iterator it3 =
149  range.first;
150  it3 != range.second; ++it3)
151  if (it3->second == *it2)
152  {
153  alreadyPresent = true;
154  break;
155  }
156  if (!alreadyPresent)
157  partialSols.insert(
158  std::pair<double, T>(getTotalCost(*it2), *it2));
159  }
160  }
161  // No more solutions to explore...
162  return found ? 1 : 0;
163  }
164 };
165 }
166 #endif
167 
168 
double Tac() noexcept
Stops the stopwatch.
Definition: CTicTac.cpp:90
GLsizei range
Definition: glext.h:5907
Scalar * iterator
Definition: eigen_plugins.h:26
Abstract graph and tree data structures, plus generic graph algorithms.
virtual bool isSolutionEnded(const T &sol)=0
Client code must implement this method.
A high-performance stopwatch, with typical resolution of nanoseconds.
double getTotalCost(const T &sol)
Calculates the total cost (known+estimated) of a solution.
virtual void generateChildren(const T &sol, std::vector< T > &sols)=0
Client code must implement this method.
virtual bool isSolutionValid(const T &sol)=0
Client code must implement this method.
This class is intended to efficiently solve graph-search problems using heuristics to determine the b...
int getOptimalSolution(const T &initialSol, T &finalSol, double upperLevel=HUGE_VAL, double maxComputationTime=HUGE_VAL)
Finds the optimal solution for a problem, using the A* algorithm.
virtual double getCost(const T &sol)=0
Client code must implement this method.
virtual double getHeuristic(const T &sol)=0
Client code must implement this method.
void Tic() noexcept
Starts the stopwatch.
Definition: CTicTac.cpp:79
const Scalar * const_iterator
Definition: eigen_plugins.h:27



Page generated by Doxygen 1.8.14 for MRPT 1.9.9 Git: 7d5e6d718 Fri Aug 24 01:51:28 2018 +0200 at lun nov 2 08:35:50 CET 2020