SQP demo that moves maps into the correct reference frames is now working using the NonlinearConstraint machinery.
parent
e440767db9
commit
5f848f272b
163
cpp/testSQP.cpp
163
cpp/testSQP.cpp
|
@ -11,6 +11,7 @@
|
|||
#include <boost/foreach.hpp>
|
||||
#include <CppUnitLite/TestHarness.h>
|
||||
#include <GaussianFactorGraph.h>
|
||||
#include <NonlinearFactor.h>
|
||||
#include <NonlinearEquality.h>
|
||||
#include <NonlinearFactorGraph.h>
|
||||
#include <NonlinearOptimizer.h>
|
||||
|
@ -251,7 +252,9 @@ bool vector_compare(const std::string& key,
|
|||
}
|
||||
typedef NonlinearFactorGraph<VectorConfig> NLGraph;
|
||||
typedef boost::shared_ptr<NonlinearFactor<VectorConfig> > shared;
|
||||
typedef boost::shared_ptr<NonlinearConstraint<VectorConfig> > shared_c;
|
||||
typedef boost::shared_ptr<NonlinearEquality<VectorConfig> > shared_eq;
|
||||
typedef boost::shared_ptr<VectorConfig> shared_cfg;
|
||||
typedef NonlinearOptimizer<NLGraph,VectorConfig> Optimizer;
|
||||
/**
|
||||
* Determining a ground truth nonlinear system
|
||||
|
@ -328,69 +331,103 @@ Matrix grad_g2(const VectorConfig& config, const std::string& key) {
|
|||
}
|
||||
} // \namespace sqp_test1
|
||||
|
||||
//typedef SQPOptimizer<NLGraph,VectorConfig> Optimizer;
|
||||
//
|
||||
///**
|
||||
// * Version that actually uses nonlinear equality constraints
|
||||
// * to to perform optimization. Same as above, but no
|
||||
// * equality constraint on x2, and two landmarks that
|
||||
// * should be the same.
|
||||
// */
|
||||
//TEST (SQP, two_pose ) {
|
||||
// // position (1, 1) constraint for x1
|
||||
// VectorConfig feas;
|
||||
// feas.insert("x1", Vector_(2, 1.0, 1.0));
|
||||
//
|
||||
// // constant constraint on x1
|
||||
// shared_eq ef1(new NonlinearEquality<VectorConfig>("x1", feas, 2, *vector_compare));
|
||||
//
|
||||
// // measurement from x1 to l1
|
||||
// Vector z1 = Vector_(2, 0.0, 5.0);
|
||||
// double sigma1 = 0.1;
|
||||
// shared f1(new Simulated2DMeasurement(z1, sigma1, "x1", "l1"));
|
||||
//
|
||||
// // measurement from x2 to l2
|
||||
// Vector z2 = Vector_(2, -4.0, 0.0);
|
||||
// double sigma2 = 0.1;
|
||||
// shared f2(new Simulated2DMeasurement(z2, sigma2, "x2", "l2"));
|
||||
//
|
||||
// // equality constraint between l1 and l2
|
||||
// boost::shared_ptr<NonlinearConstraint2<VectorConfig> > c1(
|
||||
// new NonlinearConstraint2<VectorConfig>(
|
||||
// "l1", *sqp_test1::grad_g1,
|
||||
// "l2", *sqp_test1::grad_g2,
|
||||
// *sqp_test1::g_func, 2, "L_l1l2"));
|
||||
//
|
||||
// // construct the graph
|
||||
// NLGraph graph;
|
||||
// graph.push_back(ef1);
|
||||
// graph.push_back(c1);
|
||||
// graph.push_back(f1);
|
||||
// graph.push_back(f2);
|
||||
//
|
||||
// // create an initial estimate
|
||||
// boost::shared_ptr<VectorConfig> initialEstimate(new VectorConfig(feas)); // must start with feasible set
|
||||
// initialEstimate->insert("l1", Vector_(2, 1.0, 6.0)); // ground truth
|
||||
// initialEstimate->insert("l2", Vector_(2, -4.0, 0.0)); // starting with a separate reference frame
|
||||
// initialEstimate->insert("x2", Vector_(2, 0.0, 0.0)); // other pose starts at origin
|
||||
//
|
||||
// // optimize the graph
|
||||
//// Ordering ordering;
|
||||
//// ordering += "x1", "x2", "l1";
|
||||
//// NewOptimizer optimizer(graph, ordering, initialEstimate, 1e-5);
|
||||
////
|
||||
//// // display solution
|
||||
//// double relativeThreshold = 1e-5;
|
||||
//// double absoluteThreshold = 1e-5;
|
||||
//// Optimizer act_opt = optimizer.gaussNewton(relativeThreshold, absoluteThreshold);
|
||||
//// boost::shared_ptr<const VectorConfig> actual = act_opt.config();
|
||||
//// //actual->print("Configuration after optimization");
|
||||
////
|
||||
//// // verify
|
||||
//// VectorConfig expected(feas);
|
||||
//// expected.insert("l1", Vector_(2, 1.0, 6.0));
|
||||
//// CHECK(assert_equal(expected, *actual, 1e-5));
|
||||
//}
|
||||
/**
|
||||
* Version that actually uses nonlinear equality constraints
|
||||
* to to perform optimization. Same as above, but no
|
||||
* equality constraint on x2, and two landmarks that
|
||||
* should be the same.
|
||||
*/
|
||||
TEST (SQP, two_pose ) {
|
||||
// position (1, 1) constraint for x1
|
||||
VectorConfig feas;
|
||||
feas.insert("x1", Vector_(2, 1.0, 1.0));
|
||||
|
||||
// constant constraint on x1
|
||||
shared_eq ef1(new NonlinearEquality<VectorConfig>("x1", feas, 2, *vector_compare));
|
||||
|
||||
// measurement from x1 to l1
|
||||
Vector z1 = Vector_(2, 0.0, 5.0);
|
||||
double sigma1 = 0.1;
|
||||
shared f1(new Simulated2DMeasurement(z1, sigma1, "x1", "l1"));
|
||||
|
||||
// measurement from x2 to l2
|
||||
Vector z2 = Vector_(2, -4.0, 0.0);
|
||||
double sigma2 = 0.1;
|
||||
shared f2(new Simulated2DMeasurement(z2, sigma2, "x2", "l2"));
|
||||
|
||||
// equality constraint between l1 and l2
|
||||
boost::shared_ptr<NonlinearConstraint2<VectorConfig> > c1(
|
||||
new NonlinearConstraint2<VectorConfig>(
|
||||
"l1", *sqp_test1::grad_g1,
|
||||
"l2", *sqp_test1::grad_g2,
|
||||
*sqp_test1::g_func, 2, "L_l1l2"));
|
||||
|
||||
// construct the graph
|
||||
NLGraph graph;
|
||||
graph.push_back(ef1);
|
||||
graph.push_back(c1);
|
||||
graph.push_back(f1);
|
||||
graph.push_back(f2);
|
||||
|
||||
// create an initial estimate
|
||||
shared_cfg initialEstimate(new VectorConfig(feas)); // must start with feasible set
|
||||
initialEstimate->insert("l1", Vector_(2, 1.0, 6.0)); // ground truth
|
||||
initialEstimate->insert("l2", Vector_(2, -4.0, 0.0)); // starting with a separate reference frame
|
||||
initialEstimate->insert("x2", Vector_(2, 0.0, 0.0)); // other pose starts at origin
|
||||
|
||||
// create an initial estimate for the lagrange multiplier
|
||||
shared_cfg initLagrange(new VectorConfig);
|
||||
initLagrange->insert("L_l1l2", Vector_(2, 1.0, 1.0));
|
||||
|
||||
// create state config variables and initialize them
|
||||
VectorConfig state(*initialEstimate), state_lam(*initLagrange);
|
||||
|
||||
// optimization loop
|
||||
int maxIt = 1;
|
||||
for (int i = 0; i<maxIt; ++i) {
|
||||
// linearize the graph
|
||||
GaussianFactorGraph fg;
|
||||
typedef FactorGraph<NonlinearFactor<VectorConfig> >::const_iterator const_iterator;
|
||||
typedef NonlinearConstraint<VectorConfig> NLConstraint;
|
||||
// iterate over all factors
|
||||
for (const_iterator factor = graph.begin(); factor < graph.end(); factor++) {
|
||||
const shared_c constraint = boost::shared_dynamic_cast<NLConstraint >(*factor);
|
||||
if (constraint == NULL) {
|
||||
// if a regular factor, linearize using the default linearization
|
||||
GaussianFactor::shared_ptr f = (*factor)->linearize(state);
|
||||
fg.push_back(f);
|
||||
} else {
|
||||
// if a constraint, linearize using the constraint method (2 configs)
|
||||
GaussianFactor::shared_ptr f, c;
|
||||
boost::tie(f,c) = constraint->linearize(state, state_lam);
|
||||
fg.push_back(f);
|
||||
fg.push_back(c);
|
||||
}
|
||||
}
|
||||
fg.print("Linearized graph");
|
||||
|
||||
// create an ordering
|
||||
Ordering ordering;
|
||||
ordering += "x1", "x2", "l1", "l2", "L_l1l2";
|
||||
|
||||
// optimize linear graph to get full delta config
|
||||
VectorConfig delta = fg.optimize(ordering).scale(-1.0);
|
||||
delta.print("Delta Config");
|
||||
|
||||
// update both state variables
|
||||
state = state.exmap(delta);
|
||||
state.print("newState");
|
||||
state_lam = state_lam.exmap(delta);
|
||||
state_lam.print("newStateLam");
|
||||
}
|
||||
|
||||
// verify
|
||||
VectorConfig expected(feas);
|
||||
expected.insert("l1", Vector_(2, 1.0, 6.0));
|
||||
expected.insert("l2", Vector_(2, 1.0, 6.0));
|
||||
expected.insert("x2", Vector_(2, 5.0, 6.0));
|
||||
CHECK(assert_equal(expected, state, 1e-5));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
int main() { TestResult tr; return TestRegistry::runAllTests(tr); }
|
||||
|
|
Loading…
Reference in New Issue