more refactoring to make QPSolver and LPSolver more similar
parent
dbac6169b2
commit
2cc0d93468
|
@ -21,10 +21,7 @@ namespace gtsam {
|
||||||
class ActiveSetSolver {
|
class ActiveSetSolver {
|
||||||
protected:
|
protected:
|
||||||
KeySet constrainedKeys_; //!< all constrained keys, will become factors in dual graphs
|
KeySet constrainedKeys_; //!< all constrained keys, will become factors in dual graphs
|
||||||
GaussianFactorGraph baseGraph_; //!< factor graphs of cost factors and linear equalities.
|
VariableIndex equalityVariableIndex_,
|
||||||
//!< used to initialize the working set factor graph,
|
|
||||||
//!< to which active inequalities will be added
|
|
||||||
VariableIndex costVariableIndex_, equalityVariableIndex_,
|
|
||||||
inequalityVariableIndex_; //!< index to corresponding factors to build dual graphs
|
inequalityVariableIndex_; //!< index to corresponding factors to build dual graphs
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -74,6 +74,13 @@ public:
|
||||||
cachedConstrainedKeyDimMap_.insert(keysDim2.begin(), keysDim2.end());
|
cachedConstrainedKeyDimMap_.insert(keysDim2.begin(), keysDim2.end());
|
||||||
return cachedConstrainedKeyDimMap_;
|
return cachedConstrainedKeyDimMap_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector costGradient(Key key, const VectorValues& delta) const {
|
||||||
|
Vector g = Vector::Zero(delta.at(key).size());
|
||||||
|
Factor::const_iterator it = cost.find(key);
|
||||||
|
if (it != cost.end()) g = cost.getA(it).transpose();
|
||||||
|
return g;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// traits
|
/// traits
|
||||||
|
|
|
@ -12,13 +12,9 @@
|
||||||
#include <gtsam_unstable/linear/LPInitSolver.h>
|
#include <gtsam_unstable/linear/LPInitSolver.h>
|
||||||
|
|
||||||
namespace gtsam {
|
namespace gtsam {
|
||||||
|
//******************************************************************************
|
||||||
LPSolver::LPSolver(const LP &lp) :
|
LPSolver::LPSolver(const LP &lp) :
|
||||||
lp_(lp), addedZeroPriorsIndex_() {
|
lp_(lp) {
|
||||||
// Push back factors that are the same in every iteration to the base graph.
|
|
||||||
// Those include the equality constraints and zero priors for keys that are
|
|
||||||
// not in the cost
|
|
||||||
baseGraph_.push_back(lp_.equalities);
|
|
||||||
|
|
||||||
// Variable index
|
// Variable index
|
||||||
equalityVariableIndex_ = VariableIndex(lp_.equalities);
|
equalityVariableIndex_ = VariableIndex(lp_.equalities);
|
||||||
inequalityVariableIndex_ = VariableIndex(lp_.inequalities);
|
inequalityVariableIndex_ = VariableIndex(lp_.inequalities);
|
||||||
|
@ -26,6 +22,7 @@ LPSolver::LPSolver(const LP &lp) :
|
||||||
constrainedKeys_.merge(lp_.inequalities.keys());
|
constrainedKeys_.merge(lp_.inequalities.keys());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
LPState LPSolver::iterate(const LPState &state) const {
|
LPState LPSolver::iterate(const LPState &state) const {
|
||||||
// Solve with the current working set
|
// Solve with the current working set
|
||||||
// LP: project the objective neg. gradient to the constraint's null space
|
// LP: project the objective neg. gradient to the constraint's null space
|
||||||
|
@ -39,7 +36,7 @@ LPState LPSolver::iterate(const LPState &state) const {
|
||||||
// Compute lambda from the dual graph
|
// Compute lambda from the dual graph
|
||||||
// LP: project the objective's gradient onto each constraint gradient to
|
// LP: project the objective's gradient onto each constraint gradient to
|
||||||
// obtain the dual scaling factors
|
// obtain the dual scaling factors
|
||||||
// is it true??
|
// is it true??
|
||||||
GaussianFactorGraph::shared_ptr dualGraph = buildDualGraph(state.workingSet,
|
GaussianFactorGraph::shared_ptr dualGraph = buildDualGraph(state.workingSet,
|
||||||
newValues);
|
newValues);
|
||||||
VectorValues duals = dualGraph->optimize();
|
VectorValues duals = dualGraph->optimize();
|
||||||
|
@ -64,8 +61,8 @@ LPState LPSolver::iterate(const LPState &state) const {
|
||||||
// If we CAN make some progress, i.e. p_k != 0
|
// If we CAN make some progress, i.e. p_k != 0
|
||||||
// Adapt stepsize if some inactive constraints complain about this move
|
// Adapt stepsize if some inactive constraints complain about this move
|
||||||
// LP: projection on nullspace is NOT zero:
|
// LP: projection on nullspace is NOT zero:
|
||||||
// find and put a blocking inactive constraint to the working set,
|
// find and put a blocking inactive constraint to the working set,
|
||||||
// otherwise the problem is unbounded!!!
|
// otherwise the problem is unbounded!!!
|
||||||
double alpha;
|
double alpha;
|
||||||
int factorIx;
|
int factorIx;
|
||||||
VectorValues p = newValues - state.values;
|
VectorValues p = newValues - state.values;
|
||||||
|
@ -83,6 +80,7 @@ LPState LPSolver::iterate(const LPState &state) const {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
GaussianFactorGraph::shared_ptr LPSolver::createLeastSquareFactors(
|
GaussianFactorGraph::shared_ptr LPSolver::createLeastSquareFactors(
|
||||||
const LinearCost &cost, const VectorValues &xk) const {
|
const LinearCost &cost, const VectorValues &xk) const {
|
||||||
GaussianFactorGraph::shared_ptr graph(new GaussianFactorGraph());
|
GaussianFactorGraph::shared_ptr graph(new GaussianFactorGraph());
|
||||||
|
@ -110,16 +108,13 @@ GaussianFactorGraph::shared_ptr LPSolver::createLeastSquareFactors(
|
||||||
return graph;
|
return graph;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
VectorValues LPSolver::solveWithCurrentWorkingSet(const VectorValues &xk,
|
VectorValues LPSolver::solveWithCurrentWorkingSet(const VectorValues &xk,
|
||||||
const InequalityFactorGraph &workingSet) const {
|
const InequalityFactorGraph &workingSet) const {
|
||||||
GaussianFactorGraph workingGraph = baseGraph_; // || X - Xk + g ||^2
|
GaussianFactorGraph workingGraph;
|
||||||
// We remove the old zero priors from the base graph we are going to use to solve
|
// || X - Xk + g ||^2
|
||||||
//This iteration's problem
|
|
||||||
// for (size_t index : addedZeroPriorsIndex_) {
|
|
||||||
// workingGraph.remove(index);
|
|
||||||
// }
|
|
||||||
|
|
||||||
workingGraph.push_back(*createLeastSquareFactors(lp_.cost, xk));
|
workingGraph.push_back(*createLeastSquareFactors(lp_.cost, xk));
|
||||||
|
workingGraph.push_back(lp_.equalities);
|
||||||
for (const LinearInequality::shared_ptr &factor : workingSet) {
|
for (const LinearInequality::shared_ptr &factor : workingSet) {
|
||||||
if (factor->active())
|
if (factor->active())
|
||||||
workingGraph.push_back(factor);
|
workingGraph.push_back(factor);
|
||||||
|
@ -127,37 +122,36 @@ VectorValues LPSolver::solveWithCurrentWorkingSet(const VectorValues &xk,
|
||||||
return workingGraph.optimize();
|
return workingGraph.optimize();
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::shared_ptr<JacobianFactor> LPSolver::createDualFactor(Key key,
|
//******************************************************************************
|
||||||
const InequalityFactorGraph &workingSet, const VectorValues &delta) const {
|
boost::shared_ptr<JacobianFactor> LPSolver::createDualFactor(
|
||||||
|
Key key, const InequalityFactorGraph &workingSet,
|
||||||
|
const VectorValues &delta) const {
|
||||||
// Transpose the A matrix of constrained factors to have the jacobian of the
|
// Transpose the A matrix of constrained factors to have the jacobian of the
|
||||||
// dual key
|
// dual key
|
||||||
TermsContainer Aterms = collectDualJacobians < LinearEquality
|
TermsContainer Aterms = collectDualJacobians<LinearEquality>(
|
||||||
> (key, lp_.equalities, equalityVariableIndex_);
|
key, lp_.equalities, equalityVariableIndex_);
|
||||||
TermsContainer AtermsInequalities = collectDualJacobians < LinearInequality
|
TermsContainer AtermsInequalities = collectDualJacobians<LinearInequality>(
|
||||||
> (key, workingSet, inequalityVariableIndex_);
|
key, workingSet, inequalityVariableIndex_);
|
||||||
Aterms.insert(Aterms.end(), AtermsInequalities.begin(),
|
Aterms.insert(Aterms.end(), AtermsInequalities.begin(),
|
||||||
AtermsInequalities.end());
|
AtermsInequalities.end());
|
||||||
|
|
||||||
// Collect the gradients of unconstrained cost factors to the b vector
|
// Collect the gradients of unconstrained cost factors to the b vector
|
||||||
if (Aterms.size() > 0) {
|
if (Aterms.size() > 0) {
|
||||||
Vector b = Vector::Zero(delta.at(key).size());
|
Vector b = lp_.costGradient(key, delta);
|
||||||
Factor::const_iterator it = lp_.cost.find(key);
|
// to compute the least-square approximation of dual variables
|
||||||
if (it != lp_.cost.end())
|
return boost::make_shared<JacobianFactor>(Aterms, b);
|
||||||
b = lp_.cost.getA(it).transpose();
|
|
||||||
return boost::make_shared < JacobianFactor > (Aterms, b); // compute the least-square approximation of dual variables
|
|
||||||
} else {
|
} else {
|
||||||
return boost::make_shared<JacobianFactor>();
|
return boost::make_shared<JacobianFactor>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
InequalityFactorGraph LPSolver::identifyActiveConstraints(
|
InequalityFactorGraph LPSolver::identifyActiveConstraints(
|
||||||
const InequalityFactorGraph &inequalities,
|
const InequalityFactorGraph &inequalities,
|
||||||
const VectorValues &initialValues, const VectorValues &duals) const {
|
const VectorValues &initialValues, const VectorValues &duals) const {
|
||||||
InequalityFactorGraph workingSet;
|
InequalityFactorGraph workingSet;
|
||||||
for (const LinearInequality::shared_ptr &factor : inequalities) {
|
for (const LinearInequality::shared_ptr &factor : inequalities) {
|
||||||
LinearInequality::shared_ptr workingFactor(new LinearInequality(*factor));
|
LinearInequality::shared_ptr workingFactor(new LinearInequality(*factor));
|
||||||
GTSAM_PRINT(*workingFactor);
|
|
||||||
GTSAM_PRINT(initialValues);
|
|
||||||
double error = workingFactor->error(initialValues);
|
double error = workingFactor->error(initialValues);
|
||||||
// TODO: find a feasible initial point for LPSolver.
|
// TODO: find a feasible initial point for LPSolver.
|
||||||
// For now, we just throw an exception
|
// For now, we just throw an exception
|
||||||
|
@ -174,6 +168,7 @@ InequalityFactorGraph LPSolver::identifyActiveConstraints(
|
||||||
return workingSet;
|
return workingSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
std::pair<VectorValues, VectorValues> LPSolver::optimize(
|
std::pair<VectorValues, VectorValues> LPSolver::optimize(
|
||||||
const VectorValues &initialValues, const VectorValues &duals) const {
|
const VectorValues &initialValues, const VectorValues &duals) const {
|
||||||
{
|
{
|
||||||
|
@ -190,6 +185,7 @@ std::pair<VectorValues, VectorValues> LPSolver::optimize(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
boost::tuples::tuple<double, int> LPSolver::computeStepSize(
|
boost::tuples::tuple<double, int> LPSolver::computeStepSize(
|
||||||
const InequalityFactorGraph &workingSet, const VectorValues &xk,
|
const InequalityFactorGraph &workingSet, const VectorValues &xk,
|
||||||
const VectorValues &p) const {
|
const VectorValues &p) const {
|
||||||
|
@ -197,6 +193,7 @@ boost::tuples::tuple<double, int> LPSolver::computeStepSize(
|
||||||
std::numeric_limits<double>::infinity());
|
std::numeric_limits<double>::infinity());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
pair<VectorValues, VectorValues> LPSolver::optimize() const {
|
pair<VectorValues, VectorValues> LPSolver::optimize() const {
|
||||||
LPInitSolver initSolver(lp_);
|
LPInitSolver initSolver(lp_);
|
||||||
VectorValues initValues = initSolver.solve();
|
VectorValues initValues = initSolver.solve();
|
||||||
|
|
|
@ -21,7 +21,6 @@ namespace gtsam {
|
||||||
|
|
||||||
class LPSolver: public ActiveSetSolver {
|
class LPSolver: public ActiveSetSolver {
|
||||||
const LP &lp_; //!< the linear programming problem
|
const LP &lp_; //!< the linear programming problem
|
||||||
std::vector<size_t> addedZeroPriorsIndex_;
|
|
||||||
public:
|
public:
|
||||||
/// Constructor
|
/// Constructor
|
||||||
LPSolver(const LP &lp);
|
LPSolver(const LP &lp);
|
||||||
|
|
|
@ -33,6 +33,10 @@ struct QP {
|
||||||
EqualityFactorGraph equalities; //!< linear equality constraints: cE(x) = 0
|
EqualityFactorGraph equalities; //!< linear equality constraints: cE(x) = 0
|
||||||
InequalityFactorGraph inequalities; //!< linear inequality constraints: cI(x) <= 0
|
InequalityFactorGraph inequalities; //!< linear inequality constraints: cI(x) <= 0
|
||||||
|
|
||||||
|
private:
|
||||||
|
mutable VariableIndex cachedCostVariableIndex_;
|
||||||
|
|
||||||
|
public:
|
||||||
/** default constructor */
|
/** default constructor */
|
||||||
QP() :
|
QP() :
|
||||||
cost(), equalities(), inequalities() {
|
cost(), equalities(), inequalities() {
|
||||||
|
@ -53,6 +57,23 @@ struct QP {
|
||||||
equalities.print("Linear equality factors: ");
|
equalities.print("Linear equality factors: ");
|
||||||
inequalities.print("Linear inequality factors: ");
|
inequalities.print("Linear inequality factors: ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const VariableIndex& costVariableIndex() const {
|
||||||
|
if (cachedCostVariableIndex_.size() == 0)
|
||||||
|
cachedCostVariableIndex_ = VariableIndex(cost);
|
||||||
|
return cachedCostVariableIndex_;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector costGradient(Key key, const VectorValues& delta) const {
|
||||||
|
Vector g = Vector::Zero(delta.at(key).size());
|
||||||
|
if (costVariableIndex().find(key) != costVariableIndex().end()) {
|
||||||
|
for (size_t factorIx : costVariableIndex()[key]) {
|
||||||
|
GaussianFactor::shared_ptr factor = cost.at(factorIx);
|
||||||
|
g += factor->gradient(key, delta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return g;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace gtsam
|
} // namespace gtsam
|
||||||
|
|
|
@ -31,9 +31,6 @@ namespace gtsam {
|
||||||
//******************************************************************************
|
//******************************************************************************
|
||||||
QPSolver::QPSolver(const QP& qp) :
|
QPSolver::QPSolver(const QP& qp) :
|
||||||
qp_(qp) {
|
qp_(qp) {
|
||||||
baseGraph_ = qp_.cost;
|
|
||||||
baseGraph_.push_back(qp_.equalities.begin(), qp_.equalities.end());
|
|
||||||
costVariableIndex_ = VariableIndex(qp_.cost);
|
|
||||||
equalityVariableIndex_ = VariableIndex(qp_.equalities);
|
equalityVariableIndex_ = VariableIndex(qp_.equalities);
|
||||||
inequalityVariableIndex_ = VariableIndex(qp_.inequalities);
|
inequalityVariableIndex_ = VariableIndex(qp_.inequalities);
|
||||||
constrainedKeys_ = qp_.equalities.keys();
|
constrainedKeys_ = qp_.equalities.keys();
|
||||||
|
@ -43,7 +40,8 @@ QPSolver::QPSolver(const QP& qp) :
|
||||||
//***************************************************cc***************************
|
//***************************************************cc***************************
|
||||||
VectorValues QPSolver::solveWithCurrentWorkingSet(
|
VectorValues QPSolver::solveWithCurrentWorkingSet(
|
||||||
const InequalityFactorGraph& workingSet) const {
|
const InequalityFactorGraph& workingSet) const {
|
||||||
GaussianFactorGraph workingGraph = baseGraph_;
|
GaussianFactorGraph workingGraph = qp_.cost;
|
||||||
|
workingGraph.push_back(qp_.equalities);
|
||||||
for (const LinearInequality::shared_ptr& factor : workingSet) {
|
for (const LinearInequality::shared_ptr& factor : workingSet) {
|
||||||
if (factor->active())
|
if (factor->active())
|
||||||
workingGraph.push_back(factor);
|
workingGraph.push_back(factor);
|
||||||
|
@ -52,28 +50,23 @@ VectorValues QPSolver::solveWithCurrentWorkingSet(
|
||||||
}
|
}
|
||||||
|
|
||||||
//******************************************************************************
|
//******************************************************************************
|
||||||
JacobianFactor::shared_ptr QPSolver::createDualFactor(Key key,
|
JacobianFactor::shared_ptr QPSolver::createDualFactor(
|
||||||
const InequalityFactorGraph& workingSet, const VectorValues& delta) const {
|
Key key, const InequalityFactorGraph& workingSet,
|
||||||
|
const VectorValues& delta) const {
|
||||||
// Transpose the A matrix of constrained factors to have the jacobian of the
|
// Transpose the A matrix of constrained factors to have the jacobian of the
|
||||||
// dual key
|
// dual key
|
||||||
std::vector < std::pair<Key, Matrix> > Aterms = collectDualJacobians
|
TermsContainer Aterms = collectDualJacobians<LinearEquality>(
|
||||||
< LinearEquality > (key, qp_.equalities, equalityVariableIndex_);
|
key, qp_.equalities, equalityVariableIndex_);
|
||||||
std::vector < std::pair<Key, Matrix> > AtermsInequalities =
|
TermsContainer AtermsInequalities = collectDualJacobians<LinearInequality>(
|
||||||
collectDualJacobians < LinearInequality
|
key, workingSet, inequalityVariableIndex_);
|
||||||
> (key, workingSet, inequalityVariableIndex_);
|
|
||||||
Aterms.insert(Aterms.end(), AtermsInequalities.begin(),
|
Aterms.insert(Aterms.end(), AtermsInequalities.begin(),
|
||||||
AtermsInequalities.end());
|
AtermsInequalities.end());
|
||||||
|
|
||||||
// Collect the gradients of unconstrained cost factors to the b vector
|
// Collect the gradients of unconstrained cost factors to the b vector
|
||||||
if (Aterms.size() > 0) {
|
if (Aterms.size() > 0) {
|
||||||
Vector b = Vector::Zero(delta.at(key).size());
|
Vector b = qp_.costGradient(key, delta);
|
||||||
if (costVariableIndex_.find(key) != costVariableIndex_.end()) {
|
// to compute the least-square approximation of dual variables
|
||||||
for (size_t factorIx : costVariableIndex_[key]) {
|
return boost::make_shared<JacobianFactor>(Aterms, b);
|
||||||
GaussianFactor::shared_ptr factor = qp_.cost.at(factorIx);
|
|
||||||
b += factor->gradient(key, delta);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return boost::make_shared < JacobianFactor > (Aterms, b); // compute the least-square approximation of dual variables
|
|
||||||
} else {
|
} else {
|
||||||
return boost::make_shared<JacobianFactor>();
|
return boost::make_shared<JacobianFactor>();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue