diff --git a/cpp/GaussianFactorGraph.cpp b/cpp/GaussianFactorGraph.cpp index 2ab65ccdb..1e9f33c0c 100644 --- a/cpp/GaussianFactorGraph.cpp +++ b/cpp/GaussianFactorGraph.cpp @@ -275,42 +275,36 @@ VectorConfig GaussianFactorGraph::optimalUpdate(const VectorConfig& x, // solve it for optimal step-size alpha GaussianConditional::shared_ptr gc = alphaGraph.eliminateOne("alpha"); double alpha = gc->get_d()(0); + cout << alpha << endl; // return updated estimate by stepping in direction d return x.exmap(d.scale(alpha)); } /* ************************************************************************* */ -VectorConfig GaussianFactorGraph::gradientDescent(const VectorConfig& x0) const { - VectorConfig x = x0; - int maxK = 10*x.dim(); - for (int k=0;k GaussianFactorGraph::gradientDescent_( - const VectorConfig& x0) const { - return boost::shared_ptr(new VectorConfig(gradientDescent(x0))); +boost::shared_ptr GaussianFactorGraph::steepestDescent_( + const VectorConfig& x0, double epsilon, size_t maxIterations) const { + return boost::shared_ptr(new VectorConfig( + gtsam::conjugateGradientDescent(*this, x0, epsilon, maxIterations))); } /* ************************************************************************* */ VectorConfig GaussianFactorGraph::conjugateGradientDescent( - const VectorConfig& x0, double threshold) const { - return gtsam::conjugateGradientDescent(*this, x0, threshold); + const VectorConfig& x0, double epsilon, size_t maxIterations) const { + return gtsam::conjugateGradientDescent(*this, x0, epsilon, maxIterations); } /* ************************************************************************* */ boost::shared_ptr GaussianFactorGraph::conjugateGradientDescent_( - const VectorConfig& x0, double threshold) const { + const VectorConfig& x0, double epsilon, size_t maxIterations) const { return boost::shared_ptr(new VectorConfig( - gtsam::conjugateGradientDescent(*this, x0, threshold))); + gtsam::conjugateGradientDescent(*this, x0, epsilon, maxIterations))); } /* ************************************************************************* */ diff --git a/cpp/GaussianFactorGraph.h b/cpp/GaussianFactorGraph.h index 116a4e706..67c2498e2 100644 --- a/cpp/GaussianFactorGraph.h +++ b/cpp/GaussianFactorGraph.h @@ -189,13 +189,15 @@ namespace gtsam { * @param x0: VectorConfig specifying initial estimate * @return solution */ - VectorConfig gradientDescent(const VectorConfig& x0) const; + VectorConfig steepestDescent(const VectorConfig& x0, double epsilon = 1e-5, + size_t maxIterations = 0) const; /** * shared pointer versions for MATLAB */ boost::shared_ptr - gradientDescent_(const VectorConfig& x0) const; + steepestDescent_(const VectorConfig& x0, double epsilon, + size_t maxIterations) const; /** * Find solution using conjugate gradient descent @@ -203,13 +205,13 @@ namespace gtsam { * @return solution */ VectorConfig conjugateGradientDescent(const VectorConfig& x0, - double threshold = 1e-9) const; + double epsilon = 1e-5, size_t maxIterations = 0) const; /** * shared pointer versions for MATLAB */ boost::shared_ptr conjugateGradientDescent_( - const VectorConfig& x0, double threshold = 1e-9) const; + const VectorConfig& x0, double epsilon, size_t maxIterations) const; }; } diff --git a/cpp/Vector.h b/cpp/Vector.h index fa93d1ae0..127a9bba3 100644 --- a/cpp/Vector.h +++ b/cpp/Vector.h @@ -79,6 +79,11 @@ inline Vector ones(size_t n) { return repeat(n,1.0);} * check if all zero */ bool zero(const Vector& v); + +/** + * dimensionality == size + */ +inline size_t dim(const Vector& v) { return v.size();} /** * print with optional string diff --git a/cpp/VectorConfig.h b/cpp/VectorConfig.h index 4f8941563..5971582a4 100644 --- a/cpp/VectorConfig.h +++ b/cpp/VectorConfig.h @@ -120,4 +120,7 @@ namespace gtsam { /** Dot product */ double dot(const VectorConfig&, const VectorConfig&); + /** dim function (for iterative::CGD) */ + inline double dim(const VectorConfig& x) { return x.dim();} + } // gtsam diff --git a/cpp/gtsam.h b/cpp/gtsam.h index 53e31e517..c240ee452 100644 --- a/cpp/gtsam.h +++ b/cpp/gtsam.h @@ -106,7 +106,7 @@ class GaussianFactorGraph { VectorConfig* optimize_(const Ordering& ordering); pair matrix(const Ordering& ordering) const; Matrix sparse(const Ordering& ordering) const; - VectorConfig* gradientDescent_(const VectorConfig& x0) const; + VectorConfig* steepestDescent_(const VectorConfig& x0) const; VectorConfig* conjugateGradientDescent_(const VectorConfig& x0) const; }; diff --git a/cpp/iterative.cpp b/cpp/iterative.cpp index 59cd75990..a4a6ad556 100644 --- a/cpp/iterative.cpp +++ b/cpp/iterative.cpp @@ -12,50 +12,28 @@ using namespace std; namespace gtsam { - /* ************************************************************************* */ - - /** - * gradient of objective function 0.5*|Ax-b|^2 at x = A'*(Ax-b) - */ - Vector gradient(const System& Ab, const Vector& x) { - const Matrix& A = Ab.first; - const Vector& b = Ab.second; - return A ^ (A * x - b); - } - - /** - * Apply operator A - */ - Vector operator*(const System& Ab, const Vector& x) { - const Matrix& A = Ab.first; - return A * x; - } - - /** - * Apply operator A^T - */ - Vector operator^(const System& Ab, const Vector& x) { - const Matrix& A = Ab.first; - return A ^ x; - } - /* ************************************************************************* */ // Method of conjugate gradients (CG) template // "System" class S needs gradient(S,v), e=S*v, v=S^e // "Vector" class V needs dot(v,v), -v, v+v, s*v // "Vector" class E needs dot(v,v) + // if (steepest) does steepest descent template - V CGD(const S& Ab, V x, double threshold = 1e-9) { + V conjugateGradients(const S& Ab, V x, size_t maxIterations, double epsilon, + bool steepest = false) { + + if (maxIterations == 0) maxIterations = dim(x); // Start with g0 = A'*(A*x0-b), d0 = - g0 // i.e., first step is in direction of negative gradient V g = gradient(Ab, x); V d = -g; - double prev_dotg = dot(g, g); + double dotg0 = dot(g, g), prev_dotg = dotg0; + double threshold = epsilon * epsilon * dotg0; // loop max n times size_t n = x.size(); - for (int k = 1; k <= n; k++) { + for (size_t k = 0; k < maxIterations; k++) { // calculate optimal step-size E Ad = Ab * d; @@ -73,24 +51,63 @@ namespace gtsam { if (dotg < threshold) break; // calculate new search direction - double beta = dotg / prev_dotg; - prev_dotg = dotg; - d = -g + beta * d; + if (steepest) + d = -g; + else { + double beta = dotg / prev_dotg; + prev_dotg = dotg; + d = -g + beta * d; + } } return x; } /* ************************************************************************* */ + + /** gradient of objective function 0.5*|Ax-b|^2 at x = A'*(Ax-b) */ + Vector gradient(const System& Ab, const Vector& x) { + const Matrix& A = Ab.first; + const Vector& b = Ab.second; + return A ^ (A * x - b); + } + + /** Apply operator A */ + Vector operator*(const System& Ab, const Vector& x) { + const Matrix& A = Ab.first; + return A * x; + } + + /** Apply operator A^T */ + Vector operator^(const System& Ab, const Vector& x) { + const Matrix& A = Ab.first; + return A ^ x; + } + + Vector steepestDescent(const System& Ab, const Vector& x, double epsilon, + size_t maxIterations) { + return conjugateGradients (Ab, x, epsilon, + maxIterations, true); + } + Vector conjugateGradientDescent(const System& Ab, const Vector& x, - double threshold) { - return CGD (Ab, x); + double epsilon, size_t maxIterations) { + return conjugateGradients (Ab, x, epsilon, + maxIterations); } /* ************************************************************************* */ - Vector conjugateGradientDescent(const Matrix& A, const Vector& b, - const Vector& x, double threshold) { + Vector steepestDescent(const Matrix& A, const Vector& b, const Vector& x, + double epsilon, size_t maxIterations) { System Ab = make_pair(A, b); - return CGD (Ab, x); + return conjugateGradients (Ab, x, epsilon, + maxIterations, true); + } + + Vector conjugateGradientDescent(const Matrix& A, const Vector& b, + const Vector& x, double epsilon, size_t maxIterations) { + System Ab = make_pair(A, b); + return conjugateGradients (Ab, x, epsilon, + maxIterations); } /* ************************************************************************* */ @@ -98,10 +115,16 @@ namespace gtsam { return fg.gradient(x); } - /* ************************************************************************* */ + VectorConfig steepestDescent(const GaussianFactorGraph& fg, + const VectorConfig& x, double epsilon, size_t maxIterations) { + return conjugateGradients (fg, + x, epsilon, maxIterations, true); + } + VectorConfig conjugateGradientDescent(const GaussianFactorGraph& fg, - const VectorConfig& x, double threshold) { - return CGD (fg, x); + const VectorConfig& x, double epsilon, size_t maxIterations) { + return conjugateGradients (fg, + x, epsilon, maxIterations); } /* ************************************************************************* */ diff --git a/cpp/iterative.h b/cpp/iterative.h index e99228f1f..fa922f278 100644 --- a/cpp/iterative.h +++ b/cpp/iterative.h @@ -11,24 +11,49 @@ namespace gtsam { class GaussianFactorGraph; class VectorConfig; + /** typedef for combined system |Ax-b|^2 */ typedef std::pair System; + /** + * In all calls below + * x is the initial estimate + * epsilon determines the convergence criterion: norm(g)