cleanup, bugfixes, timing
							parent
							
								
									1ba97ef62c
								
							
						
					
					
						commit
						0c48c7cdf4
					
				| 
						 | 
				
			
			@ -18,6 +18,83 @@ using namespace boost::assign;
 | 
			
		|||
#include <gtsam/inference/BayesTree-inl.h>
 | 
			
		||||
#include <gtsam/inference/ISAM2.h>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#if 1 // timing
 | 
			
		||||
#include <sys/time.h>
 | 
			
		||||
 | 
			
		||||
// simple class for accumulating execution timing information by name
 | 
			
		||||
class Timing {
 | 
			
		||||
  class Stats {
 | 
			
		||||
  public:
 | 
			
		||||
    double t0;
 | 
			
		||||
    double t;
 | 
			
		||||
    double t_max;
 | 
			
		||||
    double t_min;
 | 
			
		||||
    int n;
 | 
			
		||||
  };
 | 
			
		||||
  map<string, Stats> stats;
 | 
			
		||||
public:
 | 
			
		||||
  void add_t0(string id, double t0) {
 | 
			
		||||
    stats[id].t0 = t0;
 | 
			
		||||
  }
 | 
			
		||||
  double get_t0(string id) {
 | 
			
		||||
    return stats[id].t0;
 | 
			
		||||
  }
 | 
			
		||||
  void add_dt(string id, double dt) {
 | 
			
		||||
    Stats& s = stats[id];
 | 
			
		||||
    s.t += dt;
 | 
			
		||||
    s.n++;
 | 
			
		||||
    if (s.n==1 || s.t_max < dt) s.t_max = dt;
 | 
			
		||||
    if (s.n==1 || s.t_min > dt) s.t_min = dt;
 | 
			
		||||
  }
 | 
			
