ActiveSetSolver.h 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. /* ----------------------------------------------------------------------------
  2. * GTSAM Copyright 2010, Georgia Tech Research Corporation,
  3. * Atlanta, Georgia 30332-0415
  4. * All Rights Reserved
  5. * Authors: Frank Dellaert, et al. (see THANKS for the full author list)
  6. * See LICENSE for the license information
  7. * -------------------------------------------------------------------------- */
  8. /**
  9. * @file ActiveSetSolver.h
  10. * @brief Active set method for solving LP, QP problems
  11. * @author Ivan Dario Jimenez
  12. * @author Duy Nguyen Ta
  13. * @date 1/25/16
  14. */
  15. #pragma once
  16. #include <gtsam/linear/GaussianFactorGraph.h>
  17. #include <gtsam_unstable/linear/InequalityFactorGraph.h>
  18. #include <boost/range/adaptor/map.hpp>
  19. namespace gtsam {
  20. /**
  21. * This class implements the active set algorithm for solving convex
  22. * Programming problems.
  23. *
  24. * @tparam PROBLEM Type of the problem to solve, e.g. LP (linear program) or
  25. * QP (quadratic program).
  26. * @tparam POLICY specific detail policy tailored for the particular program
  27. * @tparam INITSOLVER Solver for an initial feasible solution of this problem.
  28. */
  29. template <class PROBLEM, class POLICY, class INITSOLVER>
  30. class ActiveSetSolver {
  31. public:
  32. /// This struct contains the state information for a single iteration
  33. struct State {
  34. VectorValues values; //!< current best values at each step
  35. VectorValues duals; //!< current values of dual variables at each step
  36. InequalityFactorGraph workingSet; /*!< keep track of current active/inactive
  37. inequality constraints */
  38. bool converged; //!< True if the algorithm has converged to a solution
  39. size_t iterations; /*!< Number of iterations. Incremented at the end of
  40. each iteration. */
  41. /// Default constructor
  42. State()
  43. : values(), duals(), workingSet(), converged(false), iterations(0) {}
  44. /// Constructor with initial values
  45. State(const VectorValues& initialValues, const VectorValues& initialDuals,
  46. const InequalityFactorGraph& initialWorkingSet, bool _converged,
  47. size_t _iterations)
  48. : values(initialValues),
  49. duals(initialDuals),
  50. workingSet(initialWorkingSet),
  51. converged(_converged),
  52. iterations(_iterations) {}
  53. };
  54. protected:
  55. const PROBLEM& problem_; //!< the particular [convex] problem to solve
  56. VariableIndex equalityVariableIndex_,
  57. inequalityVariableIndex_; /*!< index to corresponding factors to build
  58. dual graphs */
  59. KeySet constrainedKeys_; /*!< all constrained keys, will become factors in
  60. dual graphs */
  61. /// Vector of key matrix pairs. Matrices are usually the A term for a factor.
  62. typedef std::vector<std::pair<Key, Matrix> > TermsContainer;
  63. public:
  64. /// Constructor
  65. ActiveSetSolver(const PROBLEM& problem) : problem_(problem) {
  66. equalityVariableIndex_ = VariableIndex(problem_.equalities);
  67. inequalityVariableIndex_ = VariableIndex(problem_.inequalities);
  68. constrainedKeys_ = problem_.equalities.keys();
  69. constrainedKeys_.merge(problem_.inequalities.keys());
  70. }
  71. /**
  72. * Optimize with provided initial values
  73. * For this version, it is the responsibility of the caller to provide
  74. * a feasible initial value, otherwise, an exception will be thrown.
  75. * @return a pair of <primal, dual> solutions
  76. */
  77. std::pair<VectorValues, VectorValues> optimize(
  78. const VectorValues& initialValues,
  79. const VectorValues& duals = VectorValues(),
  80. bool useWarmStart = false) const;
  81. /**
  82. * For this version the caller will not have to provide an initial value
  83. * @return a pair of <primal, dual> solutions
  84. */
  85. std::pair<VectorValues, VectorValues> optimize() const;
  86. protected:
  87. /**
  88. * Compute minimum step size alpha to move from the current point @p xk to the
  89. * next feasible point along a direction @p p: x' = xk + alpha*p,
  90. * where alpha \in [0,maxAlpha].
  91. *
  92. * For QP, maxAlpha = 1. For LP: maxAlpha = Inf.
  93. *
  94. * @return a tuple of (minAlpha, closestFactorIndex) where closestFactorIndex
  95. * is the closest inactive inequality constraint that blocks xk to move
  96. * further and that has the minimum alpha, or (-1, maxAlpha) if there is no
  97. * such inactive blocking constraint.
  98. *
  99. * If there is a blocking constraint, the closest one will be added to the
  100. * working set and become active in the next iteration.
  101. */
  102. boost::tuple<double, int> computeStepSize(
  103. const InequalityFactorGraph& workingSet, const VectorValues& xk,
  104. const VectorValues& p, const double& maxAlpha) const;
  105. /**
  106. * Finds the active constraints in the given factor graph and returns the
  107. * Dual Jacobians used to build a dual factor graph.
  108. */
  109. template<typename FACTOR>
  110. TermsContainer collectDualJacobians(Key key, const FactorGraph<FACTOR>& graph,
  111. const VariableIndex& variableIndex) const {
  112. /*
  113. * Iterates through each factor in the factor graph and checks
  114. * whether it's active. If the factor is active it reutrns the A
  115. * term of the factor.
  116. */
  117. TermsContainer Aterms;
  118. if (variableIndex.find(key) != variableIndex.end()) {
  119. for (size_t factorIx : variableIndex[key]) {
  120. typename FACTOR::shared_ptr factor = graph.at(factorIx);
  121. if (!factor->active())
  122. continue;
  123. Matrix Ai = factor->getA(factor->find(key)).transpose();
  124. Aterms.push_back(std::make_pair(factor->dualKey(), Ai));
  125. }
  126. }
  127. return Aterms;
  128. }
  129. /**
  130. * Creates a dual factor from the current workingSet and the key of the
  131. * the variable used to created the dual factor.
  132. */
  133. JacobianFactor::shared_ptr createDualFactor(
  134. Key key, const InequalityFactorGraph& workingSet,
  135. const VectorValues& delta) const;
  136. public: /// Just for testing...
  137. /// Builds a dual graph from the current working set.
  138. GaussianFactorGraph buildDualGraph(const InequalityFactorGraph &workingSet,
  139. const VectorValues &delta) const;
  140. /**
  141. * Build a working graph of cost, equality and active inequality constraints
  142. * to solve at each iteration.
  143. * @param workingSet the collection of all cost and constrained factors
  144. * @param xk current solution, used to build a special quadratic cost in LP
  145. * @return a new better solution
  146. */
  147. GaussianFactorGraph buildWorkingGraph(
  148. const InequalityFactorGraph& workingSet,
  149. const VectorValues& xk = VectorValues()) const;
  150. /// Iterate 1 step, return a new state with a new workingSet and values
  151. State iterate(const State& state) const;
  152. /// Identify active constraints based on initial values.
  153. InequalityFactorGraph identifyActiveConstraints(
  154. const InequalityFactorGraph& inequalities,
  155. const VectorValues& initialValues,
  156. const VectorValues& duals = VectorValues(),
  157. bool useWarmStart = false) const;
  158. /// Identifies active constraints that shouldn't be active anymore.
  159. int identifyLeavingConstraint(const InequalityFactorGraph& workingSet,
  160. const VectorValues& lambdas) const;
  161. };
  162. /**
  163. * Find the max key in a problem.
  164. * Useful to determine unique keys for additional slack variables
  165. */
  166. template <class PROBLEM>
  167. Key maxKey(const PROBLEM& problem) {
  168. auto keys = problem.cost.keys();
  169. Key maxKey = *std::max_element(keys.begin(), keys.end());
  170. if (!problem.equalities.empty())
  171. maxKey = std::max(maxKey, *problem.equalities.keys().rbegin());
  172. if (!problem.inequalities.empty())
  173. maxKey = std::max(maxKey, *problem.inequalities.keys().rbegin());
  174. return maxKey;
  175. }
  176. } // namespace gtsam
  177. #include <gtsam_unstable/linear/ActiveSetSolver-inl.h>