LEMUR Packages: ompl_lemur or_lemur pr_bgl prpy_lemur
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends Groups Pages
RoadmapCached.h
Go to the documentation of this file.
1 
7 namespace or_lemur
8 {
9 
10 // cached roadmap wrapper
11 
12 // the file format is binary
13 // first size_t: number of batches in file
14 // for each batch:
15 // first size_t: number of vertices in subgraph (cumulative)
16 // second size_t: number of edges in subgraph (cumulative)
17 // next vertices, then edges
18 // for each vertex:
19 // size_t is_shadow (0 or 1)
20 // dim * sizeof(double): state
21 // for each edge:
22 // size_t vidx_a
23 // size_t vidx_b
24 // double distance
25 // last, size_t: number of bytes in generator state
26 // followed by those bytes
27 //
28 
29 template <class RoadmapArgs>
30 class RoadmapCached : public ompl_lemur::Roadmap<RoadmapArgs>
31 {
32  typedef boost::graph_traits<typename RoadmapArgs::Graph> GraphTypes;
33  typedef typename GraphTypes::vertex_descriptor Vertex;
34  typedef typename GraphTypes::edge_descriptor Edge;
35 
36  // on construction
37  const boost::shared_ptr< ompl_lemur::Roadmap<RoadmapArgs> > _roadmap_wrapped;
38  unsigned int _dim;
39 
40  // parameters
41  bool _is_cache_required;
42 
43  // determined on initialization
44  std::string _cache_filename;
45 
46  std::ifstream _infile;
47  size_t _infile_num_batches;
48 
49  // these are the numbers that we've added to the actual graph
50  std::vector<size_t> vertices_in_subgraph;
51  std::vector<size_t> edges_in_subgraph;
52 
53 public:
54  RoadmapCached(RoadmapArgs & args,
55  boost::shared_ptr< ompl_lemur::Roadmap<RoadmapArgs> > roadmap_wrapped):
57  "Cached" + roadmap_wrapped->name,
58  roadmap_wrapped->max_batches),
59  _roadmap_wrapped(roadmap_wrapped),
60  _dim(roadmap_wrapped->space->getDimension()),
61  _is_cache_required(false)
62  {
63  // check that we're in a real vector state space
64  // for now, we only know how to serialize/deserialize these states!
65  if (roadmap_wrapped->space->getType() != ompl::base::STATE_SPACE_REAL_VECTOR)
66  throw std::runtime_error("RoadmapCached only supports real vector state spaces!");
67 
68  // cache_filename will be set on initialization based on wrapped roadmap's params
69  this->params.include(_roadmap_wrapped->params);
70 
71  this->template declareParam<bool>("is_cache_required", this,
72  &RoadmapCached::setIsCacheRequired,
73  &RoadmapCached::getIsCacheRequired);
74  }
75  ~RoadmapCached() {}
76 
77  void setIsCacheRequired(bool is_cache_required)
78  {
79  if (is_cache_required == _is_cache_required)
80  return;
81  if (this->initialized)
82  throw std::runtime_error("cannot set is_cache_required, already initialized!");
83  _is_cache_required = is_cache_required;
84  }
85 
86  bool getIsCacheRequired() const
87  {
88  return _is_cache_required;
89  }
90 
91  void initialize()
92  {
93  // compute the cache filename for this wrapped roadmap
94  std::string id = "space_id " + ompl_lemur::space_id(this->space)
95  + " roadmap_id " + ompl_lemur::roadmap_id(_roadmap_wrapped.get());
96  _cache_filename = "or_lemur/roadmap-" + OpenRAVE::utils::GetMD5HashString(id) + ".bin";
97 
98  _infile_num_batches = 0; // assume read failure
99  bool file_found = false;
100  do
101  {
102  size_t mysizet;
103  // search for file in openrave databases path
104  std::string path = OpenRAVE::RaveFindDatabaseFile(_cache_filename, true); // bRead
105  if (!path.size())
106  {
107  RAVELOG_WARN("Could not find cached roadmap file: %s\n", _cache_filename.c_str());
108  break;
109  }
110  _infile.open(path.c_str(), std::ofstream::binary);
111  if (!_infile.is_open())
112  {
113  RAVELOG_WARN("Could not open cached roadmap file: %s\n", _cache_filename.c_str());
114  break;
115  }
116  _infile.read((char *)&mysizet, sizeof(mysizet));
117  if (!_infile.good())
118  {
119  RAVELOG_WARN("Could not read cached roadmap file: %s\n", _cache_filename.c_str());
120  break;
121  }
122  _infile_num_batches = mysizet;
123  file_found = true;
124  RAVELOG_INFO("Found a file with %lu batches: %s\n", _infile_num_batches, _cache_filename.c_str());
125  }
126  while (0);
127 
128  if (!file_found && _is_cache_required)
129  {
130  throw std::runtime_error("RoadmapCached: cache file not found!");
131  }
132 
133  // initialize wrapped roadmap (so root_radius etc work)
134  _roadmap_wrapped->initialize();
135 
136  this->initialized = true;
137  }
138 
139  void deserialize(const std::string & ser_data)
140  {
141  throw std::runtime_error("RoadmapCached deserialize from ser_data not supported!");
142  }
143 
144  double root_radius(std::size_t i_batch)
145  {
146  return _roadmap_wrapped->root_radius(i_batch);
147  }
148 
149  void generate()
150  {
151  // ok, should we generate from the cache file?
152  if (this->num_batches_generated < _infile_num_batches)
153  {
154  // read batch size
155  size_t num_vertices_subgraph;
156  size_t num_edges_subgraph;
157  _infile.read((char *)&num_vertices_subgraph, sizeof(size_t));
158  _infile.read((char *)&num_edges_subgraph, sizeof(size_t));
159  RAVELOG_INFO("Found %lu vertices and %lu edges in cached subgraph.\n",
160  num_vertices_subgraph, num_edges_subgraph);
161 
162  // load vertices
163  for (size_t v_index=num_vertices(this->g); v_index<num_vertices_subgraph; v_index++)
164  {
165  size_t is_shadow;
166  ompl::base::State * v_state = this->space->allocState();
167  double * v_values = v_state->as<ompl::base::RealVectorStateSpace::StateType>()->values;
168 
169  _infile.read((char *)&is_shadow, sizeof(size_t));
170  _infile.read((char *)v_values, _dim*sizeof(double));
171 
172  if (!_infile.good())
173  throw std::runtime_error("error reading vertex from cache file!");
174 
175  //printf("adding vertex %lu at", v_index);
176  //for (unsigned int j=0; j<_dim; j++) printf(" %f", v_values[j]);
177  //printf("\n");
178 
179  Vertex v_new = add_vertex(this->g);
180  put(this->vertex_batch_map, v_new, this->num_batches_generated);
181  put(this->is_shadow_map, v_new, is_shadow ? true : false);
182  put(this->state_map, v_new, v_state);
183  this->nn->add(v_new);
184  }
185 
186  // load edges
187  for (size_t e_index=num_edges(this->g); e_index<num_edges_subgraph; e_index++)
188  {
189  size_t vidx_a;
190  size_t vidx_b;
191  double dist;
192 
193  _infile.read((char *)&vidx_a, sizeof(size_t));
194  _infile.read((char *)&vidx_b, sizeof(size_t));
195  _infile.read((char *)&dist, sizeof(double));
196 
197  if (!_infile.good())
198  throw std::runtime_error("error reading edge from cache file!");
199 
200  //printf("adding edge b/w %lu -- %lu\n", vidx_a, vidx_b);
201 
202  Vertex v_a = vertex(vidx_a, this->g);
203  Vertex v_b = vertex(vidx_b, this->g);
204  Edge e = add_edge(v_a, v_b, this->g).first;
205  put(this->distance_map, e, dist);
206  put(this->edge_batch_map, e, this->num_batches_generated);
207  }
208 
209  if (!_infile.good())
210  throw std::runtime_error("error reading from cache file!");
211 
212  // we've generated a batch
213  this->num_batches_generated++;
214  }
215  else
216  {
217  // we've generated num_batches_generated so far
218 
219  // is this the first one, after we generated something?
220  if (_infile_num_batches // there were batches in the file
221  && this->num_batches_generated // that we've generated
222  && !(_roadmap_wrapped->num_batches_generated)) // but wrapped hasn't yet!
223  {
224  // ok, there were batches we generated from the cache,
225  // and now we're using the wrapped roadmap for the rest
226 
227  // we should deserialize the generator state first
228  size_t ser_data_len;
229  _infile.read((char *)&ser_data_len, sizeof(size_t));
230  std::string ser_data;
231  ser_data.resize(ser_data_len);
232  _infile.read(&ser_data[0], ser_data_len);
233  _roadmap_wrapped->deserialize(ser_data);
234 
235  _roadmap_wrapped->num_batches_generated = this->num_batches_generated;
236 
237  _infile.close();
238  }
239 
240  _roadmap_wrapped->generate();
241 
242  this->num_batches_generated = _roadmap_wrapped->num_batches_generated;
243  }
244 
245  // remember to keep ours and the wrapped
246  // num_batches_generated synchronized!
247 
248  vertices_in_subgraph.push_back(num_vertices(this->g));
249  edges_in_subgraph.push_back(num_edges(this->g));
250  }
251 
252  void save_file() const
253  {
254  size_t mysizet;
255 
256  // TODO: skip of we've generated into the the graph
257  // fewer batches than the file has!
258  if (_roadmap_wrapped->num_batches_generated <= _infile_num_batches)
259  return;
260 
261  RAVELOG_INFO("Saving file ...\n");
262 
263  std::string path = OpenRAVE::RaveFindDatabaseFile(_cache_filename, false); // bRead
264  if (!path.size())
265  throw OpenRAVE::openrave_exception("couldn't find a place to write rave database entry!");
266  boost::filesystem::create_directories(boost::filesystem::path(path).parent_path());
267 
268  std::ofstream outfile(path.c_str(), std::ofstream::binary);
269 
270  // write number of batches
271 
272  mysizet = _roadmap_wrapped->num_batches_generated;
273  outfile.write((const char*)&mysizet, sizeof(mysizet));
274 
275  // for each generated batch, write the vertices and edges!
276  size_t v_index = 0;
277  size_t e_index = 0;
278  for (size_t i_batch=0; i_batch<_roadmap_wrapped->num_batches_generated; i_batch++)
279  {
280  mysizet = vertices_in_subgraph[i_batch];
281  outfile.write((const char*)&mysizet, sizeof(mysizet));
282  mysizet = edges_in_subgraph[i_batch];
283  outfile.write((const char*)&mysizet, sizeof(mysizet));
284 
285  // write out the vertices for this batch
286  for (; v_index<vertices_in_subgraph[i_batch]; v_index++)
287  {
288  Vertex v = vertex(v_index,this->g);
289 
290  mysizet = get(this->is_shadow_map, v) ? 1 : 0;
291  outfile.write((const char*)&mysizet, sizeof(mysizet));
292 
293  ompl::base::State * v_state = get(this->state_map, v);
294  double * v_values = v_state->as<ompl::base::RealVectorStateSpace::StateType>()->values;
295  outfile.write((const char*)v_values, _dim*sizeof(double));
296  }
297 
298  // write out the edges for this batch
299  for (; e_index<edges_in_subgraph[i_batch]; e_index++)
300  {
301  size_t vidx_a;
302  size_t vidx_b;
303  double dist;
304 
305  // get the edge by its index somehow!
306  Edge e = get(this->edge_vector_map, e_index);
307  Vertex v_a = source(e, this->g);
308  Vertex v_b = target(e, this->g);
309 
310  vidx_a = v_a;
311  vidx_b = v_b;
312  dist = get(this->distance_map, e);
313 
314  outfile.write((const char*)&vidx_a, sizeof(size_t));
315  outfile.write((const char*)&vidx_b, sizeof(size_t));
316  outfile.write((const char*)&dist, sizeof(double));
317  }
318  }
319 
320  // next we must save the generator state!!!
321  std::string data;
322  _roadmap_wrapped->serialize(data);
323  mysizet = data.size();
324  outfile.write((const char*)&mysizet, sizeof(mysizet));
325  outfile.write(data.data(), data.size());
326  }
327 
328  void serialize(std::string & ser_data)
329  {
330  throw std::runtime_error("RoadmapCached serialize to ser_data not supported!");
331  }
332 };
333 
334 
335 template <class RoadmapArgs>
337 {
338 public:
339  boost::function<ompl_lemur::Roadmap<RoadmapArgs> * (RoadmapArgs args)> _factory;
340 
342  boost::function<ompl_lemur::Roadmap<RoadmapArgs> * (RoadmapArgs args)> factory):
343  _factory(factory)
344  {
345  }
346 
347  ompl_lemur::Roadmap<RoadmapArgs> * operator()(RoadmapArgs args) const
348  {
349  boost::shared_ptr< ompl_lemur::Roadmap<RoadmapArgs> > roadmap_wrapped(_factory(args));
350  return new RoadmapCached<RoadmapArgs>(args, roadmap_wrapped);
351  };
352 };
353 
354 } // namespace or_lemur
Definition: RoadmapCached.h:336
Definition: RoadmapCached.h:30
const T * as() const