g2o
estimate_propagator.cpp
Go to the documentation of this file.
1 // g2o - General Graph Optimization
2 // Copyright (C) 2011 R. Kuemmerle, G. Grisetti, W. Burgard
3 // All rights reserved.
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 // * Redistributions of source code must retain the above copyright notice,
10 // this list of conditions and the following disclaimer.
11 // * Redistributions in binary form must reproduce the above copyright
12 // notice, this list of conditions and the following disclaimer in the
13 // documentation and/or other materials provided with the distribution.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
16 // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17 // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
18 // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19 // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
21 // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 
27 #include "estimate_propagator.h"
28 
29 #include <queue>
30 #include <vector>
31 #include <cassert>
32 #include <iostream>
33 #include <algorithm>
34 #include <fstream>
35 
36 //#define DEBUG_ESTIMATE_PROPAGATOR
37 
38 using namespace std;
39 
40 namespace g2o {
41 
42 # ifdef DEBUG_ESTIMATE_PROPAGATOR
43  struct FrontierLevelCmp {
44  bool operator()(EstimatePropagator::AdjacencyMapEntry* e1, EstimatePropagator::AdjacencyMapEntry* e2) const
45  {
46  return e1->frontierLevel() < e2->frontierLevel();
47  }
48  };
49 # endif
50 
51  EstimatePropagator::AdjacencyMapEntry::AdjacencyMapEntry()
52  {
53  reset();
54  }
55 
56  void EstimatePropagator::AdjacencyMapEntry::reset()
57  {
58  _child = 0;
59  _parent.clear();
60  _edge = 0;
61  _distance = numeric_limits<double>::max();
62  _frontierLevel = -1;
63  inQueue = false;
64  }
65 
66  EstimatePropagator::EstimatePropagator(OptimizableGraph* g): _graph(g)
67  {
68  for (OptimizableGraph::VertexIDMap::const_iterator it=_graph->vertices().begin(); it!=_graph->vertices().end(); ++it){
69  AdjacencyMapEntry entry;
70  entry._child = static_cast<OptimizableGraph::Vertex*>(it->second);
71  _adjacencyMap.insert(make_pair(entry.child(), entry));
72  }
73  }
74 
76  {
77  for (OptimizableGraph::VertexSet::iterator it=_visited.begin(); it!=_visited.end(); ++it){
78  OptimizableGraph::Vertex* v = static_cast<OptimizableGraph::Vertex*>(*it);
79  AdjacencyMap::iterator at = _adjacencyMap.find(v);
80  assert(at != _adjacencyMap.end());
81  at->second.reset();
82  }
83  _visited.clear();
84  }
85 
89  double maxDistance,
90  double maxEdgeCost)
91  {
93  vset.insert(v);
94  propagate(vset, cost, action, maxDistance, maxEdgeCost);
95  }
96 
100  double maxDistance,
101  double maxEdgeCost)
102  {
103  reset();
104 
105  PriorityQueue frontier;
106  for (OptimizableGraph::VertexSet::iterator vit=vset.begin(); vit!=vset.end(); ++vit){
107  OptimizableGraph::Vertex* v = static_cast<OptimizableGraph::Vertex*>(*vit);
108  AdjacencyMap::iterator it = _adjacencyMap.find(v);
109  assert(it != _adjacencyMap.end());
110  it->second._distance = 0.;
111  it->second._parent.clear();
112  it->second._frontierLevel = 0;
113  frontier.push(&it->second);
114  }
115 
116  while(! frontier.empty()){
117  AdjacencyMapEntry* entry = frontier.pop();
118  OptimizableGraph::Vertex* u = entry->child();
119  double uDistance = entry->distance();
120  //cerr << "uDistance " << uDistance << endl;
121 
122  // initialize the vertex
123  if (entry->_frontierLevel > 0) {
124  action(entry->edge(), entry->parent(), u);
125  }
126 
127  /* std::pair< OptimizableGraph::VertexSet::iterator, bool> insertResult = */ _visited.insert(u);
128  OptimizableGraph::EdgeSet::iterator et = u->edges().begin();
129  while (et != u->edges().end()){
130  OptimizableGraph::Edge* edge = static_cast<OptimizableGraph::Edge*>(*et);
131  ++et;
132 
133  int maxFrontier = -1;
134  OptimizableGraph::VertexSet initializedVertices;
135  for (size_t i = 0; i < edge->vertices().size(); ++i) {
136  OptimizableGraph::Vertex* z = static_cast<OptimizableGraph::Vertex*>(edge->vertex(i));
137  if (! z)
138  continue;
139  AdjacencyMap::iterator ot = _adjacencyMap.find(z);
140  if (ot->second._distance != numeric_limits<double>::max()) {
141  initializedVertices.insert(z);
142  maxFrontier = (max)(maxFrontier, ot->second._frontierLevel);
143  }
144  }
145  assert(maxFrontier >= 0);
146 
147  for (size_t i = 0; i < edge->vertices().size(); ++i) {
148  OptimizableGraph::Vertex* z = static_cast<OptimizableGraph::Vertex*>(edge->vertex(i));
149  if (! z)
150  continue;
151  if (z == u)
152  continue;
153  size_t wasInitialized = initializedVertices.erase(z);
154 
155  double edgeDistance = cost(edge, initializedVertices, z);
156  if (edgeDistance > 0. && edgeDistance != std::numeric_limits<double>::max() && edgeDistance < maxEdgeCost) {
157  double zDistance = uDistance + edgeDistance;
158  //cerr << z->id() << " " << zDistance << endl;
159 
160  AdjacencyMap::iterator ot = _adjacencyMap.find(z);
161  assert(ot!=_adjacencyMap.end());
162 
163  if (zDistance < ot->second.distance() && zDistance < maxDistance){
164  //if (ot->second.inQueue)
165  //cerr << "Updating" << endl;
166  ot->second._distance = zDistance;
167  ot->second._parent = initializedVertices;
168  ot->second._edge = edge;
169  ot->second._frontierLevel = maxFrontier + 1;
170  frontier.push(&ot->second);
171  }
172  }
173 
174  if (wasInitialized > 0)
175  initializedVertices.insert(z);
176 
177  }
178  }
179  }
180 
181  // writing debug information like cost for reaching each vertex and the parent used to initialize
182 #ifdef DEBUG_ESTIMATE_PROPAGATOR
183  cerr << "Writing cost.dat" << endl;
184  ofstream costStream("cost.dat");
185  for (AdjacencyMap::const_iterator it = _adjacencyMap.begin(); it != _adjacencyMap.end(); ++it) {
186  HyperGraph::Vertex* u = it->second.child();
187  costStream << "vertex " << u->id() << " cost " << it->second._distance << endl;
188  }
189  cerr << "Writing init.dat" << endl;
190  ofstream initStream("init.dat");
191  vector<AdjacencyMapEntry*> frontierLevels;
192  for (AdjacencyMap::iterator it = _adjacencyMap.begin(); it != _adjacencyMap.end(); ++it) {
193  if (it->second._frontierLevel > 0)
194  frontierLevels.push_back(&it->second);
195  }
196  sort(frontierLevels.begin(), frontierLevels.end(), FrontierLevelCmp());
197  for (vector<AdjacencyMapEntry*>::const_iterator it = frontierLevels.begin(); it != frontierLevels.end(); ++it) {
198  AdjacencyMapEntry* entry = *it;
199  OptimizableGraph::Vertex* to = entry->child();
200 
201  initStream << "calling init level = " << entry->_frontierLevel << "\t (";
202  for (OptimizableGraph::VertexSet::iterator pit = entry->parent().begin(); pit != entry->parent().end(); ++pit) {
203  initStream << " " << (*pit)->id();
204  }
205  initStream << " ) -> " << to->id() << endl;
206  }
207 #endif
208 
209  }
210 
212  {
213  assert(entry != NULL);
214  if (entry->inQueue) {
215  assert(entry->queueIt->second == entry);
216  erase(entry->queueIt);
217  }
218 
219  entry->queueIt = insert(std::make_pair(entry->distance(), entry));
220  assert(entry->queueIt != end());
221  entry->inQueue = true;
222  }
223 
225  {
226  assert(!empty());
227  iterator it = begin();
228  AdjacencyMapEntry* entry = it->second;
229  erase(it);
230 
231  assert(entry != NULL);
232  entry->queueIt = end();
233  entry->inQueue = false;
234  return entry;
235  }
236 
238  _graph(graph)
239  {
240  }
241 
243  {
244  OptimizableGraph::Edge* e = dynamic_cast<OptimizableGraph::Edge*>(edge);
245  OptimizableGraph::Vertex* to = dynamic_cast<OptimizableGraph::Vertex*>(to_);
246  SparseOptimizer::EdgeContainer::const_iterator it = _graph->findActiveEdge(e);
247  if (it == _graph->activeEdges().end()) // it has to be an active edge
248  return std::numeric_limits<double>::max();
249  return e->initialEstimatePossible(from, to);
250  }
251 
254  {
255  }
256 
258  {
259  OptimizableGraph::Edge* e = dynamic_cast<OptimizableGraph::Edge*>(edge);
260  OptimizableGraph::Vertex* from = dynamic_cast<OptimizableGraph::Vertex*>(*from_.begin());
261  OptimizableGraph::Vertex* to = dynamic_cast<OptimizableGraph::Vertex*>(to_);
262  if (std::abs(from->id() - to->id()) != 1) // simple method to identify odometry edges in a pose graph
263  return std::numeric_limits<double>::max();
264  SparseOptimizer::EdgeContainer::const_iterator it = _graph->findActiveEdge(e);
265  if (it == _graph->activeEdges().end()) // it has to be an active edge
266  return std::numeric_limits<double>::max();
267  return e->initialEstimatePossible(from_, to);
268  }
269 
270 } // end namespace
int id() const
returns the id
Definition: hyper_graph.h:148
const Vertex * vertex(size_t i) const
Definition: hyper_graph.h:186
EstimatePropagatorCost(SparseOptimizer *graph)
std::set< Vertex * > VertexSet
Definition: hyper_graph.h:136
OptimizableGraph::VertexSet _visited
virtual double initialEstimatePossible(const OptimizableGraph::VertexSet &from, OptimizableGraph::Vertex *to)
Applying the action for propagating.
virtual double operator()(OptimizableGraph::Edge *edge, const OptimizableGraph::VertexSet &from, OptimizableGraph::Vertex *to_) const
const EdgeContainer & activeEdges() const
the edges active in the current optimization
const VertexIDMap & vertices() const
Definition: hyper_graph.h:225
OptimizableGraph * graph()
data structure for loopuk during Dijkstra
const VertexContainer & vertices() const
Definition: hyper_graph.h:178
const EdgeSet & edges() const
returns the set of hyper-edges that are leaving/entering in this vertex
Definition: hyper_graph.h:151
OptimizableGraph::Vertex * child() const
const OptimizableGraph::VertexSet & parent() const
EstimatePropagatorCostOdometry(SparseOptimizer *graph)
void propagate(OptimizableGraph::Vertex *v, const EstimatePropagator::PropagateCost &cost, const EstimatePropagator::PropagateAction &action=PropagateAction(), double maxDistance=std::numeric_limits< double >::max(), double maxEdgeCost=std::numeric_limits< double >::max())
cost for traversing along active edges in the optimizer
OptimizableGraph::Edge * edge() const
A general case Vertex for optimization.
abstract Vertex, your types must derive from that one
Definition: hyper_graph.h:142
EdgeContainer::const_iterator findActiveEdge(const OptimizableGraph::Edge *e) const
virtual double operator()(OptimizableGraph::Edge *edge, const OptimizableGraph::VertexSet &from_, OptimizableGraph::Vertex *to_) const
Protocol The SLAM executable accepts such as solving the and retrieving or vertices in the graph
Definition: protocol.txt:7
priority queue for AdjacencyMapEntry