refactor maxKey and keyDimMap out of solvers
parent
7492a708d2
commit
8cdddeccd1
|
@ -92,4 +92,20 @@ protected:
|
|||
const InequalityFactorGraph& workingSet, const VectorValues& xk,
|
||||
const VectorValues& p, const double& startAlpha) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* Find the max key in a problem.
|
||||
* Useful to determine unique keys for additional slack variables
|
||||
*/
|
||||
template <class PROBLEM>
|
||||
Key maxKey(const PROBLEM& problem) {
|
||||
Key maxKey =
|
||||
*std::max_element(problem.cost.keys().begin(), problem.cost.keys().end());
|
||||
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;
|
||||
}
|
||||
|
||||
} // namespace gtsam
|
||||
|
|
|
@ -16,11 +16,36 @@ namespace gtsam {
|
|||
|
||||
using namespace std;
|
||||
|
||||
/// Mapping between variable's key and its corresponding dimensionality
|
||||
using KeyDimMap = std::map<Key, size_t>;
|
||||
/*
|
||||
* Iterates through every factor in a linear graph and generates a
|
||||
* mapping between every factor key and it's corresponding dimensionality.
|
||||
*/
|
||||
template <class LinearGraph>
|
||||
KeyDimMap collectKeyDim(const LinearGraph& linearGraph) {
|
||||
KeyDimMap keyDimMap;
|
||||
for (const typename LinearGraph::sharedFactor& factor : linearGraph) {
|
||||
if (!factor) continue;
|
||||
for (Key key : factor->keys())
|
||||
keyDimMap[key] = factor->getDim(factor->find(key));
|
||||
}
|
||||
return keyDimMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Data structure of a Linear Program
|
||||
*/
|
||||
struct LP {
|
||||
using shared_ptr = boost::shared_ptr<LP>;
|
||||
|
||||
LinearCost cost; //!< Linear cost factor
|
||||
EqualityFactorGraph equalities; //!< Linear equality constraints: cE(x) = 0
|
||||
InequalityFactorGraph inequalities; //!< Linear inequality constraints: cI(x) <= 0
|
||||
private:
|
||||
mutable KeyDimMap cachedConstrainedKeyDimMap_; //!< cached key-dim map of all variables in the constraints
|
||||
|
||||
public:
|
||||
/// check feasibility
|
||||
bool isFeasible(const VectorValues& x) const {
|
||||
return (equalities.error(x) == 0 && inequalities.error(x) == 0);
|
||||
|
@ -40,10 +65,19 @@ struct LP {
|
|||
&& inequalities.equals(other.inequalities);
|
||||
}
|
||||
|
||||
typedef boost::shared_ptr<LP> shared_ptr;
|
||||
const KeyDimMap& constrainedKeyDimMap() const {
|
||||
if (!cachedConstrainedKeyDimMap_.empty())
|
||||
return cachedConstrainedKeyDimMap_;
|
||||
// Collect key-dim map of all variables in the constraints
|
||||
cachedConstrainedKeyDimMap_ = collectKeyDim(equalities);
|
||||
KeyDimMap keysDim2 = collectKeyDim(inequalities);
|
||||
cachedConstrainedKeyDimMap_.insert(keysDim2.begin(), keysDim2.end());
|
||||
return cachedConstrainedKeyDimMap_;
|
||||
}
|
||||
};
|
||||
|
||||
/// traits
|
||||
template<> struct traits<LP> : public Testable<LP> {
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -41,12 +41,10 @@ namespace gtsam {
|
|||
*/
|
||||
class LPInitSolver {
|
||||
private:
|
||||
const LPSolver& lpSolver_;
|
||||
const LP& lp_;
|
||||
|
||||
public:
|
||||
LPInitSolver(const LPSolver& lpSolver) :
|
||||
lpSolver_(lpSolver), lp_(lpSolver.lp()) {
|
||||
LPInitSolver(const LP& lp) : lp_(lp) {
|
||||
}
|
||||
|
||||
virtual ~LPInitSolver() {
|
||||
|
@ -57,7 +55,7 @@ public:
|
|||
GaussianFactorGraph::shared_ptr initOfInitGraph = buildInitOfInitGraph();
|
||||
VectorValues x0 = initOfInitGraph->optimize();
|
||||
double y0 = compute_y0(x0);
|
||||
Key yKey = maxKey(lpSolver_.keysDim()) + 1; // the unique key for y0
|
||||
Key yKey = maxKey(lp_) + 1; // the unique key for y0
|
||||
VectorValues xy0(x0);
|
||||
xy0.insert(yKey, Vector::Constant(1, y0));
|
||||
|
||||
|
@ -86,15 +84,6 @@ private:
|
|||
return initLP;
|
||||
}
|
||||
|
||||
/// Find the max key in the problem to determine unique keys for additional slack variables
|
||||
Key maxKey(const KeyDimMap& keysDim) const {
|
||||
Key maxK = 0;
|
||||
for (Key key : keysDim | boost::adaptors::map_keys)
|
||||
if (maxK < key)
|
||||
maxK = key;
|
||||
return maxK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the following graph to solve for an initial value of the initial problem
|
||||
* min ||x||^2 s.t. Ax = b
|
||||
|
@ -105,9 +94,9 @@ private:
|
|||
new GaussianFactorGraph(lp_.equalities));
|
||||
|
||||
// create factor ||x||^2 and add to the graph
|
||||
const KeyDimMap& keysDim = lpSolver_.keysDim();
|
||||
for (Key key : keysDim | boost::adaptors::map_keys) {
|
||||
size_t dim = keysDim.at(key);
|
||||
const KeyDimMap& constrainedKeyDim = lp_.constrainedKeyDimMap();
|
||||
for (Key key : constrainedKeyDim | boost::adaptors::map_keys) {
|
||||
size_t dim = constrainedKeyDim.at(key);
|
||||
initGraph->push_back(
|
||||
JacobianFactor(key, Matrix::Identity(dim, dim), Vector::Zero(dim)));
|
||||
}
|
||||
|
|
|
@ -19,12 +19,6 @@ LPSolver::LPSolver(const LP &lp) :
|
|||
// not in the cost
|
||||
baseGraph_.push_back(lp_.equalities);
|
||||
|
||||
// Collect key-dim map of all variables in the constraints to create their
|
||||
// zero priors later
|
||||
keysDim_ = collectKeysDim(lp_.equalities);
|
||||
KeyDimMap keysDim2 = collectKeysDim(lp_.inequalities);
|
||||
keysDim_.insert(keysDim2.begin(), keysDim2.end());
|
||||
|
||||
// Variable index
|
||||
equalityVariableIndex_ = VariableIndex(lp_.equalities);
|
||||
inequalityVariableIndex_ = VariableIndex(lp_.inequalities);
|
||||
|
@ -101,14 +95,15 @@ GaussianFactorGraph::shared_ptr LPSolver::createLeastSquareFactors(
|
|||
KeySet allKeys = lp_.inequalities.keys();
|
||||
allKeys.merge(lp_.equalities.keys());
|
||||
allKeys.merge(KeySet(lp_.cost.keys()));
|
||||
// add the corresponding factors for all variables that are not explicitly in the
|
||||
// cost function for vars that are not in the cost, the cost gradient is zero (g=0), so b=xk
|
||||
// Add corresponding factors for all variables that are not explicitly in the
|
||||
// cost function. Gradients of the cost function wrt to these variables are
|
||||
// zero (g=0), so b=xk
|
||||
if (cost.keys().size() != allKeys.size()) {
|
||||
KeySet difference;
|
||||
std::set_difference(allKeys.begin(), allKeys.end(), lp_.cost.begin(),
|
||||
lp_.cost.end(), std::inserter(difference, difference.end()));
|
||||
for (Key k : difference) {
|
||||
size_t dim = keysDim_.at(k);
|
||||
size_t dim = lp_.constrainedKeyDimMap().at(k);
|
||||
graph->push_back(JacobianFactor(k, Matrix::Identity(dim, dim), xk.at(k)));
|
||||
}
|
||||
}
|
||||
|
@ -203,7 +198,7 @@ boost::tuples::tuple<double, int> LPSolver::computeStepSize(
|
|||
}
|
||||
|
||||
pair<VectorValues, VectorValues> LPSolver::optimize() const {
|
||||
LPInitSolver initSolver(*this);
|
||||
LPInitSolver initSolver(lp_);
|
||||
VectorValues initValues = initSolver.solve();
|
||||
return optimize(initValues);
|
||||
}
|
||||
|
|
|
@ -18,11 +18,9 @@
|
|||
|
||||
namespace gtsam {
|
||||
|
||||
typedef std::map<Key, size_t> KeyDimMap;
|
||||
|
||||
class LPSolver: public ActiveSetSolver {
|
||||
const LP &lp_; //!< the linear programming problem
|
||||
KeyDimMap keysDim_; //!< key-dim map of all variables in the constraints, used to create zero priors
|
||||
std::vector<size_t> addedZeroPriorsIndex_;
|
||||
public:
|
||||
/// Constructor
|
||||
|
@ -32,30 +30,6 @@ public:
|
|||
return lp_;
|
||||
}
|
||||
|
||||
const KeyDimMap &keysDim() const {
|
||||
return keysDim_;
|
||||
}
|
||||
|
||||
/*
|
||||
* Iterates through every factor in a linear graph and generates a
|
||||
* mapping between every factor key and it's corresponding dimensionality.
|
||||
*/
|
||||
template<class LinearGraph>
|
||||
KeyDimMap collectKeysDim(const LinearGraph &linearGraph) const {
|
||||
KeyDimMap keysDim;
|
||||
for (const typename LinearGraph::sharedFactor &factor : linearGraph) {
|
||||
if (!factor)
|
||||
continue;
|
||||
for (Key key : factor->keys())
|
||||
keysDim[key] = factor->getDim(factor->find(key));
|
||||
}
|
||||
return keysDim;
|
||||
}
|
||||
|
||||
/// Create a zero prior for any keys in the graph that don't exist in the cost
|
||||
GaussianFactorGraph::shared_ptr createZeroPriors(const KeyVector &costKeys,
|
||||
const KeyDimMap &keysDim) const;
|
||||
|
||||
/*
|
||||
* This function performs an iteration of the Active Set Method for solving
|
||||
* LP problems. At the end of this iteration the problem should either be found
|
||||
|
|
|
@ -172,25 +172,19 @@ pair<VectorValues, VectorValues> QPSolver::optimize(
|
|||
return make_pair(state.values, state.duals);
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
pair<VectorValues, VectorValues> QPSolver::optimize() const {
|
||||
//Make an LP with any linear cost function. It doesn't matter for initialization.
|
||||
LP initProblem;
|
||||
// make an unrelated key for a random variable cost: max key + 1
|
||||
Key newKey = *qp_.cost.keys().rbegin();
|
||||
if (!qp_.equalities.empty())
|
||||
newKey = std::max(newKey, *qp_.equalities.keys().rbegin());
|
||||
if (!qp_.inequalities.empty())
|
||||
newKey = std::max(newKey, *qp_.inequalities.keys().rbegin());
|
||||
++newKey;
|
||||
// make an unrelated key for a random variable cost
|
||||
Key newKey = maxKey(qp_) + 1;
|
||||
initProblem.cost = LinearCost(newKey, Vector::Ones(1));
|
||||
initProblem.equalities = qp_.equalities;
|
||||
initProblem.inequalities = qp_.inequalities;
|
||||
LPSolver solver(initProblem);
|
||||
LPInitSolver initSolver(solver);
|
||||
LPInitSolver initSolver(initProblem);
|
||||
VectorValues initValues = initSolver.solve();
|
||||
|
||||
return optimize(initValues);
|
||||
}
|
||||
;
|
||||
|
||||
} /* namespace gtsam */
|
||||
|
|
|
@ -106,8 +106,7 @@ TEST(LPInitSolver, infinite_loop_multi_var) {
|
|||
|
||||
TEST(LPInitSolver, initialization) {
|
||||
LP lp = simpleLP1();
|
||||
LPSolver lpSolver(lp);
|
||||
LPInitSolver initSolver(lpSolver);
|
||||
LPInitSolver initSolver(lp);
|
||||
|
||||
GaussianFactorGraph::shared_ptr initOfInitGraph = initSolver.buildInitOfInitGraph();
|
||||
VectorValues x0 = initOfInitGraph->optimize();
|
||||
|
|
Loading…
Reference in New Issue