/* * @file testNonlinearConstraint.cpp * @brief demos of constrained optimization using existing gtsam components * @author Alex Cunningham */ #include #include #include // for operator += #include // for insert #include #include #include #define GTSAM_MAGIC_KEY #include #include #include #include #include #include #include // templated implementations #include #include #include using namespace std; using namespace gtsam; using namespace boost; using namespace boost::assign; //// Models to use //SharedDiagonal probModel1 = sharedSigma(1,1.0); //SharedDiagonal probModel2 = sharedSigma(2,1.0); //SharedDiagonal constraintModel1 = noiseModel::Constrained::All(1); // //// trick from some reading group //#define FOREACH_PAIR( KEY, VAL, COL) BOOST_FOREACH (boost::tie(KEY,VAL),COL) // ///* ********************************************************************* */ //// full components //typedef simulated2D::Config Config2D; //typedef NonlinearFactorGraph Graph2D; //typedef NonlinearEquality NLE; //typedef boost::shared_ptr > shared; //typedef NonlinearOptimizer Optimizer; ///* ********************************************************************* */ //// This is an obstacle avoidance demo, where there is a trajectory of //// three points, where there is a circular obstacle in the middle. There //// is a binary inequality constraint connecting the obstacle to the //// states, which enforces a minimum distance. ///* ********************************************************************* */ // ////typedef NonlinearConstraint2 AvoidConstraint; ////typedef shared_ptr shared_a; ////typedef NonlinearEquality PoseNLConstraint; ////typedef shared_ptr shared_pc; ////typedef NonlinearEquality ObstacleConstraint; ////typedef shared_ptr shared_oc; //// //// ////namespace constrained_avoid1 { ////// avoidance radius ////double radius = 1.0; //// ////// binary avoidance constraint /////** g(x) = ||x2-obs||^2 - radius^2 > 0 */ ////Vector g_func(const Config2D& config, const PoseKey& x, const PointKey& obs) { //// double dist2 = config[x].dist(config[obs]); //// double thresh = radius*radius; //// return Vector_(1, dist2-thresh); ////} //// /////** jacobian at pose */ ////Matrix jac_g1(const Config2D& config, const PoseKey& x, const PointKey& obs) { //// Point2 p = config[x]-config[obs]; //// return Matrix_(1,2, 2.0*p.x(), 2.0*p.y()); ////} //// /////** jacobian at obstacle */ ////Matrix jac_g2(const Config2D& config, const PoseKey& x, const PointKey& obs) { //// Point2 p = config[x]-config[obs]; //// return Matrix_(1,2, -2.0*p.x(), -2.0*p.y()); ////} ////} //// ////pair obstacleAvoidGraph() { //// // Keys //// PoseKey x1(1), x2(2), x3(3); //// PointKey l1(1); //// LagrangeKey L20(20); //// //// // Constrained Points //// Point2 pt_x1, //// pt_x3(10.0, 0.0), //// pt_l1(5.0, -0.5); //// //// shared_pc e1(new PoseNLConstraint(x1, pt_x1)); //// shared_pc e2(new PoseNLConstraint(x3, pt_x3)); //// shared_oc e3(new ObstacleConstraint(l1, pt_l1)); //// //// // measurement from x1 to x2 //// Point2 x1x2(5.0, 0.0); //// shared f1(new simulated2D::Odometry(x1x2, sigma, 1,2)); //// //// // measurement from x2 to x3 //// Point2 x2x3(5.0, 0.0); //// shared f2(new simulated2D::Odometry(x2x3, sigma, 2,3)); //// //// // create a binary inequality constraint that forces the middle point away from //// // the obstacle //// shared_a c1(new AvoidConstraint(boost::bind(constrained_avoid1::g_func, _1, x2, l1), //// x2, boost::bind(constrained_avoid1::jac_g1, _1, x2, l1), //// l1,boost::bind(constrained_avoid1::jac_g2, _1, x2, l1), //// 1, L20, false)); //// //// // construct the graph //// NLGraph graph; //// graph.push_back(e1); //// graph.push_back(e2); //// graph.push_back(e3); //// graph.push_back(c1); //// graph.push_back(f1); //// graph.push_back(f2); //// //// // make a config of the fixed values, for convenience //// Config2D config; //// config.insert(x1, pt_x1); //// config.insert(x3, pt_x3); //// config.insert(l1, pt_l1); //// //// return make_pair(graph, config); ////} //// /////* ********************************************************************* */ ////TEST ( SQPOptimizer, inequality_avoid ) { //// // create the graph //// NLGraph graph; Config2D feasible; //// boost::tie(graph, feasible) = obstacleAvoidGraph(); //// //// // create the rest of the config //// shared_ptr init(new Config2D(feasible)); //// PoseKey x2(2); //// init->insert(x2, Point2(5.0, 100.0)); //// //// // create an ordering //// Ordering ord; //// ord += "x1", "x2", "x3", "l1"; //// //// // create an optimizer //// Optimizer optimizer(graph, ord, init); //// //// // perform an iteration of optimization //// // NOTE: the constraint will be inactive in the first iteration, //// // so it will violate the constraint after one iteration //// Optimizer afterOneIteration = optimizer.iterate(Optimizer::SILENT); //// //// Config2D exp1(feasible); //// exp1.insert(x2, Point2(5.0, 0.0)); //// CHECK(assert_equal(exp1, *(afterOneIteration.config()))); //// //// // the second iteration will activate the constraint and force the //// // config to a viable configuration. //// Optimizer after2ndIteration = afterOneIteration.iterate(Optimizer::SILENT); //// //// Config2D exp2(feasible); //// exp2.insert(x2, Point2(5.0, 0.5)); //// CHECK(assert_equal(exp2, *(after2ndIteration.config()))); ////} // /////* ********************************************************************* */ ////TEST ( SQPOptimizer, inequality_avoid_iterative ) { //// // create the graph //// NLGraph graph; Config2D feasible; //// boost::tie(graph, feasible) = obstacleAvoidGraph(); //// //// // create the rest of the config //// shared_ptr init(new Config2D(feasible)); //// PoseKey x2(2); //// init->insert(x2, Point2(5.0, 100.0)); //// //// // create an ordering //// Ordering ord; //// ord += "x1", "x2", "x3", "l1"; //// //// // create an optimizer //// Optimizer optimizer(graph, ord, init); //// //// double relThresh = 1e-5; // minimum change in error between iterations //// double absThresh = 1e-5; // minimum error necessary to converge //// double constraintThresh = 1e-9; // minimum constraint error to be feasible //// Optimizer final = optimizer.iterateSolve(relThresh, absThresh, constraintThresh); //// //// // verify //// Config2D exp2(feasible); //// exp2.insert(x2, Point2(5.0, 0.5)); //// CHECK(assert_equal(exp2, *(final.config()))); ////} /* ************************************************************************* */ int main() { TestResult tr; return TestRegistry::runAllTests(tr); } /* ************************************************************************* */