/** * @file testConstraintOptimizer.cpp * @brief Tests the optimization engine for SQP and BFGS Quadratic programming techniques * @author Alex Cunningham */ #include #include #include #include #include #include #include using namespace std; using namespace gtsam; using namespace example; /* ************************************************************************* */ // Example of a single Constrained QP problem from the matlab testCQP.m file. TEST( matrix, CQP_example ) { Matrix A = Matrix_(3, 2, -1.0, -1.0, -2.0, 1.0, 1.0, -1.0); Matrix At = trans(A), B = 2.0 * eye(3,3); Vector b = Vector_(2, 4.0, -2.0), g = zero(3); Matrix G = zeros(5,5); insertSub(G, B, 0, 0); insertSub(G, A, 0, 3); insertSub(G, At, 3, 0); Vector rhs = zero(5); subInsert(rhs, -1.0*g, 0); subInsert(rhs, -1.0*b, 3); // solve the system with the LDL solver Vector actualFull = solve_ldl(G, rhs); Vector actual = sub(actualFull, 0, 3); Vector expected = Vector_(3, 2.0/7.0, 10.0/7.0, -6.0/7.0); CHECK(assert_equal(expected, actual)); } /* ************************************************************************* */ TEST( matrix, CQP_example_automatic ) { Matrix A = Matrix_(3, 2, -1.0, -1.0, -2.0, 1.0, 1.0, -1.0); Matrix At = trans(A), B = 2.0 * eye(3,3); Vector g = zero(3), h = Vector_(2, 4.0, -2.0); Vector actState, actLam; boost::tie(actState, actLam) = solveCQP(B, A, g, h); Vector expected = Vector_(3, 2.0/7.0, 10.0/7.0, -6.0/7.0); CHECK(assert_equal(expected, actState)); CHECK(actLam.size() == 2); } /* ************************************************************************* */ /** SQP example from SQP tutorial */ namespace sqp_example1 { /** * objective function with gradient and hessian * fx = (x2-2)^2 + x1^2; */ Vector objective(const Vector& x, boost::optional g = boost::none, boost::optional B = boost::none) { double x1 = x(0), x2 = x(1); if (g) *g = Vector_(2, 2.0*x1, 2.0*(x2-2.0)); if (B) *B = 2.0 * eye(2,2); return Vector_(1, (x2-2)*(x2-2) + x1*x1); } /** * constraint function with gradient and hessian * cx = 4*x1^2 + x2^2 - 1; */ Vector constraint(const Vector& x, boost::optional A = boost::none, boost::optional B = boost::none) { double x1 = x(0), x2 = x(1); if (A) *A = Matrix_(2,1, 8.0*x1, 2.0*x2); if (B) *B = Matrix_(2,2, 8.0, 0.0, 0.0, 2.0); return Vector_(1, 4.0*x1*x1 + x2*x2 - 1.0); } } /* ************************************************************************* */ TEST( matrix, SQP_simple_analytic ) { using namespace sqp_example1; // parameters double stepsize = 0.25; size_t maxIt = 50; // initial conditions Vector x0 = Vector_(2, 2.0, 4.0), lam0 = Vector_(1, -0.5); // current state Vector x = x0, lam = lam0; for (size_t i =0; i0) { Vector Bis = Bi * step, y = dfx - prev_dfx; Bi = Bi + outer_prod(y, y) / inner_prod(y, step) - outer_prod(Bis, Bis) / inner_prod(step, Bis); } prev_dfx = dfx; // solve subproblem Vector delta, lambda; boost::tie(delta, lambda) = solveCQP(Bi, -dcx, dfx, -cx); // update step = stepsize * delta; x = x + step; lam = lambda; } // verify Vector expX = Vector_(2, 0.0, 1.0), expLambda = Vector_(1, -1.0); CHECK(assert_equal(expX, x, 1e-4)); CHECK(assert_equal(expLambda, lam, 1e-4)); } /* ************************************************************************* */ TEST( matrix, SQP_simple_bfgs ) { using namespace sqp_example1; // parameters double stepsize = 0.25; size_t maxIt = 50; // initial conditions Vector x0 = Vector_(2, 2.0, 4.0), lam0 = Vector_(1, -0.5); // create a BFGSEstimator BFGSEstimator hessian(2); // current state Vector x = x0, lam = lam0; Vector step; for (size_t i=0; i0) { hessian.update(dfx, step); } else { hessian.update(dfx); } // solve subproblem Vector delta, lambda; boost::tie(delta, lambda) = solveCQP(hessian.getB(), -dcx, dfx, -cx); // update step = stepsize * delta; x = x + step; lam = lambda; } // verify Vector expX = Vector_(2, 0.0, 1.0), expLambda = Vector_(1, -1.0); CHECK(assert_equal(expX, x, 1e-4)); CHECK(assert_equal(expLambda, lam, 1e-4)); } /* ************************************************************************* */ TEST( matrix, unconstrained_fg ) { // create a graph GaussianFactorGraph fg = createGaussianFactorGraph(); // parameters size_t maxIt = 5; double stepsize = 0.1; // iterate to solve VectorConfig x = createZeroDelta(); BFGSEstimator B(x.dim()); Vector step; for (size_t i=0; i0) { B.update(dfx, step); } else { B.update(dfx); } // solve subproblem Vector delta = solve_ldl(B.getB(), -dfx); // update step = stepsize * delta; x = x.vectorUpdate(step); } // verify VectorConfig expected = createCorrectDelta(); CHECK(assert_equal(expected,x)); } /* ************************************************************************* */ int main() { TestResult tr; return TestRegistry::runAllTests(tr); } /* ************************************************************************* */