Fixed math, use functor not macro

release/4.3a0
Frank Dellaert 2024-12-11 13:10:31 -05:00
parent 1ae3fc2ad8
commit af9db89ea9
2 changed files with 40 additions and 36 deletions

View File

@ -25,22 +25,27 @@
#include <gtsam/linear/JacobianFactor.h>
#include <gtsam/linear/KalmanFilter.h>
using namespace std;
#include "gtsam/base/Matrix.h"
// In the code below we often get a covariance matrix Q, and we need to create a
// JacobianFactor with cost 0.5 * |Ax - b|^T Q^{-1} |Ax - b|. Factorizing Q as
// Q = L L^T
// and hence
// Q^{-1} = L^{-T} L^{-1} = M^T M, with M = L^{-1}
// We then have
// 0.5 * |Ax - b|^T Q^{-1} |Ax - b|
// = 0.5 * |Ax - b|^T M^T M |Ax - b|
// = 0.5 * |MAx - Mb|^T |MAx - Mb|
// The functor below efficiently multiplies with M by calling L.solve().
namespace {
using Matrix = gtsam::Matrix;
struct InverseL : public Eigen::LLT<Matrix> {
InverseL(const Matrix& Q) : Eigen::LLT<Matrix>(Q) {}
Matrix operator*(const Matrix& A) const { return matrixL().solve(A); }
};
} // namespace
namespace gtsam {
// In the code below we often need to multiply matrices with R, the Cholesky
// factor of the information matrix Q^{-1}, when given a covariance matrix Q.
// We can do this efficiently using Eigen, as we have:
// Q = L L^T
// => Q^{-1} = L^{-T}L^{-1} = R^T R
// => L^{-1} = R
// Rather than explicitly calculate R and do R*A, we should use L.solve(A)
// The following macro makes L available in the scope where it is used:
#define FACTORIZE_Q_INTO_L(Q) \
Eigen::LLT<Matrix> llt(Q); \
auto L = llt.matrixL();
/* ************************************************************************* */
// Auxiliary function to solve factor graph and return pointer to root
// conditional
@ -85,19 +90,19 @@ KalmanFilter::State KalmanFilter::init(const Vector& x0,
// Create a factor graph f(x0), eliminate it into P(x0)
GaussianFactorGraph factorGraph;
// Perform Cholesky decomposition of P0
FACTORIZE_Q_INTO_L(P0)
// Perform Cholesky decomposition of P0 = LL^T
InverseL M(P0);
// Premultiply I and x0 with R
const Matrix R = L.solve(I_); // = R
const Vector b = L.solve(x0); // = R*x0
factorGraph.emplace_shared<JacobianFactor>(0, R, b);
// Premultiply I and x0 with M=L^{-1}
const Matrix A = M * I_; // = M
const Vector b = M * x0; // = M*x0
factorGraph.emplace_shared<JacobianFactor>(0, A, b);
return solve(factorGraph);
}
/* ************************************************************************* */
void KalmanFilter::print(const string& s) const {
cout << "KalmanFilter " << s << ", dim = " << n_ << endl;
void KalmanFilter::print(const std::string& s) const {
std::cout << "KalmanFilter " << s << ", dim = " << n_ << std::endl;
}
/* ************************************************************************* */
@ -126,13 +131,13 @@ KalmanFilter::State KalmanFilter::predictQ(const State& p, const Matrix& F,
assert(Q.cols() == n);
#endif
// Perform Cholesky decomposition of Q
FACTORIZE_Q_INTO_L(Q)
// Perform Cholesky decomposition of Q = LL^T
InverseL M(Q);
// Premultiply A1 = -F and A2 = I, b = B * u with R
const Matrix A1 = -L.solve(F); // = -R*F
const Matrix A2 = L.solve(I_); // = R
const Vector b = L.solve(B * u); // = R * (B * u)
// Premultiply -F, I, and B * u with M=L^{-1}
const Matrix A1 = -(M * F);
const Matrix A2 = M * I_;
const Vector b = M * (B * u);
return predict2(p, A1, A2, b);
}
@ -163,14 +168,13 @@ KalmanFilter::State KalmanFilter::updateQ(const State& p, const Matrix& H,
const Matrix& Q) const {
Key k = step(p);
// Perform Cholesky decomposition of Q
FACTORIZE_Q_INTO_L(Q)
// Perform Cholesky decomposition of Q = LL^T
InverseL M(Q);
// Pre-multiply H and z with R, respectively
const Matrix RtH = L.solve(H); // = R * H
const Vector b = L.solve(z); // = R * z
return fuse(p, std::make_shared<JacobianFactor>(k, RtH, b));
// Pre-multiply H and z with M=L^{-1}, respectively
const Matrix A = M * H;
const Vector b = M * z;
return fuse(p, std::make_shared<JacobianFactor>(k, A, b));
}
/* ************************************************************************* */

View File

@ -214,4 +214,4 @@ class GTSAM_EXPORT KalmanFilter {
size_t dim() const { return n_; }
};
} // namespace gtsam
} // namespace gtsam