| 
									
										
										
										
											2014-04-15 10:57:55 +08:00
										 |  |  | /* ----------------------------------------------------------------------------
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  * 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 testQPSolver.cpp | 
					
						
							|  |  |  |  * @brief Test simple QP solver for a linear inequality constraint | 
					
						
							|  |  |  |  * @date Apr 10, 2014 | 
					
						
							|  |  |  |  * @author Duy-Nguyen Ta | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-02 02:44:14 +08:00
										 |  |  | #include <gtsam/base/Testable.h>
 | 
					
						
							|  |  |  | #include <gtsam/inference/Symbol.h>
 | 
					
						
							| 
									
										
										
										
											2014-11-22 05:04:12 +08:00
										 |  |  | #include <gtsam_unstable/linear/QPSolver.h>
 | 
					
						
							| 
									
										
										
										
											2014-04-15 10:57:55 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-26 16:04:34 +08:00
										 |  |  | #include <CppUnitLite/TestHarness.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-15 10:57:55 +08:00
										 |  |  | using namespace std; | 
					
						
							|  |  |  | using namespace gtsam; | 
					
						
							|  |  |  | using namespace gtsam::symbol_shorthand; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-13 01:03:00 +08:00
										 |  |  | const Matrix One = ones(1,1); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-15 10:57:55 +08:00
										 |  |  | /* ************************************************************************* */ | 
					
						
							|  |  |  | // Create test graph according to Forst10book_pg171Ex5
 | 
					
						
							| 
									
										
										
										
											2014-12-09 19:13:57 +08:00
										 |  |  | QP createTestCase() { | 
					
						
							|  |  |  |   QP qp; | 
					
						
							| 
									
										
										
										
											2014-04-15 10:57:55 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-27 05:40:48 +08:00
										 |  |  |   // Objective functions x1^2 - x1*x2 + x2^2 - 3*x1 + 5
 | 
					
						
							| 
									
										
										
										
											2014-04-15 10:57:55 +08:00
										 |  |  |   // Note the Hessian encodes:
 | 
					
						
							|  |  |  |   //        0.5*x1'*G11*x1 + x1'*G12*x2 + 0.5*x2'*G22*x2 - x1'*g1 - x2'*g2 + 0.5*f
 | 
					
						
							| 
									
										
										
										
											2014-11-27 05:40:48 +08:00
										 |  |  |   // Hence, we have G11=2, G12 = -1, g1 = +3, G22 = 2, g2 = 0, f = 10
 | 
					
						
							| 
									
										
										
										
											2014-12-09 19:13:57 +08:00
										 |  |  |   qp.cost.push_back( | 
					
						
							| 
									
										
										
										
											2014-11-26 16:04:34 +08:00
										 |  |  |       HessianFactor(X(1), X(2), 2.0 * ones(1, 1), -ones(1, 1), 3.0 * ones(1), | 
					
						
							|  |  |  |           2.0 * ones(1, 1), zero(1), 10.0)); | 
					
						
							| 
									
										
										
										
											2014-04-15 10:57:55 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // Inequality constraints
 | 
					
						
							| 
									
										
										
										
											2014-12-13 01:03:00 +08:00
										 |  |  |   qp.inequalities.push_back(LinearInequality(X(1), ones(1,1), X(2), ones(1,1), 2, 0)); // x1 + x2 <= 2 --> x1 + x2 -2 <= 0, --> b=2
 | 
					
						
							|  |  |  |   qp.inequalities.push_back(LinearInequality(X(1), -ones(1,1), 0, 1));                 // -x1     <= 0
 | 
					
						
							|  |  |  |   qp.inequalities.push_back(LinearInequality(X(2), -ones(1,1), 0, 2));                 //    -x2  <= 0
 | 
					
						
							|  |  |  |   qp.inequalities.push_back(LinearInequality(X(1), ones(1,1), 1.5, 3));                // x1      <= 3/2
 | 
					
						
							| 
									
										
										
										
											2014-04-15 10:57:55 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-09 19:13:57 +08:00
										 |  |  |   return qp; | 
					
						
							| 
									
										
										
										
											2014-04-15 10:57:55 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-27 05:40:48 +08:00
										 |  |  | TEST(QPSolver, TestCase) { | 
					
						
							|  |  |  |   VectorValues values; | 
					
						
							|  |  |  |   double x1 = 5, x2 = 7; | 
					
						
							|  |  |  |   values.insert(X(1), x1 * ones(1, 1)); | 
					
						
							|  |  |  |   values.insert(X(2), x2 * ones(1, 1)); | 
					
						
							| 
									
										
										
										
											2014-12-09 19:13:57 +08:00
										 |  |  |   QP qp = createTestCase(); | 
					
						
							|  |  |  |   DOUBLES_EQUAL(29, x1 * x1 - x1 * x2 + x2 * x2 - 3 * x1 + 5, 1e-9); | 
					
						
							|  |  |  |   DOUBLES_EQUAL(29, qp.cost[0]->error(values), 1e-9); | 
					
						
							| 
									
										
										
										
											2014-11-27 05:40:48 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-16 04:27:19 +08:00
										 |  |  | TEST(QPSolver, constraintsAux) { | 
					
						
							| 
									
										
										
										
											2014-12-09 19:13:57 +08:00
										 |  |  |   QP qp = createTestCase(); | 
					
						
							| 
									
										
										
										
											2014-11-27 05:40:48 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-09 19:13:57 +08:00
										 |  |  |   QPSolver solver(qp); | 
					
						
							| 
									
										
										
										
											2014-04-15 10:57:55 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   VectorValues lambdas; | 
					
						
							| 
									
										
										
										
											2014-12-13 06:23:31 +08:00
										 |  |  |   lambdas.insert(0, (Vector(1) << -0.5).finished()); | 
					
						
							|  |  |  |   lambdas.insert(1, (Vector(1) <<  0.0).finished()); | 
					
						
							|  |  |  |   lambdas.insert(2, (Vector(1) <<  0.3).finished()); | 
					
						
							|  |  |  |   lambdas.insert(3, (Vector(1) <<  0.1).finished()); | 
					
						
							| 
									
										
										
										
											2014-12-13 01:03:00 +08:00
										 |  |  |   int factorIx = solver.identifyLeavingConstraint(qp.inequalities, lambdas); | 
					
						
							|  |  |  |   LONGS_EQUAL(2, factorIx); | 
					
						
							| 
									
										
										
										
											2014-04-15 10:57:55 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   VectorValues lambdas2; | 
					
						
							| 
									
										
										
										
											2014-12-13 06:23:31 +08:00
										 |  |  |   lambdas2.insert(0, (Vector(1) << -0.5).finished()); | 
					
						
							|  |  |  |   lambdas2.insert(1, (Vector(1) <<  0.0).finished()); | 
					
						
							|  |  |  |   lambdas2.insert(2, (Vector(1) << -0.3).finished()); | 
					
						
							|  |  |  |   lambdas2.insert(3, (Vector(1) << -0.1).finished()); | 
					
						
							| 
									
										
										
										
											2014-12-13 01:03:00 +08:00
										 |  |  |   int factorIx2 = solver.identifyLeavingConstraint(qp.inequalities, lambdas2); | 
					
						
							| 
									
										
										
										
											2014-04-15 10:57:55 +08:00
										 |  |  |   LONGS_EQUAL(-1, factorIx2); | 
					
						
							| 
									
										
										
										
											2014-04-15 18:07:41 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* ************************************************************************* */ | 
					
						
							| 
									
										
										
										
											2014-04-16 01:55:24 +08:00
										 |  |  | // Create a simple test graph with one equality constraint
 | 
					
						
							| 
									
										
										
										
											2014-12-09 19:13:57 +08:00
										 |  |  | QP createEqualityConstrainedTest() { | 
					
						
							|  |  |  |   QP qp; | 
					
						
							| 
									
										
										
										
											2014-04-15 18:07:41 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // Objective functions x1^2 + x2^2
 | 
					
						
							|  |  |  |   // Note the Hessian encodes:
 | 
					
						
							|  |  |  |   //        0.5*x1'*G11*x1 + x1'*G12*x2 + 0.5*x2'*G22*x2 - x1'*g1 - x2'*g2 + 0.5*f
 | 
					
						
							|  |  |  |   // Hence, we have G11=2, G12 = 0, g1 = 0, G22 = 2, g2 = 0, f = 0
 | 
					
						
							| 
									
										
										
										
											2014-12-09 19:13:57 +08:00
										 |  |  |   qp.cost.push_back( | 
					
						
							| 
									
										
										
										
											2014-11-26 16:04:34 +08:00
										 |  |  |       HessianFactor(X(1), X(2), 2.0 * ones(1, 1), zeros(1, 1), zero(1), | 
					
						
							|  |  |  |           2.0 * ones(1, 1), zero(1), 0.0)); | 
					
						
							| 
									
										
										
										
											2014-04-15 18:07:41 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // Equality constraints
 | 
					
						
							|  |  |  |   // x1 + x2 = 1 --> x1 + x2 -1 = 0, hence we negate the b vector
 | 
					
						
							| 
									
										
										
										
											2014-12-13 06:23:31 +08:00
										 |  |  |   Matrix A1 = (Matrix(1, 1) << 1).finished(); | 
					
						
							|  |  |  |   Matrix A2 = (Matrix(1, 1) << 1).finished(); | 
					
						
							|  |  |  |   Vector b = -(Vector(1) << 1).finished(); | 
					
						
							| 
									
										
										
										
											2014-12-09 19:13:57 +08:00
										 |  |  |   qp.equalities.push_back(LinearEquality(X(1), A1, X(2), A2, b, 0)); | 
					
						
							| 
									
										
										
										
											2014-04-15 18:07:41 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-09 19:13:57 +08:00
										 |  |  |   return qp; | 
					
						
							| 
									
										
										
										
											2014-04-16 01:55:24 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TEST(QPSolver, dual) { | 
					
						
							| 
									
										
										
										
											2014-12-09 19:13:57 +08:00
										 |  |  |   QP qp = createEqualityConstrainedTest(); | 
					
						
							| 
									
										
										
										
											2014-04-16 01:55:24 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-15 18:07:41 +08:00
										 |  |  |   // Initials values
 | 
					
						
							| 
									
										
										
										
											2014-11-27 17:52:25 +08:00
										 |  |  |   VectorValues initialValues; | 
					
						
							|  |  |  |   initialValues.insert(X(1), ones(1)); | 
					
						
							|  |  |  |   initialValues.insert(X(2), ones(1)); | 
					
						
							| 
									
										
										
										
											2014-04-15 18:07:41 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-09 19:13:57 +08:00
										 |  |  |   QPSolver solver(qp); | 
					
						
							| 
									
										
										
										
											2014-04-15 18:07:41 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-09 19:13:57 +08:00
										 |  |  |   GaussianFactorGraph::shared_ptr dualGraph = solver.buildDualGraph( | 
					
						
							|  |  |  |       qp.inequalities, initialValues); | 
					
						
							|  |  |  |   VectorValues dual = dualGraph->optimize(); | 
					
						
							| 
									
										
										
										
											2014-04-15 18:07:41 +08:00
										 |  |  |   VectorValues expectedDual; | 
					
						
							| 
									
										
										
										
											2014-12-13 06:23:31 +08:00
										 |  |  |   expectedDual.insert(0, (Vector(1) << 2.0).finished()); | 
					
						
							| 
									
										
										
										
											2014-04-18 00:01:29 +08:00
										 |  |  |   CHECK(assert_equal(expectedDual, dual, 1e-10)); | 
					
						
							| 
									
										
										
										
											2014-04-15 10:57:55 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-16 01:55:24 +08:00
										 |  |  | /* ************************************************************************* */ | 
					
						
							| 
									
										
										
										
											2014-12-10 05:27:11 +08:00
										 |  |  | TEST(QPSolver, indentifyActiveConstraints) { | 
					
						
							|  |  |  |   QP qp = createTestCase(); | 
					
						
							|  |  |  |   QPSolver solver(qp); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   VectorValues currentSolution; | 
					
						
							|  |  |  |   currentSolution.insert(X(1), zero(1)); | 
					
						
							|  |  |  |   currentSolution.insert(X(2), zero(1)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   LinearInequalityFactorGraph workingSet = | 
					
						
							|  |  |  |       solver.identifyActiveConstraints(qp.inequalities, currentSolution); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-13 01:03:00 +08:00
										 |  |  |   CHECK(!workingSet.at(0)->active());   // inactive
 | 
					
						
							|  |  |  |   CHECK(workingSet.at(1)->active());    // active
 | 
					
						
							|  |  |  |   CHECK(workingSet.at(2)->active());    // active
 | 
					
						
							|  |  |  |   CHECK(!workingSet.at(3)->active());   // inactive
 | 
					
						
							| 
									
										
										
										
											2014-12-10 05:27:11 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   VectorValues solution  = solver.solveWithCurrentWorkingSet(workingSet); | 
					
						
							|  |  |  |   VectorValues expectedSolution; | 
					
						
							| 
									
										
										
										
											2014-12-13 06:23:31 +08:00
										 |  |  |   expectedSolution.insert(X(1), (Vector(1) << 0.0).finished()); | 
					
						
							|  |  |  |   expectedSolution.insert(X(2), (Vector(1) << 0.0).finished()); | 
					
						
							| 
									
										
										
										
											2014-12-10 05:27:11 +08:00
										 |  |  |   CHECK(assert_equal(expectedSolution, solution, 1e-100)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* ************************************************************************* */ | 
					
						
							|  |  |  | TEST(QPSolver, iterate) { | 
					
						
							|  |  |  |   QP qp = createTestCase(); | 
					
						
							|  |  |  |   QPSolver solver(qp); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   VectorValues currentSolution; | 
					
						
							|  |  |  |   currentSolution.insert(X(1), zero(1)); | 
					
						
							|  |  |  |   currentSolution.insert(X(2), zero(1)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   std::vector<VectorValues> expectedSolutions(4), expectedDuals(4); | 
					
						
							| 
									
										
										
										
											2014-12-13 06:23:31 +08:00
										 |  |  |   expectedSolutions[0].insert(X(1), (Vector(1) << 0.0).finished()); | 
					
						
							|  |  |  |   expectedSolutions[0].insert(X(2), (Vector(1) << 0.0).finished()); | 
					
						
							|  |  |  |   expectedDuals[0].insert(1, (Vector(1) << 3).finished()); | 
					
						
							|  |  |  |   expectedDuals[0].insert(2, (Vector(1) << 0).finished()); | 
					
						
							| 
									
										
										
										
											2014-12-10 05:27:11 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-13 06:23:31 +08:00
										 |  |  |   expectedSolutions[1].insert(X(1), (Vector(1) << 1.5).finished()); | 
					
						
							|  |  |  |   expectedSolutions[1].insert(X(2), (Vector(1) << 0.0).finished()); | 
					
						
							|  |  |  |   expectedDuals[1].insert(3, (Vector(1) << 1.5).finished()); | 
					
						
							| 
									
										
										
										
											2014-12-10 05:27:11 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-13 06:23:31 +08:00
										 |  |  |   expectedSolutions[2].insert(X(1), (Vector(1) << 1.5).finished()); | 
					
						
							|  |  |  |   expectedSolutions[2].insert(X(2), (Vector(1) << 0.75).finished()); | 
					
						
							| 
									
										
										
										
											2014-12-10 05:27:11 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-13 06:23:31 +08:00
										 |  |  |   expectedSolutions[3].insert(X(1), (Vector(1) << 1.5).finished()); | 
					
						
							|  |  |  |   expectedSolutions[3].insert(X(2), (Vector(1) << 0.5).finished()); | 
					
						
							| 
									
										
										
										
											2014-12-10 05:27:11 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   LinearInequalityFactorGraph workingSet = | 
					
						
							|  |  |  |       solver.identifyActiveConstraints(qp.inequalities, currentSolution); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   QPState state(currentSolution, VectorValues(), workingSet, false); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   int it = 0; | 
					
						
							|  |  |  |   while (!state.converged) { | 
					
						
							|  |  |  |     state = solver.iterate(state); | 
					
						
							|  |  |  |     // These checks will fail because the expected solutions obtained from
 | 
					
						
							|  |  |  |     // Forst10book do not follow exactly what we implemented from Nocedal06book.
 | 
					
						
							|  |  |  |     // Specifically, we do not re-identify active constraints and
 | 
					
						
							|  |  |  |     // do not recompute dual variables after every step!!!
 | 
					
						
							|  |  |  | //    CHECK(assert_equal(expectedSolutions[it], state.values, 1e-10));
 | 
					
						
							|  |  |  | //    CHECK(assert_equal(expectedDuals[it], state.duals, 1e-10));
 | 
					
						
							|  |  |  |     it++; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   CHECK(assert_equal(expectedSolutions[3], state.values, 1e-10)); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2014-04-16 01:55:24 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* ************************************************************************* */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-16 04:47:07 +08:00
										 |  |  | TEST(QPSolver, optimizeForst10book_pg171Ex5) { | 
					
						
							| 
									
										
										
										
											2014-12-09 19:13:57 +08:00
										 |  |  |   QP qp = createTestCase(); | 
					
						
							|  |  |  |   QPSolver solver(qp); | 
					
						
							| 
									
										
										
										
											2014-11-27 17:52:25 +08:00
										 |  |  |   VectorValues initialValues; | 
					
						
							|  |  |  |   initialValues.insert(X(1), zero(1)); | 
					
						
							|  |  |  |   initialValues.insert(X(2), zero(1)); | 
					
						
							| 
									
										
											  
											
												Support non positive definite Hessian factors while doing EliminatePreferCholesky with some constrained factors.
Currently, when eliminating a constrained variable, EliminatePreferCholesky converts every other factors to JacobianFactor before doing the special QR factorization for constrained variables. Unfortunately, after a constrained nonlinear graph is linearized, new hessian factors from constraints, multiplied with the dual variable  (-lambda*\hessian{c} terms in the Lagrangian objective function), might become negative definite, thus cannot be converted to JacobianFactors.
Following EliminateCholesky, this version of EliminatePreferCholesky for constrained var gathers all unconstrained factors into a big joint HessianFactor before converting it into a JacobianFactor to be eliminiated by QR together with the other constrained factors.
Of course, this might not solve the non-positive-definite problem entirely, because (1) the original hessian factors might be non-positive definite and (2) large strange value of lambdas might cause the joint factor non-positive definite [is this true?]. But at least, this will help in typical cases.
											
										 
											2014-05-04 06:04:37 +08:00
										 |  |  |   VectorValues solution; | 
					
						
							| 
									
										
										
										
											2014-11-27 17:52:25 +08:00
										 |  |  |   boost::tie(solution, boost::tuples::ignore) = solver.optimize(initialValues); | 
					
						
							| 
									
										
										
										
											2014-04-16 03:14:10 +08:00
										 |  |  |   VectorValues expectedSolution; | 
					
						
							| 
									
										
										
										
											2014-12-13 06:23:31 +08:00
										 |  |  |   expectedSolution.insert(X(1), (Vector(1) << 1.5).finished()); | 
					
						
							|  |  |  |   expectedSolution.insert(X(2), (Vector(1) << 0.5).finished()); | 
					
						
							| 
									
										
										
										
											2014-04-16 03:14:10 +08:00
										 |  |  |   CHECK(assert_equal(expectedSolution, solution, 1e-100)); | 
					
						
							| 
									
										
										
										
											2014-04-16 01:55:24 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-16 04:47:07 +08:00
										 |  |  | /* ************************************************************************* */ | 
					
						
							| 
									
										
										
										
											2014-04-16 05:28:23 +08:00
										 |  |  | // Create Matlab's test graph as in http://www.mathworks.com/help/optim/ug/quadprog.html
 | 
					
						
							| 
									
										
										
										
											2014-12-09 19:13:57 +08:00
										 |  |  | QP createTestMatlabQPEx() { | 
					
						
							|  |  |  |   QP qp; | 
					
						
							| 
									
										
										
										
											2014-04-16 04:47:07 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // Objective functions 0.5*x1^2 + x2^2 - x1*x2 - 2*x1 -6*x2
 | 
					
						
							|  |  |  |   // Note the Hessian encodes:
 | 
					
						
							|  |  |  |   //        0.5*x1'*G11*x1 + x1'*G12*x2 + 0.5*x2'*G22*x2 - x1'*g1 - x2'*g2 + 0.5*f
 | 
					
						
							|  |  |  |   // Hence, we have G11=1, G12 = -1, g1 = +2, G22 = 2, g2 = +6, f = 0
 | 
					
						
							| 
									
										
										
										
											2014-12-09 19:13:57 +08:00
										 |  |  |   qp.cost.push_back( | 
					
						
							| 
									
										
										
										
											2014-11-26 16:04:34 +08:00
										 |  |  |       HessianFactor(X(1), X(2), 1.0 * ones(1, 1), -ones(1, 1), 2.0 * ones(1), | 
					
						
							|  |  |  |           2.0 * ones(1, 1), 6 * ones(1), 1000.0)); | 
					
						
							| 
									
										
										
										
											2014-04-16 04:47:07 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // Inequality constraints
 | 
					
						
							| 
									
										
										
										
											2014-12-13 01:03:00 +08:00
										 |  |  |   qp.inequalities.push_back(LinearInequality(X(1), One, X(2), One, 2, 0));      // x1 + x2 <= 2
 | 
					
						
							|  |  |  |   qp.inequalities.push_back(LinearInequality(X(1), -One, X(2), 2*One, 2, 1));   //-x1 + 2*x2 <=2
 | 
					
						
							|  |  |  |   qp.inequalities.push_back(LinearInequality(X(1), 2*One, X(2), One, 3, 2));    // 2*x1 + x2 <=3
 | 
					
						
							|  |  |  |   qp.inequalities.push_back(LinearInequality(X(1), -One, 0, 3));                // -x1      <= 0
 | 
					
						
							|  |  |  |   qp.inequalities.push_back(LinearInequality(X(2), -One, 0, 4));                //      -x2 <= 0
 | 
					
						
							| 
									
										
										
										
											2014-04-16 04:47:07 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-09 19:13:57 +08:00
										 |  |  |   return qp; | 
					
						
							| 
									
										
										
										
											2014-04-16 04:47:07 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TEST(QPSolver, optimizeMatlabEx) { | 
					
						
							| 
									
										
										
										
											2014-12-09 19:13:57 +08:00
										 |  |  |   QP qp = createTestMatlabQPEx(); | 
					
						
							|  |  |  |   QPSolver solver(qp); | 
					
						
							| 
									
										
										
										
											2014-11-27 17:52:25 +08:00
										 |  |  |   VectorValues initialValues; | 
					
						
							|  |  |  |   initialValues.insert(X(1), zero(1)); | 
					
						
							|  |  |  |   initialValues.insert(X(2), zero(1)); | 
					
						
							| 
									
										
											  
											
												Support non positive definite Hessian factors while doing EliminatePreferCholesky with some constrained factors.
Currently, when eliminating a constrained variable, EliminatePreferCholesky converts every other factors to JacobianFactor before doing the special QR factorization for constrained variables. Unfortunately, after a constrained nonlinear graph is linearized, new hessian factors from constraints, multiplied with the dual variable  (-lambda*\hessian{c} terms in the Lagrangian objective function), might become negative definite, thus cannot be converted to JacobianFactors.
Following EliminateCholesky, this version of EliminatePreferCholesky for constrained var gathers all unconstrained factors into a big joint HessianFactor before converting it into a JacobianFactor to be eliminiated by QR together with the other constrained factors.
Of course, this might not solve the non-positive-definite problem entirely, because (1) the original hessian factors might be non-positive definite and (2) large strange value of lambdas might cause the joint factor non-positive definite [is this true?]. But at least, this will help in typical cases.
											
										 
											2014-05-04 06:04:37 +08:00
										 |  |  |   VectorValues solution; | 
					
						
							| 
									
										
										
										
											2014-11-27 17:52:25 +08:00
										 |  |  |   boost::tie(solution, boost::tuples::ignore) = solver.optimize(initialValues); | 
					
						
							| 
									
										
										
										
											2014-04-16 04:47:07 +08:00
										 |  |  |   VectorValues expectedSolution; | 
					
						
							| 
									
										
										
										
											2014-12-13 06:23:31 +08:00
										 |  |  |   expectedSolution.insert(X(1), (Vector(1) << 2.0 / 3.0).finished()); | 
					
						
							|  |  |  |   expectedSolution.insert(X(2), (Vector(1) << 4.0 / 3.0).finished()); | 
					
						
							| 
									
										
										
										
											2014-04-16 04:47:07 +08:00
										 |  |  |   CHECK(assert_equal(expectedSolution, solution, 1e-7)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-16 05:28:23 +08:00
										 |  |  | /* ************************************************************************* */ | 
					
						
							|  |  |  | // Create test graph as in Nocedal06book, Ex 16.4, pg. 475
 | 
					
						
							| 
									
										
										
										
											2014-12-09 19:13:57 +08:00
										 |  |  | QP createTestNocedal06bookEx16_4() { | 
					
						
							|  |  |  |   QP qp; | 
					
						
							| 
									
										
										
										
											2014-04-16 05:28:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-09 19:13:57 +08:00
										 |  |  |   qp.cost.push_back(JacobianFactor(X(1), ones(1, 1), ones(1))); | 
					
						
							|  |  |  |   qp.cost.push_back(JacobianFactor(X(2), ones(1, 1), 2.5 * ones(1))); | 
					
						
							| 
									
										
										
										
											2014-04-16 05:28:23 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // Inequality constraints
 | 
					
						
							| 
									
										
										
										
											2014-12-13 01:03:00 +08:00
										 |  |  |   qp.inequalities.push_back(LinearInequality(X(1), -One, X(2), 2 * One, 2, 0)); | 
					
						
							|  |  |  |   qp.inequalities.push_back(LinearInequality(X(1), One, X(2), 2 * One, 6, 1)); | 
					
						
							|  |  |  |   qp.inequalities.push_back(LinearInequality(X(1), One, X(2), -2 * One, 2, 2)); | 
					
						
							|  |  |  |   qp.inequalities.push_back(LinearInequality(X(1), -One, 0.0, 3)); | 
					
						
							|  |  |  |   qp.inequalities.push_back(LinearInequality(X(2), -One, 0.0, 4)); | 
					
						
							| 
									
										
										
										
											2014-12-09 19:13:57 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   return qp; | 
					
						
							| 
									
										
										
										
											2014-04-16 05:28:23 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TEST(QPSolver, optimizeNocedal06bookEx16_4) { | 
					
						
							| 
									
										
										
										
											2014-12-09 19:13:57 +08:00
										 |  |  |   QP qp = createTestNocedal06bookEx16_4(); | 
					
						
							|  |  |  |   QPSolver solver(qp); | 
					
						
							| 
									
										
										
										
											2014-11-27 17:52:25 +08:00
										 |  |  |   VectorValues initialValues; | 
					
						
							| 
									
										
										
										
											2014-12-13 06:23:31 +08:00
										 |  |  |   initialValues.insert(X(1), (Vector(1) << 2.0).finished()); | 
					
						
							| 
									
										
										
										
											2014-11-27 17:52:25 +08:00
										 |  |  |   initialValues.insert(X(2), zero(1)); | 
					
						
							| 
									
										
										
										
											2014-04-16 05:28:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
											  
											
												Support non positive definite Hessian factors while doing EliminatePreferCholesky with some constrained factors.
Currently, when eliminating a constrained variable, EliminatePreferCholesky converts every other factors to JacobianFactor before doing the special QR factorization for constrained variables. Unfortunately, after a constrained nonlinear graph is linearized, new hessian factors from constraints, multiplied with the dual variable  (-lambda*\hessian{c} terms in the Lagrangian objective function), might become negative definite, thus cannot be converted to JacobianFactors.
Following EliminateCholesky, this version of EliminatePreferCholesky for constrained var gathers all unconstrained factors into a big joint HessianFactor before converting it into a JacobianFactor to be eliminiated by QR together with the other constrained factors.
Of course, this might not solve the non-positive-definite problem entirely, because (1) the original hessian factors might be non-positive definite and (2) large strange value of lambdas might cause the joint factor non-positive definite [is this true?]. But at least, this will help in typical cases.
											
										 
											2014-05-04 06:04:37 +08:00
										 |  |  |   VectorValues solution; | 
					
						
							| 
									
										
										
										
											2014-11-27 17:52:25 +08:00
										 |  |  |   boost::tie(solution, boost::tuples::ignore) = solver.optimize(initialValues); | 
					
						
							| 
									
										
										
										
											2014-04-16 05:28:23 +08:00
										 |  |  |   VectorValues expectedSolution; | 
					
						
							| 
									
										
										
										
											2014-12-13 06:23:31 +08:00
										 |  |  |   expectedSolution.insert(X(1), (Vector(1) << 1.4).finished()); | 
					
						
							|  |  |  |   expectedSolution.insert(X(2), (Vector(1) << 1.7).finished()); | 
					
						
							| 
									
										
										
										
											2014-04-16 05:28:23 +08:00
										 |  |  |   CHECK(assert_equal(expectedSolution, solution, 1e-7)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
											  
											
												Support non positive definite Hessian factors while doing EliminatePreferCholesky with some constrained factors.
Currently, when eliminating a constrained variable, EliminatePreferCholesky converts every other factors to JacobianFactor before doing the special QR factorization for constrained variables. Unfortunately, after a constrained nonlinear graph is linearized, new hessian factors from constraints, multiplied with the dual variable  (-lambda*\hessian{c} terms in the Lagrangian objective function), might become negative definite, thus cannot be converted to JacobianFactors.
Following EliminateCholesky, this version of EliminatePreferCholesky for constrained var gathers all unconstrained factors into a big joint HessianFactor before converting it into a JacobianFactor to be eliminiated by QR together with the other constrained factors.
Of course, this might not solve the non-positive-definite problem entirely, because (1) the original hessian factors might be non-positive definite and (2) large strange value of lambdas might cause the joint factor non-positive definite [is this true?]. But at least, this will help in typical cases.
											
										 
											2014-05-04 06:04:37 +08:00
										 |  |  | /* ************************************************************************* */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TEST(QPSolver, failedSubproblem) { | 
					
						
							| 
									
										
										
										
											2014-12-09 19:13:57 +08:00
										 |  |  |   QP qp; | 
					
						
							|  |  |  |   qp.cost.push_back(JacobianFactor(X(1), eye(2), zero(2))); | 
					
						
							|  |  |  |   qp.cost.push_back(HessianFactor(X(1), zeros(2, 2), zero(2), 100.0)); | 
					
						
							|  |  |  |   qp.inequalities.push_back( | 
					
						
							| 
									
										
										
										
											2014-12-13 06:23:31 +08:00
										 |  |  |       LinearInequality(X(1), (Matrix(1,2) << -1.0, 0.0).finished(), -1.0, 0)); | 
					
						
							| 
									
										
											  
											
												Support non positive definite Hessian factors while doing EliminatePreferCholesky with some constrained factors.
Currently, when eliminating a constrained variable, EliminatePreferCholesky converts every other factors to JacobianFactor before doing the special QR factorization for constrained variables. Unfortunately, after a constrained nonlinear graph is linearized, new hessian factors from constraints, multiplied with the dual variable  (-lambda*\hessian{c} terms in the Lagrangian objective function), might become negative definite, thus cannot be converted to JacobianFactors.
Following EliminateCholesky, this version of EliminatePreferCholesky for constrained var gathers all unconstrained factors into a big joint HessianFactor before converting it into a JacobianFactor to be eliminiated by QR together with the other constrained factors.
Of course, this might not solve the non-positive-definite problem entirely, because (1) the original hessian factors might be non-positive definite and (2) large strange value of lambdas might cause the joint factor non-positive definite [is this true?]. But at least, this will help in typical cases.
											
										 
											2014-05-04 06:04:37 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   VectorValues expected; | 
					
						
							| 
									
										
										
										
											2014-12-13 06:23:31 +08:00
										 |  |  |   expected.insert(X(1), (Vector(2) << 1.0, 0.0).finished()); | 
					
						
							| 
									
										
											  
											
												Support non positive definite Hessian factors while doing EliminatePreferCholesky with some constrained factors.
Currently, when eliminating a constrained variable, EliminatePreferCholesky converts every other factors to JacobianFactor before doing the special QR factorization for constrained variables. Unfortunately, after a constrained nonlinear graph is linearized, new hessian factors from constraints, multiplied with the dual variable  (-lambda*\hessian{c} terms in the Lagrangian objective function), might become negative definite, thus cannot be converted to JacobianFactors.
Following EliminateCholesky, this version of EliminatePreferCholesky for constrained var gathers all unconstrained factors into a big joint HessianFactor before converting it into a JacobianFactor to be eliminiated by QR together with the other constrained factors.
Of course, this might not solve the non-positive-definite problem entirely, because (1) the original hessian factors might be non-positive definite and (2) large strange value of lambdas might cause the joint factor non-positive definite [is this true?]. But at least, this will help in typical cases.
											
										 
											2014-05-04 06:04:37 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-17 00:27:20 +08:00
										 |  |  |   VectorValues initialValues; | 
					
						
							|  |  |  |   initialValues.insert(X(1),  (Vector(2) << 10.0, 100.0).finished()); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-09 19:13:57 +08:00
										 |  |  |   QPSolver solver(qp); | 
					
						
							| 
									
										
											  
											
												Support non positive definite Hessian factors while doing EliminatePreferCholesky with some constrained factors.
Currently, when eliminating a constrained variable, EliminatePreferCholesky converts every other factors to JacobianFactor before doing the special QR factorization for constrained variables. Unfortunately, after a constrained nonlinear graph is linearized, new hessian factors from constraints, multiplied with the dual variable  (-lambda*\hessian{c} terms in the Lagrangian objective function), might become negative definite, thus cannot be converted to JacobianFactors.
Following EliminateCholesky, this version of EliminatePreferCholesky for constrained var gathers all unconstrained factors into a big joint HessianFactor before converting it into a JacobianFactor to be eliminiated by QR together with the other constrained factors.
Of course, this might not solve the non-positive-definite problem entirely, because (1) the original hessian factors might be non-positive definite and (2) large strange value of lambdas might cause the joint factor non-positive definite [is this true?]. But at least, this will help in typical cases.
											
										 
											2014-05-04 06:04:37 +08:00
										 |  |  |   VectorValues solution; | 
					
						
							| 
									
										
										
										
											2014-12-17 00:27:20 +08:00
										 |  |  |   boost::tie(solution, boost::tuples::ignore) = solver.optimize(initialValues); | 
					
						
							| 
									
										
										
										
											2014-08-06 09:55:09 +08:00
										 |  |  | //  graph.print("Graph: ");
 | 
					
						
							|  |  |  | //  solution.print("Solution: ");
 | 
					
						
							| 
									
										
											  
											
												Support non positive definite Hessian factors while doing EliminatePreferCholesky with some constrained factors.
Currently, when eliminating a constrained variable, EliminatePreferCholesky converts every other factors to JacobianFactor before doing the special QR factorization for constrained variables. Unfortunately, after a constrained nonlinear graph is linearized, new hessian factors from constraints, multiplied with the dual variable  (-lambda*\hessian{c} terms in the Lagrangian objective function), might become negative definite, thus cannot be converted to JacobianFactors.
Following EliminateCholesky, this version of EliminatePreferCholesky for constrained var gathers all unconstrained factors into a big joint HessianFactor before converting it into a JacobianFactor to be eliminiated by QR together with the other constrained factors.
Of course, this might not solve the non-positive-definite problem entirely, because (1) the original hessian factors might be non-positive definite and (2) large strange value of lambdas might cause the joint factor non-positive definite [is this true?]. But at least, this will help in typical cases.
											
										 
											2014-05-04 06:04:37 +08:00
										 |  |  |   CHECK(assert_equal(expected, solution, 1e-7)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-15 10:57:55 +08:00
										 |  |  | /* ************************************************************************* */ | 
					
						
							|  |  |  | int main() { | 
					
						
							|  |  |  |   TestResult tr; | 
					
						
							|  |  |  |   return TestRegistry::runAllTests(tr); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | /* ************************************************************************* */ | 
					
						
							|  |  |  | 
 |