ThunderDB.cpp
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2014, JSK, The University of Tokyo.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following
15  * disclaimer in the documentation and/or other materials provided
16  * with the distribution.
17  * * Neither the name of the JSK, The University of Tokyo nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *********************************************************************/
34 
35 /* Author: Dave Coleman */
36 
37 // OMPL
38 #include <ompl/tools/thunder/ThunderDB.h>
39 #include <ompl/base/ScopedState.h>
40 #include <ompl/util/Time.h>
41 #include <ompl/util/Console.h>
42 #include <ompl/tools/config/SelfConfig.h>
43 #include <ompl/base/PlannerDataStorage.h>
44 
45 // Boost
46 #include <boost/filesystem.hpp>
47 
49  : numPathsInserted_(0)
50  , saving_enabled_(true)
51 {
52  // Set space information
53  si_.reset(new base::SpaceInformation(space));
54 }
55 
57 {
58  if (numPathsInserted_)
59  OMPL_WARN("The database is being unloaded with unsaved experiences");
60 }
61 
62 bool ompl::tools::ThunderDB::load(const std::string& fileName)
63 {
64  // Error checking
65  if (fileName.empty())
66  {
67  OMPL_ERROR("Empty filename passed to save function");
68  return false;
69  }
70  if ( !boost::filesystem::exists( fileName ) )
71  {
72  OMPL_INFORM("Database file does not exist: %s.", fileName.c_str());
73  return false;
74  }
75  if (!spars_)
76  {
77  OMPL_ERROR("SPARSdb planner has not been passed into the ThunderDB yet");
78  return false;
79  }
80 
81  // Load database from file, track loading time
82  time::point start = time::now();
83 
84  OMPL_INFORM("Loading database from file: %s", fileName.c_str());
85 
86  // Open a binary input stream
87  std::ifstream iStream(fileName.c_str(), std::ios::binary);
88 
89  // Get the total number of paths saved
90  double numPaths = 0;
91  iStream >> numPaths;
92 
93  // Check that the number of paths makes sense
94  if (numPaths < 0 || numPaths > std::numeric_limits<double>::max())
95  {
96  OMPL_WARN("Number of paths to load %d is a bad value", numPaths);
97  return false;
98  }
99 
100  if (numPaths > 1)
101  {
102  OMPL_ERROR("Currently more than one planner data is disabled from loading");
103  return false;
104  }
105 
106  // Create a new planner data instance
108 
109  // Note: the StateStorage class checks if the states match for us
110  plannerDataStorage_.load(iStream, *plannerData.get());
111 
112  OMPL_INFORM("ThunderDB: Loaded planner data with \n %d vertices\n %d edges\n %d start states\n %d goal states",
113  plannerData->numVertices(), plannerData->numEdges(), plannerData->numStartVertices(), plannerData->numGoalVertices());
114 
115  // Add to SPARSdb
116  OMPL_INFORM("Adding plannerData to SPARSdb:");
117  spars_->setPlannerData(*plannerData);
118 
119  // Output the number of connected components
120  OMPL_INFORM(" %d connected components", spars_->getNumConnectedComponents());
121 
122  // Close file
123  iStream.close();
124 
125  double loadTime = time::seconds(time::now() - start);
126  OMPL_INFORM("Loaded database from file in %f sec ", loadTime);
127  return true;
128 }
129 
130 bool ompl::tools::ThunderDB::addPath(ompl::geometric::PathGeometric& solutionPath, double &insertionTime)
131 {
132  // Error check
133  if (!spars_)
134  {
135  OMPL_ERROR("SPARSdb planner has not been passed into the ThunderDB yet");
136  insertionTime = 0;
137  return false;
138  }
139 
140  // Prevent inserting into database
141  if (!saving_enabled_)
142  {
143  OMPL_WARN("ThunderDB: Saving is disabled so not adding path");
144  return false;
145  }
146 
147  bool result;
148  double seconds = 120; //10; // a large number, should never need to use this
150 
151  // Benchmark runtime
152  time::point startTime = time::now();
153  {
154  result = spars_->addPathToRoadmap(ptc, solutionPath);
155  }
156  insertionTime = time::seconds(time::now() - startTime);
157 
158  OMPL_INFORM("SPARSdb now has %d states", spars_->getNumVertices());
159 
160  // Record this new addition
161  numPathsInserted_++;
162 
163  return result;
164 }
165 
166 bool ompl::tools::ThunderDB::saveIfChanged(const std::string& fileName)
167 {
168  if (numPathsInserted_)
169  return save(fileName);
170  else
171  OMPL_INFORM("Not saving because database has not changed");
172  return true;
173 }
174 
175 bool ompl::tools::ThunderDB::save(const std::string& fileName)
176 {
177  // Disabled
178  if (!saving_enabled_)
179  {
180  OMPL_WARN("Not saving because option disabled for ExperienceDB");
181  return false;
182  }
183 
184  // Error checking
185  if (fileName.empty())
186  {
187  OMPL_ERROR("Empty filename passed to save function");
188  return false;
189  }
190  if (!spars_)
191  {
192  OMPL_ERROR("SPARSdb planner has not been passed into the ThunderDB yet");
193  return false;
194  }
195 
196  // Save database from file, track saving time
197  time::point start = time::now();
198 
199  OMPL_INFORM("Saving database to file: %s", fileName.c_str());
200 
201  // Open a binary output stream
202  std::ofstream outStream(fileName.c_str(), std::ios::binary);
203 
204  // Populate multiple planner Datas
205  std::vector<ompl::base::PlannerDataPtr> plannerDatas;
206 
207  // TODO: make this more than 1 planner data perhaps
209  spars_->getPlannerData(*data);
210  OMPL_INFORM("Get planner data from SPARS2 with \n %d vertices\n %d edges\n %d start states\n %d goal states",
211  data->numVertices(), data->numEdges(), data->numStartVertices(), data->numGoalVertices());
212 
213  plannerDatas.push_back(data);
214 
215  // Write the number of paths we will be saving
216  double numPaths = plannerDatas.size();
217  outStream << numPaths;
218 
219  // Start saving each planner data object
220  for (std::size_t i = 0; i < numPaths; ++i)
221  {
222  ompl::base::PlannerData &pd = *plannerDatas[i].get();
223 
224  OMPL_INFORM("Saving experience %d with %d verticies and %d edges", i, pd.numVertices(), pd.numEdges());
225 
226  if (false) // debug code
227  {
228  for (std::size_t i = 0; i < pd.numVertices(); ++i)
229  {
230  OMPL_INFORM("Vertex %d:", i);
231  debugVertex(pd.getVertex(i));
232  }
233  }
234 
235  // Save a single planner data
236  plannerDataStorage_.store(pd, outStream);
237  }
238 
239  // Close file
240  outStream.close();
241 
242  // Benchmark
243  double loadTime = time::seconds(time::now() - start);
244  OMPL_INFORM("Saved database to file in %f sec with %d planner datas", loadTime, plannerDatas.size());
245 
246  numPathsInserted_ = 0;
247 
248  return true;
249 }
250 
252 {
253  // OMPL_INFORM("-------------------------------------------------------");
254  // OMPL_INFORM("setSPARSdb ");
255  // OMPL_INFORM("-------------------------------------------------------");
256  spars_ = prm;
257 }
258 
260 {
261  return spars_;
262 }
263 
264 void ompl::tools::ThunderDB::getAllPlannerDatas(std::vector<ompl::base::PlannerDataPtr> &plannerDatas) const
265 {
266  if (!spars_)
267  {
268  OMPL_ERROR("SPARSdb planner has not been passed into the ThunderDB yet");
269  return;
270  }
271 
273  spars_->getPlannerData(*data);
274  plannerDatas.push_back(data);
275 
276  //OMPL_DEBUG("ThunderDB::getAllPlannerDatas: Number of planner databases found: %d", plannerDatas.size());
277 }
278 
279 bool ompl::tools::ThunderDB::findNearestStartGoal(int nearestK, const base::State* start, const base::State* goal,
282 {
283  bool result = spars_->getSimilarPaths(nearestK, start, goal, candidateSolution, ptc);
284 
285  if (!result)
286  {
287  OMPL_INFORM("RETRIEVE COULD NOT FIND SOLUTION ");
288  OMPL_INFORM("spars::getSimilarPaths() returned false - retrieve could not find solution");
289  return false;
290  }
291 
292  OMPL_INFORM("spars::getSimilarPaths() returned true - found a solution of size %d",
293  candidateSolution.getStateCount());
294  return true;
295 }
296 
298 {
299  debugState(vertex.getState());
300 }
301 
302 void ompl::tools::ThunderDB::debugState(const ompl::base::State* state)
303 {
304  si_->printState(state, std::cout);
305 }
306 
ompl::tools::SPARSdbPtr & getSPARSdb()
Hook for debugging.
Definition: ThunderDB.cpp:259
base::SpaceInformationPtr si_
The created space information.
Definition: ThunderDB.h:163
bool save(const std::string &fileName)
Save loaded database to file.
Definition: ThunderDB.cpp:175
Object containing planner generated vertex and edge data. It is assumed that all vertices are unique...
Definition: PlannerData.h:163
A shared pointer wrapper for ompl::base::StateSpace.
Encapsulate a termination condition for a motion planner. Planners will call operator() to decide whe...
Struct for passing around partially solved solutions.
Definition: SPARSdb.h:240
bool findNearestStartGoal(int nearestK, const base::State *start, const base::State *goal, ompl::geometric::SPARSdb::CandidateSolution &candidateSolution, const base::PlannerTerminationCondition &ptc)
Find the k nearest paths to our queries one.
Definition: ThunderDB.cpp:279
virtual ~ThunderDB(void)
Deconstructor.
Definition: ThunderDB.cpp:56
Base class for a vertex in the PlannerData structure. All derived classes must implement the clone an...
Definition: PlannerData.h:59
duration seconds(double sec)
Return the time duration representing a given number of seconds.
Definition: Time.h:78
PlannerTerminationCondition timedPlannerTerminationCondition(double duration)
Return a termination condition that will become true duration seconds in the future (wall-time) ...
bool addPath(ompl::geometric::PathGeometric &solutionPath, double &insertionTime)
Add a new solution path to our database. Des not actually save to file so experience will be lost if ...
Definition: ThunderDB.cpp:130
#define OMPL_ERROR(fmt,...)
Log a formatted error string.
Definition: Console.h:64
void getAllPlannerDatas(std::vector< ompl::base::PlannerDataPtr > &plannerDatas) const
Get a vector of all the planner datas in the database.
Definition: ThunderDB.cpp:264
unsigned int numEdges() const
Retrieve the number of edges in this structure.
unsigned int numVertices() const
Retrieve the number of vertices in this structure.
const PlannerDataVertex & getVertex(unsigned int index) const
Retrieve a reference to the vertex object with the given index. If this vertex does not exist...
The base class for space information. This contains all the information about the space planning is d...
bool load(const std::string &fileName)
Load database from file.
Definition: ThunderDB.cpp:62
Definition of an abstract state.
Definition: State.h:50
#define OMPL_WARN(fmt,...)
Log a formatted warning string.
Definition: Console.h:66
point now()
Get the current time point.
Definition: Time.h:72
ThunderDB(const base::StateSpacePtr &space)
Constructor needs the state space used for planning.
Definition: ThunderDB.cpp:48
void setSPARSdb(ompl::tools::SPARSdbPtr &prm)
Create the database structure for saving experiences.
Definition: ThunderDB.cpp:251
void debugVertex(const ompl::base::PlannerDataVertex &vertex)
Print info to screen.
Definition: ThunderDB.cpp:297
Definition of a geometric path.
Definition: PathGeometric.h:60
std::chrono::system_clock::time_point point
Representation of a point in time.
Definition: Time.h:66
bool saveIfChanged(const std::string &fileName)
Save loaded database to file, except skips saving if no paths have been added.
Definition: ThunderDB.cpp:166
std::shared_ptr< ompl::geometric::SPARSdb > SPARSdbPtr
Definition: ThunderDB.h:65
virtual const State * getState() const
Retrieve the state associated with this vertex.
Definition: PlannerData.h:73
A shared pointer wrapper for ompl::base::PlannerData.
#define OMPL_INFORM(fmt,...)
Log a formatted information string.
Definition: Console.h:68