		||||
  void print() {
 | 
			
		||||
    map<string, Stats>::iterator it;
 | 
			
		||||
    for(it = stats.begin(); it!=stats.end(); it++) {
 | 
			
		||||
      Stats& s = it->second;
 | 
			
		||||
      printf("%s: %g (%i times, min: %g, max: %g)\n",
 | 
			
		||||
             it->first.c_str(), s.t, s.n, s.t_min, s.t_max);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  double time(string id) {
 | 
			
		||||
    Stats& s = stats[id];
 | 
			
		||||
    return s.t;
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
Timing timing;
 | 
			
		||||
 | 
			
		||||
double tic() {
 | 
			
		||||
  struct timeval t;
 | 
			
		||||
  gettimeofday(&t, NULL);
 | 
			
		||||
  return ((double)t.tv_sec + ((double)t.tv_usec)/1000000.);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
double tic(string id) {
 | 
			
		||||
  double t0 = tic();
 | 
			
		||||
  timing.add_t0(id, t0);
 | 
			
		||||
  return t0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
double toc(double t) {
 | 
			
		||||
  double s = tic();
 | 
			
		||||
  return (max(0., s-t));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
double toc(string id) {
 | 
			
		||||
  double dt = toc(timing.get_t0(id));
 | 
			
		||||
  timing.add_dt(id, dt);
 | 
			
		||||
  return dt;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void tictoc_print() {
 | 
			
		||||
  timing.print();
 | 
			
		||||
}
 | 
			
		||||
#else
 | 
			
		||||
void tictoc_print() {}
 | 
			
		||||
double tic(string id) {return 0.;}
 | 
			
		||||
double toc(string id) {return 0.;}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace gtsam {
 | 
			
		||||
 | 
			
		||||
	using namespace std;
 | 
			
		||||
| 
						 | 
				
			
			@ -27,12 +104,16 @@ namespace gtsam {
 | 
			
		|||
 | 
			
		||||
		// combine the factors of all nodes connected to the variable to be eliminated
 | 
			
		||||
		// if no factors are connected to key, returns an empty factor
 | 
			
		||||
		tic("eliminate_removeandcombinefactors");
 | 
			
		||||
		boost::shared_ptr<GaussianFactor> joint_factor = removeAndCombineFactors(graph,key);
 | 
			
		||||
		toc("eliminate_removeandcombinefactors");
 | 
			
		||||
 | 
			
		||||
		// eliminate that joint factor
 | 
			
		||||
		boost::shared_ptr<GaussianFactor> factor;
 | 
			
		||||
		boost::shared_ptr<GaussianConditional> conditional;
 | 
			
		||||
		tic("eliminate_eliminate");
 | 
			
		||||
		boost::tie(conditional, factor) = joint_factor->eliminate(key);
 | 
			
		||||
		toc("eliminate_eliminate");
 | 
			
		||||
 | 
			
		||||
		// ADDED: remember the intermediate result to be able to later restart computation in the middle
 | 
			
		||||
		cached[key] = factor;
 | 
			
		||||
| 
						 | 
				
			
			@ -67,7 +148,7 @@ namespace gtsam {
 | 
			
		|||
	/** Create a Bayes Tree from a nonlinear factor graph */
 | 
			
		||||
	template<class Conditional, class Config>
 | 
			
		||||
	ISAM2<Conditional, Config>::ISAM2(const NonlinearFactorGraph<Config>& nlfg, const Ordering& ordering, const Config& config)
 | 
			
		||||
	: BayesTree<Conditional>(nlfg.linearize(config)->eliminate(ordering)), theta_(config), thetaFuture_(config), nonlinearFactors_(nlfg) {
 | 
			
		||||
	: BayesTree<Conditional>(nlfg.linearize(config)->eliminate(ordering)), theta_(config), nonlinearFactors_(nlfg) {
 | 
			
		||||
		// todo: repeats calculation above, just to set "cached"
 | 
			
		||||
		// De-referencing shared pointer can be quite expensive because creates temporary
 | 
			
		||||
		_eliminate_const(*nlfg.linearize(config), cached_, ordering);
 | 
			
		||||
| 
						 | 
				
			
			@ -157,6 +238,7 @@ namespace gtsam {
 | 
			
		|||
 | 
			
		||||
		// BEGIN OF COPIED CODE
 | 
			
		||||
 | 
			
		||||
		tic("linear_lookup1");
 | 
			
		||||
		// ordering provides all keys in conditionals, there cannot be others because path to root included
 | 
			
		||||
		set<Symbol> affectedKeys;
 | 
			
		||||
		list<Symbol> tmp = affectedBayesNet.ordering();
 | 
			
		||||
| 
						 | 
				
			
			@ -165,6 +247,7 @@ namespace gtsam {
 | 
			
		|||
		FactorGraph<GaussianFactor> factors(*relinearizeAffectedFactors(affectedKeys));  // todo: no need to relinearize here, should have cached linearized factors
 | 
			
		||||
 | 
			
		||||
		cout << "linear: #affected: " << affectedKeys.size() << " #factors: " << factors.size() << endl;
 | 
			
		||||
		toc("linear_lookup1");
 | 
			
		||||
 | 
			
		||||
		// add the cached intermediate results from the boundary of the orphans ...
 | 
			
		||||
		FactorGraph<GaussianFactor> cachedBoundary = getCachedBoundaryFactors(orphans);
 | 
			
		||||
| 
						 | 
				
			
			@ -182,11 +265,12 @@ namespace gtsam {
 | 
			
		|||
		// newKeys are passed in: those variables will be forced to the end in the ordering
 | 
			
		||||
		set<Symbol> newKeysSet;
 | 
			
		||||
		newKeysSet.insert(newKeys.begin(), newKeys.end());
 | 
			
		||||
    //		Ordering ordering = factors.getConstrainedOrdering(newKeysSet);
 | 
			
		||||
		Ordering ordering = factors.getOrdering(); // todo: back to constrained...
 | 
			
		||||
		Ordering ordering = factors.getConstrainedOrdering(newKeysSet);
 | 
			
		||||
 | 
			
		||||
		// eliminate into a Bayes net
 | 
			
		||||
		tic("linear_eliminate");
 | 
			
		||||
		BayesNet<Conditional> bayesNet = _eliminate(factors, cached_, ordering);
 | 
			
		||||
		toc("linear_eliminate");
 | 
			
		||||
 | 
			
		||||
		// Create Index from ordering
 | 
			
		||||
		IndexTable<Symbol> index(ordering);
 | 
			
		||||
| 
						 | 
				
			
			@ -218,7 +302,7 @@ namespace gtsam {
 | 
			
		|||
	void ISAM2<Conditional, Config>::find_all(sharedClique clique, list<Symbol>& keys, const list<Symbol>& marked) {
 | 
			
		||||
		// does the separator contain any of the variables?
 | 
			
		||||
		bool found = false;
 | 
			
		||||
		BOOST_FOREACH(const Symbol& key, clique->keys()) { // todo  clique->separator_) {
 | 
			
		||||
		BOOST_FOREACH(const Symbol& key, clique->separator_) {
 | 
			
		||||
			if (find(marked.begin(), marked.end(), key) != marked.end())
 | 
			
		||||
				found = true;
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -258,9 +342,11 @@ namespace gtsam {
 | 
			
		|||
 | 
			
		||||
			// mark all cliques that involve marked variables
 | 
			
		||||
			list<Symbol> affectedSymbols(marked); // add all marked
 | 
			
		||||
			tic("nonlin-find_all");
 | 
			
		||||
			find_all(this->root(), affectedSymbols, marked); // add other cliques that have the marked ones in the separator
 | 
			
		||||
			affectedSymbols.sort(); // remove duplicates
 | 
			
		||||
			affectedSymbols.unique();
 | 
			
		||||
			toc("nonlin-find_all");
 | 
			
		||||
 | 
			
		||||
			// 4. From the leaves to the top, if a clique is marked:
 | 
			
		||||
			//    re-linearize the original factors in \Factors associated with the clique,
 | 
			
		||||
| 
						 | 
				
			
			@ -268,11 +354,14 @@ namespace gtsam {
 | 
			
		|||
 | 
			
		||||
			// todo: for simplicity, currently simply remove the top and recreate it using the original ordering
 | 
			
		||||
 | 
			
		||||
			tic("nonlin-mess");
 | 
			
		||||
			Cliques orphans;
 | 
			
		||||
			BayesNet<GaussianConditional> affectedBayesNet;
 | 
			
		||||
			this->removeTop(affectedSymbols, affectedBayesNet, orphans);
 | 
			
		||||
			// remember original ordering
 | 
			
		||||
			Ordering original_ordering = affectedBayesNet.ordering();
 | 
			
		||||
// todo			Ordering original_ordering = affectedBayesNet.ordering(); // does not yield original ordering...
 | 
			
		||||
			FactorGraph<GaussianFactor> tmp_factors(affectedBayesNet); // so instead we recalculate an acceptable ordering here
 | 
			
		||||
			Ordering original_ordering = tmp_factors.getOrdering(); // todo - remove multiple lines up to here
 | 
			
		||||
 | 
			
		||||
			boost::shared_ptr<GaussianFactorGraph> factors;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -280,8 +369,11 @@ namespace gtsam {
 | 
			
		|||
			set<Symbol> affectedKeys;
 | 
			
		||||
			list<Symbol> tmp = affectedBayesNet.ordering();
 | 
			
		||||
			affectedKeys.insert(tmp.begin(), tmp.end());
 | 
			
		||||
			toc("nonlin-mess");
 | 
			
		||||
 | 
			
		||||
			tic("nonlin_relin");
 | 
			
		||||
			factors = relinearizeAffectedFactors(affectedKeys);
 | 
			
		||||
			toc("nonlin_relin");
 | 
			
		||||
 | 
			
		||||
			cout << "nonlinear: #marked: " << marked.size() << " #affected: " << affectedKeys.size() << " #factors: " << factors->size() << endl;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -289,14 +381,13 @@ namespace gtsam {
 | 
			
		|||
			FactorGraph<GaussianFactor> cachedBoundary = getCachedBoundaryFactors(orphans);
 | 
			
		||||
			factors->push_back(cachedBoundary);
 | 
			
		||||
 | 
			
		||||
			// todo - temporary solution
 | 
			
		||||
			Ordering ordering = factors->getOrdering();
 | 
			
		||||
 | 
			
		||||
			// eliminate into a Bayes net
 | 
			
		||||
			BayesNet<Conditional> bayesNet = _eliminate(*factors, cached_, ordering); // todo original_ordering);
 | 
			
		||||
			tic("nonlin_eliminate");
 | 
			
		||||
			BayesNet<Conditional> bayesNet = _eliminate(*factors, cached_, original_ordering);
 | 
			
		||||
			toc("nonlin_eliminate");
 | 
			
		||||
 | 
			
		||||
			// Create Index from ordering
 | 
			
		||||
			IndexTable<Symbol> index(ordering); // todo original_ordering);
 | 
			
		||||
			IndexTable<Symbol> index(original_ordering);
 | 
			
		||||
 | 
			
		||||
			// insert conditionals back in, straight into the topless bayesTree
 | 
			
		||||
			typename BayesNet<Conditional>::const_reverse_iterator rit;
 | 
			
		||||
| 
						 | 
				
			
			@ -321,31 +412,46 @@ namespace gtsam {
 | 
			
		|||
			const NonlinearFactorGraph<Config>& newFactors, const Config& newTheta,
 | 
			
		||||
			double wildfire_threshold, double relinearize_threshold, bool relinearize) {
 | 
			
		||||
 | 
			
		||||
		tic("all");
 | 
			
		||||
 | 
			
		||||
		tic("step1");
 | 
			
		||||
		// 1. Add any new factors \Factors:=\Factors\cup\Factors'.
 | 
			
		||||
		nonlinearFactors_.push_back(newFactors);
 | 
			
		||||
		toc("step1");
 | 
			
		||||
 | 
			
		||||
		tic("step2");
 | 
			
		||||
		// 2. Initialize any new variables \Theta_{new} and add \Theta:=\Theta\cup\Theta_{new}.
 | 
			
		||||
		theta_.insert(newTheta);
 | 
			
		||||
		toc("step2");
 | 
			
		||||
 | 
			
		||||
		tic("step3");
 | 
			
		||||
		// 3. Linearize new factor
 | 
			
		||||
		boost::shared_ptr<GaussianFactorGraph> linearFactors = newFactors.linearize(theta_);
 | 
			
		||||
		toc("step3");
 | 
			
		||||
 | 
			
		||||
		tic("step4");
 | 
			
		||||
		// 4. Linear iSAM step (alg 3)
 | 
			
		||||
		linear_update(*linearFactors); // in: this
 | 
			
		||||
		toc("step4");
 | 
			
		||||
 | 
			
		||||
		tic("step5");
 | 
			
		||||
		// 5. Calculate Delta (alg 0)
 | 
			
		||||
		delta_ = optimize2(*this, wildfire_threshold);
 | 
			
		||||
		toc("step5");
 | 
			
		||||
 | 
			
		||||
		tic("step6");
 | 
			
		||||
		// 6. Iterate Algorithm 4 until no more re-linearizations occur
 | 
			
		||||
		if (relinearize)
 | 
			
		||||
		if (relinearize) {
 | 
			
		||||
			fluid_relinearization(relinearize_threshold); // in: delta_, theta_, nonlinearFactors_, this
 | 
			
		||||
		}
 | 
			
		||||
		toc("step6");
 | 
			
		||||
 | 
			
		||||
		// todo: not part of algorithm in paper: linearization point and delta_ do not fit... have to update delta again
 | 
			
		||||
		delta_ = optimize2(*this, wildfire_threshold);
 | 
			
		||||
//todo		delta_ = optimize2(*this, wildfire_threshold);
 | 
			
		||||
 | 
			
		||||
		// todo: for getLinearizationPoint(), see ISAM2.h
 | 
			
		||||
		thetaFuture_ = theta_;
 | 
			
		||||
		toc("all");
 | 
			
		||||
 | 
			
		||||
		tictoc_print();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
/* ************************************************************************* */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -34,7 +34,6 @@ namespace gtsam {
 | 
			
		|||
 | 
			
		||||
		// current linearization point
 | 
			
		||||
		Config theta_;
 | 
			
		||||
		Config thetaFuture_; // lin point of next iteration
 | 
			
		||||
 | 
			
		||||
		// for keeping all original nonlinear factors
 | 
			
		||||
		NonlinearFactorGraph<Config> nonlinearFactors_;
 | 
			
		||||
| 
						 | 
				
			
			@ -75,7 +74,7 @@ namespace gtsam {
 | 
			
		|||
				double wildfire_threshold = 0., double relinearize_threshold = 0., bool relinearize = true);
 | 
			
		||||
 | 
			
		||||
		// needed to create initial estimates (note that this will be the linearization point in the next step!)
 | 
			
		||||
		const Config getLinearizationPoint() const {return thetaFuture_;}
 | 
			
		||||
		const Config getLinearizationPoint() const {return theta_;}
 | 
			
		||||
		// estimate based on incomplete delta (threshold!)
 | 
			
		||||
		const Config calculateEstimate() const {return theta_.expmap(delta_);}
 | 
			
		||||
		// estimate based on full delta (note that this is based on the actual current linearization point)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue