gtsam/gtsam_unstable/nonlinear/LinearConstraintSQP.cpp

137 lines
4.8 KiB
C++
Raw Normal View History

2014-12-23 08:49:32 +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
* -------------------------------------------------------------------------- */
/**
2015-02-25 12:40:53 +08:00
* @file LinearConstraintSQP.cpp
2014-12-23 08:49:32 +08:00
* @author Duy-Nguyen Ta
* @author Krunal Chande
* @author Luca Carlone
* @date Dec 15, 2014
*/
2015-02-25 12:40:53 +08:00
#include <gtsam_unstable/nonlinear/LinearConstraintSQP.h>
2014-12-24 03:44:43 +08:00
#include <gtsam_unstable/linear/QPSolver.h>
#include <iostream>
2014-12-24 03:44:43 +08:00
2014-12-23 08:49:32 +08:00
namespace gtsam {
/* ************************************************************************* */
2015-02-25 12:40:53 +08:00
bool LinearConstraintSQP::isStationary(const VectorValues& delta) const {
2014-12-23 08:49:32 +08:00
return delta.vector().lpNorm<Eigen::Infinity>() < errorTol;
}
/* ************************************************************************* */
2015-02-25 12:40:53 +08:00
bool LinearConstraintSQP::isPrimalFeasible(const LinearConstraintNLPState& state) const {
return lcnlp_.linearEqualities.checkFeasibility(state.values, errorTol);
2014-12-23 08:49:32 +08:00
}
/* ************************************************************************* */
2015-02-25 12:40:53 +08:00
bool LinearConstraintSQP::isDualFeasible(const VectorValues& duals) const {
BOOST_FOREACH(const NonlinearFactor::shared_ptr& factor, lcnlp_.linearInequalities){
2015-02-25 12:40:53 +08:00
ConstrainedFactor::shared_ptr inequality
= boost::dynamic_pointer_cast<ConstrainedFactor>(factor);
2014-12-23 08:49:32 +08:00
Key dualKey = inequality->dualKey();
if (!duals.exists(dualKey)) continue; // should be inactive constraint!
double dual = duals.at(dualKey)[0];// because we only support single-valued inequalities
if (dual > 0.0) { // See the explanation in QPSolver::identifyLeavingConstraint, we want dual < 0 ?
2014-12-23 08:49:32 +08:00
return false;
}
2014-12-23 08:49:32 +08:00
}
return true;
}
/* ************************************************************************* */
2015-02-25 12:40:53 +08:00
bool LinearConstraintSQP::isComplementary(const LinearConstraintNLPState& state) const {
return lcnlp_.linearInequalities.checkFeasibilityAndComplimentary(
state.values, state.duals, errorTol);
2014-12-23 08:49:32 +08:00
}
/* ************************************************************************* */
2015-02-25 12:40:53 +08:00
bool LinearConstraintSQP::checkConvergence(const LinearConstraintNLPState& state,
const VectorValues& delta) const {
return isStationary(delta) && isPrimalFeasible(state)
&& isDualFeasible(state.duals) && isComplementary(state);
2014-12-23 08:49:32 +08:00
}
/* ************************************************************************* */
2015-02-25 12:40:53 +08:00
VectorValues LinearConstraintSQP::initializeDuals() const {
2014-12-23 08:49:32 +08:00
VectorValues duals;
BOOST_FOREACH(const NonlinearFactor::shared_ptr& factor, lcnlp_.linearEqualities){
2015-02-25 12:40:53 +08:00
ConstrainedFactor::shared_ptr constraint
= boost::dynamic_pointer_cast<ConstrainedFactor>(factor);
2014-12-23 08:49:32 +08:00
duals.insert(constraint->dualKey(), zero(factor->dim()));
}
return duals;
}
/* ************************************************************************* */
2015-02-25 12:40:53 +08:00
LinearConstraintNLPState LinearConstraintSQP::iterate(const LinearConstraintNLPState& state, bool useWarmStart,
bool debug) const {
2014-12-23 08:49:32 +08:00
// construct the qp subproblem
QP qp;
qp.cost = *lcnlp_.cost.linearize(state.values);
qp.equalities.add(*lcnlp_.linearEqualities.linearize(state.values));
qp.inequalities.add(*lcnlp_.linearInequalities.linearize(state.values));
2014-12-23 08:49:32 +08:00
// if (debug)
// qp.print("QP subproblem:");
2014-12-23 08:49:32 +08:00
// solve the QP subproblem
VectorValues delta, duals;
QPSolver qpSolver(qp);
VectorValues zeroInitialValues;
BOOST_FOREACH(const Values::ConstKeyValuePair& key_value, state.values) {
zeroInitialValues.insert(key_value.key, zero(key_value.value.dim()));
}
boost::tie(delta, duals) = qpSolver.optimize(zeroInitialValues, state.duals,
useWarmStart);
2014-12-23 08:49:32 +08:00
if (debug)
state.values.print("state.values: ");
2014-12-23 08:49:32 +08:00
if (debug)
delta.print("delta = ");
// if (debug)
// duals.print("duals = ");
2014-12-23 08:49:32 +08:00
// update new state
2015-02-25 12:40:53 +08:00
LinearConstraintNLPState newState;
2014-12-23 08:49:32 +08:00
newState.values = state.values.retract(delta);
newState.duals = duals;
newState.converged = checkConvergence(newState, delta);
newState.iterations = state.iterations + 1;
if (debug)
newState.print("newState: ");
2014-12-23 08:49:32 +08:00
return newState;
}
2015-02-25 12:40:53 +08:00
/* ************************************************************************* */
std::pair<Values, VectorValues> LinearConstraintSQP::optimize(
const Values& initialValues, bool useWarmStart, bool debug) const {
LinearConstraintNLPState state(initialValues);
state.duals = initializeDuals();
while (!state.converged && state.iterations < 100) {
if (debug)
std::cout << "state: iteration " << state.iterations << std::endl;
state = iterate(state, useWarmStart, debug);
}
if (debug)
std::cout << "Number of iterations: " << state.iterations << std::endl;
return std::make_pair(state.values, state.duals);
}
} // namespace gtsam
2014-12-23 08:49:32 +08:00