263 lines
8.3 KiB
C++
263 lines
8.3 KiB
C++
/* ----------------------------------------------------------------------------
|
|
|
|
* GTSAM Copyright 2010, Georgia Tech Research Corporation,
|
|
* Atlanta, Georgia 30332-0415
|
|
* All Rights Reserved
|
|
* Authors: Frank Dellaert, et al. (see THANKS for the full author list)
|
|
|
|
* See LICENSE for the license information
|
|
* -------------------------------------------------------------------------- */
|
|
|
|
/**
|
|
* @file timeIncremental.cpp
|
|
* @brief Overall timing tests for incremental solving
|
|
* @author Richard Roberts
|
|
*/
|
|
|
|
#include <gtsam/base/timing.h>
|
|
#include <gtsam/slam/dataset.h>
|
|
#include <gtsam/geometry/Pose2.h>
|
|
#include <gtsam/slam/PriorFactor.h>
|
|
#include <gtsam/slam/BetweenFactor.h>
|
|
#include <gtsam/slam/BearingRangeFactor.h>
|
|
#include <gtsam/inference/Symbol.h>
|
|
#include <gtsam/nonlinear/ISAM2.h>
|
|
#include <gtsam/nonlinear/Marginals.h>
|
|
|
|
#include <fstream>
|
|
#include <boost/archive/binary_oarchive.hpp>
|
|
#include <boost/archive/binary_iarchive.hpp>
|
|
#include <boost/serialization/export.hpp>
|
|
|
|
using namespace std;
|
|
using namespace gtsam;
|
|
using namespace gtsam::symbol_shorthand;
|
|
|
|
typedef Pose2 Pose;
|
|
|
|
typedef NoiseModelFactor1<Pose> NM1;
|
|
typedef NoiseModelFactor2<Pose,Pose> NM2;
|
|
typedef BearingRangeFactor<Pose,Point2> BR;
|
|
|
|
BOOST_CLASS_EXPORT(Value);
|
|
BOOST_CLASS_EXPORT(Pose);
|
|
BOOST_CLASS_EXPORT(NonlinearFactor);
|
|
BOOST_CLASS_EXPORT(NoiseModelFactor);
|
|
BOOST_CLASS_EXPORT(NM1);
|
|
BOOST_CLASS_EXPORT(NM2);
|
|
BOOST_CLASS_EXPORT(BetweenFactor<Pose>);
|
|
BOOST_CLASS_EXPORT(PriorFactor<Pose>);
|
|
BOOST_CLASS_EXPORT(BR);
|
|
BOOST_CLASS_EXPORT(noiseModel::Base);
|
|
BOOST_CLASS_EXPORT(noiseModel::Isotropic);
|
|
BOOST_CLASS_EXPORT(noiseModel::Gaussian);
|
|
BOOST_CLASS_EXPORT(noiseModel::Diagonal);
|
|
BOOST_CLASS_EXPORT(noiseModel::Unit);
|
|
|
|
double chi2_red(const gtsam::NonlinearFactorGraph& graph, const gtsam::Values& config) {
|
|
// Compute degrees of freedom (observations - variables)
|
|
// In ocaml, +1 was added to the observations to account for the prior, but
|
|
// the factor graph already includes a factor for the prior/equality constraint.
|
|
// double dof = graph.size() - config.size();
|
|
int graph_dim = 0;
|
|
BOOST_FOREACH(const boost::shared_ptr<gtsam::NonlinearFactor>& nlf, graph) {
|
|
graph_dim += nlf->dim();
|
|
}
|
|
double dof = graph_dim - config.dim(); // kaess: changed to dim
|
|
return 2. * graph.error(config) / dof; // kaess: added factor 2, graph.error returns half of actual error
|
|
}
|
|
|
|
int main(int argc, char *argv[]) {
|
|
|
|
cout << "Loading data..." << endl;
|
|
|
|
gttic_(Find_datafile);
|
|
//string datasetFile = findExampleDataFile("w10000-odom");
|
|
string datasetFile = findExampleDataFile("victoria_park");
|
|
std::pair<NonlinearFactorGraph::shared_ptr, Values::shared_ptr> data =
|
|
load2D(datasetFile);
|
|
gttoc_(Find_datafile);
|
|
|
|
NonlinearFactorGraph measurements = *data.first;
|
|
Values initial = *data.second;
|
|
|
|
cout << "Playing forward time steps..." << endl;
|
|
|
|
ISAM2 isam2;
|
|
|
|
size_t nextMeasurement = 0;
|
|
for(size_t step=1; nextMeasurement < measurements.size(); ++step) {
|
|
|
|
Values newVariables;
|
|
NonlinearFactorGraph newFactors;
|
|
|
|
// Collect measurements and new variables for the current step
|
|
gttic_(Collect_measurements);
|
|
if(step == 1) {
|
|
// cout << "Initializing " << 0 << endl;
|
|
newVariables.insert(0, Pose());
|
|
// Add prior
|
|
newFactors.add(PriorFactor<Pose>(0, Pose(), noiseModel::Unit::Create(Pose::Dim())));
|
|
}
|
|
while(nextMeasurement < measurements.size()) {
|
|
|
|
NonlinearFactor::shared_ptr measurementf = measurements[nextMeasurement];
|
|
|
|
if(BetweenFactor<Pose>::shared_ptr measurement =
|
|
boost::dynamic_pointer_cast<BetweenFactor<Pose> >(measurementf))
|
|
{
|
|
// Stop collecting measurements that are for future steps
|
|
if(measurement->key1() > step || measurement->key2() > step)
|
|
break;
|
|
|
|
// Require that one of the nodes is the current one
|
|
if(measurement->key1() != step && measurement->key2() != step)
|
|
throw runtime_error("Problem in data file, out-of-sequence measurements");
|
|
|
|
// Add a new factor
|
|
newFactors.push_back(measurement);
|
|
|
|
// Initialize the new variable
|
|
if(measurement->key1() == step && measurement->key2() == step-1) {
|
|
if(step == 1)
|
|
newVariables.insert(step, measurement->measured().inverse());
|
|
else {
|
|
Pose prevPose = isam2.calculateEstimate<Pose>(step-1);
|
|
newVariables.insert(step, prevPose * measurement->measured().inverse());
|
|
}
|
|
// cout << "Initializing " << step << endl;
|
|
} else if(measurement->key2() == step && measurement->key1() == step-1) {
|
|
if(step == 1)
|
|
newVariables.insert(step, measurement->measured());
|
|
else {
|
|
Pose prevPose = isam2.calculateEstimate<Pose>(step-1);
|
|
newVariables.insert(step, prevPose * measurement->measured());
|
|
}
|
|
// cout << "Initializing " << step << endl;
|
|
}
|
|
}
|
|
else if(BearingRangeFactor<Pose, Point2>::shared_ptr measurement =
|
|
boost::dynamic_pointer_cast<BearingRangeFactor<Pose, Point2> >(measurementf))
|
|
{
|
|
Key poseKey = measurement->keys()[0], lmKey = measurement->keys()[1];
|
|
|
|
// Stop collecting measurements that are for future steps
|
|
if(poseKey > step)
|
|
throw runtime_error("Problem in data file, out-of-sequence measurements");
|
|
|
|
// Add new factor
|
|
newFactors.push_back(measurement);
|
|
|
|
// Initialize new landmark
|
|
if(!isam2.getLinearizationPoint().exists(lmKey))
|
|
{
|
|
Pose pose = isam2.calculateEstimate<Pose>(poseKey);
|
|
Rot2 measuredBearing = measurement->measured().first;
|
|
double measuredRange = measurement->measured().second;
|
|
newVariables.insert(lmKey,
|
|
pose.transform_from(measuredBearing.rotate(Point2(measuredRange, 0.0))));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw std::runtime_error("Unknown factor type read from data file");
|
|
}
|
|
++ nextMeasurement;
|
|
}
|
|
gttoc_(Collect_measurements);
|
|
|
|
// Update iSAM2
|
|
gttic_(Update_ISAM2);
|
|
isam2.update(newFactors, newVariables);
|
|
gttoc_(Update_ISAM2);
|
|
|
|
if(step % 100 == 0) {
|
|
gttic_(chi2);
|
|
Values estimate(isam2.calculateEstimate());
|
|
double chi2 = chi2_red(isam2.getFactorsUnsafe(), estimate);
|
|
cout << "chi2 = " << chi2 << endl;
|
|
gttoc_(chi2);
|
|
}
|
|
|
|
tictoc_finishedIteration_();
|
|
|
|
if(step % 1000 == 0) {
|
|
cout << "Step " << step << endl;
|
|
tictoc_print_();
|
|
}
|
|
}
|
|
|
|
//try {
|
|
// {
|
|
// std::ofstream writerStream("incremental_init", ios::binary);
|
|
// boost::archive::binary_oarchive writer(writerStream);
|
|
// writer << isam2.calculateEstimate();
|
|
// writerStream.close();
|
|
// }
|
|
// {
|
|
// std::ofstream writerStream("incremental_graph", ios::binary);
|
|
// boost::archive::binary_oarchive writer(writerStream);
|
|
// writer << isam2.getFactorsUnsafe();
|
|
// writerStream.close();
|
|
// }
|
|
//} catch(std::exception& e) {
|
|
// cout << e.what() << endl;
|
|
//}
|
|
|
|
NonlinearFactorGraph graph;
|
|
Values values;
|
|
|
|
//{
|
|
// std::ifstream readerStream("incremental_init", ios::binary);
|
|
// boost::archive::binary_iarchive reader(readerStream);
|
|
// reader >> values;
|
|
//}
|
|
//{
|
|
// std::ifstream readerStream("incremental_graph", ios::binary);
|
|
// boost::archive::binary_iarchive reader(readerStream);
|
|
// reader >> graph;
|
|
//}
|
|
|
|
graph = isam2.getFactorsUnsafe();
|
|
values = isam2.calculateEstimate();
|
|
|
|
// Compute marginals
|
|
try {
|
|
Marginals marginals(graph, values);
|
|
int i=0;
|
|
BOOST_REVERSE_FOREACH(Key key1, values.keys()) {
|
|
int j=0;
|
|
BOOST_REVERSE_FOREACH(Key key2, values.keys()) {
|
|
if(i != j) {
|
|
gttic_(jointMarginalInformation);
|
|
std::vector<Key> keys(2);
|
|
keys[0] = key1;
|
|
keys[1] = key2;
|
|
JointMarginal info = marginals.jointMarginalInformation(keys);
|
|
gttoc_(jointMarginalInformation);
|
|
tictoc_finishedIteration_();
|
|
}
|
|
++j;
|
|
if(j >= 50)
|
|
break;
|
|
}
|
|
++i;
|
|
if(i >= 50)
|
|
break;
|
|
}
|
|
tictoc_print_();
|
|
BOOST_FOREACH(Key key, values.keys()) {
|
|
gttic_(marginalInformation);
|
|
Matrix info = marginals.marginalInformation(key);
|
|
gttoc_(marginalInformation);
|
|
tictoc_finishedIteration_();
|
|
++i;
|
|
}
|
|
} catch(std::exception& e) {
|
|
cout << e.what() << endl;
|
|
}
|
|
tictoc_print_();
|
|
|
|
return 0;
|
|
}
|