| 
									
										
										
										
											2016-06-17 11:49:14 +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 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  * -------------------------------------------------------------------------- */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-26 08:24:37 +08:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * @file     ActiveSetSolver.h | 
					
						
							| 
									
										
										
										
											2016-06-17 11:49:14 +08:00
										 |  |  |  * @brief    Active set method for solving LP, QP problems | 
					
						
							| 
									
										
										
										
											2016-01-26 08:24:37 +08:00
										 |  |  |  * @author   Ivan Dario Jimenez | 
					
						
							| 
									
										
										
										
											2016-01-30 01:07:14 +08:00
										 |  |  |  * @author   Duy Nguyen Ta | 
					
						
							| 
									
										
										
										
											2016-01-26 08:24:37 +08:00
										 |  |  |  * @date     1/25/16 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | #pragma once
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-26 22:34:05 +08:00
										 |  |  | #include <gtsam/linear/GaussianFactorGraph.h>
 | 
					
						
							| 
									
										
										
										
											2016-02-12 12:28:08 +08:00
										 |  |  | #include <gtsam_unstable/linear/InequalityFactorGraph.h>
 | 
					
						
							| 
									
										
										
										
											2016-01-26 08:24:37 +08:00
										 |  |  | #include <boost/range/adaptor/map.hpp>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace gtsam { | 
					
						
							| 
									
										
										
										
											2016-02-12 12:28:08 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							| 
									
										
										
										
											2016-06-17 18:54:18 +08:00
										 |  |  |  * This class implements the active set algorithm for solving convex | 
					
						
							| 
									
										
										
										
											2016-06-17 11:49:14 +08:00
										 |  |  |  * Programming problems. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2019-02-11 22:39:48 +08:00
										 |  |  |  * @tparam PROBLEM Type of the problem to solve, e.g. LP (linear program) or | 
					
						
							| 
									
										
										
										
											2016-06-17 11:49:14 +08:00
										 |  |  |  *                 QP (quadratic program). | 
					
						
							|  |  |  |  * @tparam POLICY specific detail policy tailored for the particular program | 
					
						
							|  |  |  |  * @tparam INITSOLVER Solver for an initial feasible solution of this problem. | 
					
						
							| 
									
										
										
										
											2016-02-12 12:28:08 +08:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2016-06-17 11:49:14 +08:00
										 |  |  | template <class PROBLEM, class POLICY, class INITSOLVER> | 
					
						
							| 
									
										
										
										
											2016-01-26 08:24:37 +08:00
										 |  |  | class ActiveSetSolver { | 
					
						
							| 
									
										
										
										
											2016-06-17 11:49:14 +08:00
										 |  |  | public: | 
					
						
							| 
									
										
										
										
											2016-06-17 18:54:18 +08:00
										 |  |  |   /// This struct contains the state information for a single iteration
 | 
					
						
							| 
									
										
										
										
											2016-06-17 11:49:14 +08:00
										 |  |  |   struct State { | 
					
						
							|  |  |  |     VectorValues values;  //!< current best values at each step
 | 
					
						
							|  |  |  |     VectorValues duals;   //!< current values of dual variables at each step
 | 
					
						
							|  |  |  |     InequalityFactorGraph workingSet; /*!< keep track of current active/inactive
 | 
					
						
							|  |  |  |                                            inequality constraints */ | 
					
						
							|  |  |  |     bool converged;     //!< True if the algorithm has converged to a solution
 | 
					
						
							| 
									
										
										
										
											2016-06-17 18:54:18 +08:00
										 |  |  |     size_t iterations;  /*!< Number of iterations. Incremented at the end of
 | 
					
						
							|  |  |  |                         each iteration. */ | 
					
						
							| 
									
										
										
										
											2016-06-17 11:49:14 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /// Default constructor
 | 
					
						
							|  |  |  |     State() | 
					
						
							|  |  |  |         : values(), duals(), workingSet(), converged(false), iterations(0) {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /// Constructor with initial values
 | 
					
						
							|  |  |  |     State(const VectorValues& initialValues, const VectorValues& initialDuals, | 
					
						
							|  |  |  |           const InequalityFactorGraph& initialWorkingSet, bool _converged, | 
					
						
							|  |  |  |           size_t _iterations) | 
					
						
							|  |  |  |         : values(initialValues), | 
					
						
							|  |  |  |           duals(initialDuals), | 
					
						
							|  |  |  |           workingSet(initialWorkingSet), | 
					
						
							|  |  |  |           converged(_converged), | 
					
						
							|  |  |  |           iterations(_iterations) {} | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-30 01:07:14 +08:00
										 |  |  | protected: | 
					
						
							| 
									
										
										
										
											2016-06-17 11:49:14 +08:00
										 |  |  |   const PROBLEM& problem_;  //!< the particular [convex] problem to solve
 | 
					
						
							| 
									
										
										
										
											2016-06-16 20:12:40 +08:00
										 |  |  |   VariableIndex equalityVariableIndex_, | 
					
						
							| 
									
										
										
										
											2016-06-17 11:49:14 +08:00
										 |  |  |       inequalityVariableIndex_;  /*!< index to corresponding factors to build
 | 
					
						
							|  |  |  |                                  dual graphs */ | 
					
						
							|  |  |  |   KeySet constrainedKeys_;  /*!< all constrained keys, will become factors in
 | 
					
						
							|  |  |  |                                  dual graphs */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /// Vector of key matrix pairs. Matrices are usually the A term for a factor.
 | 
					
						
							| 
									
										
										
										
											2019-02-11 22:39:48 +08:00
										 |  |  |   typedef std::vector<std::pair<Key, Matrix> > TermsContainer; | 
					
						
							| 
									
										
										
										
											2016-01-26 08:24:37 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | public: | 
					
						
							| 
									
										
										
										
											2016-06-17 11:49:14 +08:00
										 |  |  |   /// Constructor
 | 
					
						
							|  |  |  |   ActiveSetSolver(const PROBLEM& problem) :  problem_(problem) { | 
					
						
							|  |  |  |     equalityVariableIndex_ = VariableIndex(problem_.equalities); | 
					
						
							|  |  |  |     inequalityVariableIndex_ = VariableIndex(problem_.inequalities); | 
					
						
							|  |  |  |     constrainedKeys_ = problem_.equalities.keys(); | 
					
						
							|  |  |  |     constrainedKeys_.merge(problem_.inequalities.keys()); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-12 12:28:08 +08:00
										 |  |  |   /**
 | 
					
						
							| 
									
										
										
										
											2016-06-17 11:49:14 +08:00
										 |  |  |    * Optimize with provided initial values | 
					
						
							|  |  |  |    * For this version, it is the responsibility of the caller to provide | 
					
						
							|  |  |  |    * a feasible initial value, otherwise, an exception will be thrown. | 
					
						
							|  |  |  |    * @return a pair of <primal, dual> solutions | 
					
						
							| 
									
										
										
										
											2016-02-12 12:28:08 +08:00
										 |  |  |    */ | 
					
						
							| 
									
										
										
										
											2016-06-17 11:49:14 +08:00
										 |  |  |   std::pair<VectorValues, VectorValues> optimize( | 
					
						
							|  |  |  |       const VectorValues& initialValues, | 
					
						
							|  |  |  |       const VectorValues& duals = VectorValues(), | 
					
						
							|  |  |  |       bool useWarmStart = false) const; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /**
 | 
					
						
							|  |  |  |    * For this version the caller will not have to provide an initial value | 
					
						
							|  |  |  |    * @return a pair of <primal, dual> solutions | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   std::pair<VectorValues, VectorValues> optimize() const; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | protected: | 
					
						
							|  |  |  |   /**
 | 
					
						
							| 
									
										
										
										
											2019-02-11 22:39:48 +08:00
										 |  |  |    * Compute minimum step size alpha to move from the current point @p xk to the | 
					
						
							|  |  |  |    * next feasible point along a direction @p p:  x' = xk + alpha*p, | 
					
						
							|  |  |  |    * where alpha \in [0,maxAlpha]. | 
					
						
							|  |  |  |    * | 
					
						
							| 
									
										
										
										
											2016-06-17 11:49:14 +08:00
										 |  |  |    * For QP, maxAlpha = 1. For LP: maxAlpha = Inf. | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * @return a tuple of (minAlpha, closestFactorIndex) where closestFactorIndex | 
					
						
							| 
									
										
										
										
											2019-02-11 22:39:48 +08:00
										 |  |  |    * is the closest inactive inequality constraint that blocks xk to move | 
					
						
							|  |  |  |    * further and that has the minimum alpha, or (-1, maxAlpha) if there is no | 
					
						
							| 
									
										
										
										
											2016-06-17 11:49:14 +08:00
										 |  |  |    * such inactive blocking constraint. | 
					
						
							| 
									
										
										
										
											2019-02-11 22:39:48 +08:00
										 |  |  |    * | 
					
						
							|  |  |  |    * If there is a blocking constraint, the closest one will be added to the | 
					
						
							| 
									
										
										
										
											2016-06-17 11:49:14 +08:00
										 |  |  |    * working set and become active in the next iteration. | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   boost::tuple<double, int> computeStepSize( | 
					
						
							|  |  |  |       const InequalityFactorGraph& workingSet, const VectorValues& xk, | 
					
						
							|  |  |  |       const VectorValues& p, const double& maxAlpha) const; | 
					
						
							| 
									
										
										
										
											2016-01-26 08:24:37 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-12 12:28:08 +08:00
										 |  |  |   /**
 | 
					
						
							| 
									
										
										
										
											2019-02-11 22:39:48 +08:00
										 |  |  |    * Finds the active constraints in the given factor graph and returns the | 
					
						
							| 
									
										
										
										
											2016-02-12 12:28:08 +08:00
										 |  |  |    * Dual Jacobians used to build a dual factor graph. | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   template<typename FACTOR> | 
					
						
							| 
									
										
										
										
											2016-06-14 10:58:36 +08:00
										 |  |  |   TermsContainer collectDualJacobians(Key key, const FactorGraph<FACTOR>& graph, | 
					
						
							| 
									
										
										
										
											2016-02-12 13:57:37 +08:00
										 |  |  |       const VariableIndex& variableIndex) const { | 
					
						
							|  |  |  |     /*
 | 
					
						
							| 
									
										
										
										
											2019-02-11 22:39:48 +08:00
										 |  |  |      * Iterates through each factor in the factor graph and checks | 
					
						
							|  |  |  |      * whether it's active. If the factor is active it reutrns the A | 
					
						
							| 
									
										
										
										
											2016-02-12 13:57:37 +08:00
										 |  |  |      * term of the factor. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     TermsContainer Aterms; | 
					
						
							|  |  |  |     if (variableIndex.find(key) != variableIndex.end()) { | 
					
						
							| 
									
										
										
										
											2016-06-14 10:58:36 +08:00
										 |  |  |       for (size_t factorIx : variableIndex[key]) { | 
					
						
							|  |  |  |         typename FACTOR::shared_ptr factor = graph.at(factorIx); | 
					
						
							|  |  |  |         if (!factor->active()) | 
					
						
							|  |  |  |           continue; | 
					
						
							|  |  |  |         Matrix Ai = factor->getA(factor->find(key)).transpose(); | 
					
						
							|  |  |  |         Aterms.push_back(std::make_pair(factor->dualKey(), Ai)); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2016-02-12 13:57:37 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-06-14 10:58:36 +08:00
										 |  |  |     return Aterms; | 
					
						
							| 
									
										
										
										
											2016-02-12 13:57:37 +08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2016-01-26 08:24:37 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-14 10:58:36 +08:00
										 |  |  |   /**
 | 
					
						
							| 
									
										
										
										
											2016-06-17 11:49:14 +08:00
										 |  |  |    * Creates a dual factor from the current workingSet and the key of the | 
					
						
							|  |  |  |    * the variable used to created the dual factor. | 
					
						
							| 
									
										
										
										
											2016-06-14 10:58:36 +08:00
										 |  |  |    */ | 
					
						
							| 
									
										
										
										
											2016-06-17 11:49:14 +08:00
										 |  |  |   JacobianFactor::shared_ptr createDualFactor( | 
					
						
							|  |  |  |     Key key, const InequalityFactorGraph& workingSet, | 
					
						
							|  |  |  |     const VectorValues& delta) const; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | public: /// Just for testing...
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /// Builds a dual graph from the current working set.
 | 
					
						
							| 
									
										
										
										
											2020-10-01 03:38:08 +08:00
										 |  |  |   GaussianFactorGraph buildDualGraph(const InequalityFactorGraph &workingSet, | 
					
						
							|  |  |  |                                      const VectorValues &delta) const; | 
					
						
							| 
									
										
										
										
											2016-01-30 01:07:14 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-14 10:58:36 +08:00
										 |  |  |   /**
 | 
					
						
							| 
									
										
										
										
											2016-06-17 11:49:14 +08:00
										 |  |  |    * Build a working graph of cost, equality and active inequality constraints | 
					
						
							|  |  |  |    * to solve at each iteration. | 
					
						
							|  |  |  |    * @param  workingSet the collection of all cost and constrained factors | 
					
						
							|  |  |  |    * @param  xk   current solution, used to build a special quadratic cost in LP | 
					
						
							|  |  |  |    * @return      a new better solution | 
					
						
							| 
									
										
										
										
											2016-06-14 10:58:36 +08:00
										 |  |  |    */ | 
					
						
							| 
									
										
										
										
											2016-06-17 11:49:14 +08:00
										 |  |  |   GaussianFactorGraph buildWorkingGraph( | 
					
						
							|  |  |  |       const InequalityFactorGraph& workingSet, | 
					
						
							|  |  |  |       const VectorValues& xk = VectorValues()) const; | 
					
						
							| 
									
										
										
										
											2019-02-11 22:39:48 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-17 11:49:14 +08:00
										 |  |  |   /// Iterate 1 step, return a new state with a new workingSet and values
 | 
					
						
							|  |  |  |   State iterate(const State& state) const; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /// Identify active constraints based on initial values.
 | 
					
						
							|  |  |  |   InequalityFactorGraph identifyActiveConstraints( | 
					
						
							|  |  |  |       const InequalityFactorGraph& inequalities, | 
					
						
							|  |  |  |       const VectorValues& initialValues, | 
					
						
							|  |  |  |       const VectorValues& duals = VectorValues(), | 
					
						
							|  |  |  |       bool useWarmStart = false) const; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /// Identifies active constraints that shouldn't be active anymore.
 | 
					
						
							|  |  |  |   int identifyLeavingConstraint(const InequalityFactorGraph& workingSet, | 
					
						
							|  |  |  |       const VectorValues& lambdas) const; | 
					
						
							| 
									
										
										
										
											2016-01-30 01:07:14 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-26 08:24:37 +08:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2016-06-16 18:49:19 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * Find the max key in a problem. | 
					
						
							|  |  |  |  * Useful to determine unique keys for additional slack variables | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | template <class PROBLEM> | 
					
						
							|  |  |  | Key maxKey(const PROBLEM& problem) { | 
					
						
							| 
									
										
										
										
											2016-06-16 20:10:46 +08:00
										 |  |  |   auto keys = problem.cost.keys(); | 
					
						
							|  |  |  |   Key maxKey = *std::max_element(keys.begin(), keys.end()); | 
					
						
							| 
									
										
										
										
											2016-06-16 18:49:19 +08:00
										 |  |  |   if (!problem.equalities.empty()) | 
					
						
							|  |  |  |     maxKey = std::max(maxKey, *problem.equalities.keys().rbegin()); | 
					
						
							|  |  |  |   if (!problem.inequalities.empty()) | 
					
						
							|  |  |  |     maxKey = std::max(maxKey, *problem.inequalities.keys().rbegin()); | 
					
						
							|  |  |  |   return maxKey; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-12 12:28:08 +08:00
										 |  |  | } // namespace gtsam
 | 
					
						
							| 
									
										
										
										
											2016-06-17 11:49:14 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include <gtsam_unstable/linear/ActiveSetSolver-inl.h>
 |