Sidestep Scatter altogether and just use HessianFactor keys_. In theory, n^3 lookup cost, but in practice (as keys is contiguous memory) just as fast as map.
parent
08f30966dd
commit
f6575323d6
|
@ -126,7 +126,7 @@ namespace gtsam {
|
||||||
* @param scatter A mapping from variable index to slot index in this HessianFactor
|
* @param scatter A mapping from variable index to slot index in this HessianFactor
|
||||||
* @param info The information matrix to be updated
|
* @param info The information matrix to be updated
|
||||||
*/
|
*/
|
||||||
virtual void updateHessian(const Scatter& scatter,
|
virtual void updateHessian(const FastVector<Key>& keys,
|
||||||
SymmetricBlockMatrix* info) const = 0;
|
SymmetricBlockMatrix* info) const = 0;
|
||||||
|
|
||||||
/// y += alpha * A'*A*x
|
/// y += alpha * A'*A*x
|
||||||
|
@ -141,6 +141,12 @@ namespace gtsam {
|
||||||
/// Gradient wrt a key at any values
|
/// Gradient wrt a key at any values
|
||||||
virtual Vector gradient(Key key, const VectorValues& x) const = 0;
|
virtual Vector gradient(Key key, const VectorValues& x) const = 0;
|
||||||
|
|
||||||
|
// Determine position of a given key
|
||||||
|
template <typename CONTAINER>
|
||||||
|
static DenseIndex Slot(const CONTAINER& keys, Key key) {
|
||||||
|
return std::find(keys.begin(), keys.end(), key) - keys.begin();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/** Serialization function */
|
/** Serialization function */
|
||||||
friend class boost::serialization::access;
|
friend class boost::serialization::access;
|
||||||
|
@ -150,7 +156,7 @@ namespace gtsam {
|
||||||
}
|
}
|
||||||
|
|
||||||
}; // GaussianFactor
|
}; // GaussianFactor
|
||||||
|
|
||||||
/// traits
|
/// traits
|
||||||
template<>
|
template<>
|
||||||
struct traits<GaussianFactor> : public Testable<GaussianFactor> {
|
struct traits<GaussianFactor> : public Testable<GaussianFactor> {
|
||||||
|
|
|
@ -248,7 +248,7 @@ HessianFactor::HessianFactor(const GaussianFactorGraph& factors,
|
||||||
gttic(update);
|
gttic(update);
|
||||||
BOOST_FOREACH(const GaussianFactor::shared_ptr& factor, factors)
|
BOOST_FOREACH(const GaussianFactor::shared_ptr& factor, factors)
|
||||||
if(factor)
|
if(factor)
|
||||||
factor->updateHessian(*scatter, &info_);
|
factor->updateHessian(keys_, &info_);
|
||||||
gttoc(update);
|
gttoc(update);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -346,15 +346,15 @@ double HessianFactor::error(const VectorValues& c) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ************************************************************************* */
|
/* ************************************************************************* */
|
||||||
void HessianFactor::updateHessian(const Scatter& scatter,
|
void HessianFactor::updateHessian(const FastVector<Key>& infoKeys,
|
||||||
SymmetricBlockMatrix* info) const {
|
SymmetricBlockMatrix* info) const {
|
||||||
gttic(updateHessian_HessianFactor);
|
gttic(updateHessian_HessianFactor);
|
||||||
// Apply updates to the upper triangle
|
// Apply updates to the upper triangle
|
||||||
DenseIndex n = size(), N = info->nBlocks()-1;
|
DenseIndex n = size(), N = info->nBlocks()-1;
|
||||||
for (DenseIndex j = 0; j <= n; ++j) {
|
for (DenseIndex j = 0; j <= n; ++j) {
|
||||||
const DenseIndex J = j==n ? N : scatter.slot(keys_[j]);
|
const DenseIndex J = (j==n) ? N : Slot(infoKeys, keys_[j]);
|
||||||
for (DenseIndex i = 0; i <= j; ++i) {
|
for (DenseIndex i = 0; i <= j; ++i) {
|
||||||
const DenseIndex I = i==n ? N : scatter.slot(keys_[i]);
|
const DenseIndex I = (i==n) ? N : Slot(infoKeys, keys_[i]);
|
||||||
(*info)(I, J) += info_(i, j);
|
(*info)(I, J) += info_(i, j);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -344,7 +344,7 @@ namespace gtsam {
|
||||||
* @param scatter A mapping from variable index to slot index in this HessianFactor
|
* @param scatter A mapping from variable index to slot index in this HessianFactor
|
||||||
* @param info The information matrix to be updated
|
* @param info The information matrix to be updated
|
||||||
*/
|
*/
|
||||||
void updateHessian(const Scatter& scatter, SymmetricBlockMatrix* info) const;
|
void updateHessian(const FastVector<Key>& keys, SymmetricBlockMatrix* info) const;
|
||||||
|
|
||||||
/** y += alpha * A'*A*x */
|
/** y += alpha * A'*A*x */
|
||||||
void multiplyHessianAdd(double alpha, const VectorValues& x, VectorValues& y) const;
|
void multiplyHessianAdd(double alpha, const VectorValues& x, VectorValues& y) const;
|
||||||
|
|
|
@ -498,7 +498,7 @@ map<Key, Matrix> JacobianFactor::hessianBlockDiagonal() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ************************************************************************* */
|
/* ************************************************************************* */
|
||||||
void JacobianFactor::updateHessian(const Scatter& scatter,
|
void JacobianFactor::updateHessian(const FastVector<Key>& infoKeys,
|
||||||
SymmetricBlockMatrix* info) const {
|
SymmetricBlockMatrix* info) const {
|
||||||
gttic(updateHessian_JacobianFactor);
|
gttic(updateHessian_JacobianFactor);
|
||||||
|
|
||||||
|
@ -512,7 +512,7 @@ void JacobianFactor::updateHessian(const Scatter& scatter,
|
||||||
"JacobianFactor::updateHessian: cannot update information with "
|
"JacobianFactor::updateHessian: cannot update information with "
|
||||||
"constrained noise model");
|
"constrained noise model");
|
||||||
JacobianFactor whitenedFactor = whiten();
|
JacobianFactor whitenedFactor = whiten();
|
||||||
whitenedFactor.updateHessian(scatter, info);
|
whitenedFactor.updateHessian(infoKeys, info);
|
||||||
} else {
|
} else {
|
||||||
// Ab_ is the augmented Jacobian matrix A, and we perform I += A'*A below
|
// Ab_ is the augmented Jacobian matrix A, and we perform I += A'*A below
|
||||||
DenseIndex n = Ab_.nBlocks() - 1, N = info->nBlocks() - 1;
|
DenseIndex n = Ab_.nBlocks() - 1, N = info->nBlocks() - 1;
|
||||||
|
@ -520,10 +520,10 @@ void JacobianFactor::updateHessian(const Scatter& scatter,
|
||||||
// Apply updates to the upper triangle
|
// Apply updates to the upper triangle
|
||||||
// Loop over blocks of A, including RHS with j==n
|
// Loop over blocks of A, including RHS with j==n
|
||||||
for (DenseIndex j = 0; j <= n; ++j) {
|
for (DenseIndex j = 0; j <= n; ++j) {
|
||||||
const DenseIndex J = j==n ? N : scatter.slot(keys_[j]);
|
const DenseIndex J = (j==n) ? N : Slot(infoKeys, keys_[j]);
|
||||||
// Fill off-diagonal blocks with Ai'*Aj
|
// Fill off-diagonal blocks with Ai'*Aj
|
||||||
for (DenseIndex i = 0; i < j; ++i) {
|
for (DenseIndex i = 0; i < j; ++i) {
|
||||||
const DenseIndex I = scatter.slot(keys_[i]);
|
const DenseIndex I = Slot(infoKeys, keys_[i]);
|
||||||
(*info)(I, J).knownOffDiagonal() += Ab_(i).transpose() * Ab_(j);
|
(*info)(I, J).knownOffDiagonal() += Ab_(i).transpose() * Ab_(j);
|
||||||
}
|
}
|
||||||
// Fill diagonal block with Aj'*Aj
|
// Fill diagonal block with Aj'*Aj
|
||||||
|
|
|
@ -278,7 +278,7 @@ namespace gtsam {
|
||||||
* @param scatter A mapping from variable index to slot index in this HessianFactor
|
* @param scatter A mapping from variable index to slot index in this HessianFactor
|
||||||
* @param info The information matrix to be updated
|
* @param info The information matrix to be updated
|
||||||
*/
|
*/
|
||||||
void updateHessian(const Scatter& scatter, SymmetricBlockMatrix* info) const;
|
void updateHessian(const FastVector<Key>& keys, SymmetricBlockMatrix* info) const;
|
||||||
|
|
||||||
/** Return A*x */
|
/** Return A*x */
|
||||||
Vector operator*(const VectorValues& x) const;
|
Vector operator*(const VectorValues& x) const;
|
||||||
|
|
|
@ -38,6 +38,16 @@ using namespace gtsam;
|
||||||
|
|
||||||
const double tol = 1e-5;
|
const double tol = 1e-5;
|
||||||
|
|
||||||
|
/* ************************************************************************* */
|
||||||
|
TEST(HessianFactor, Slot)
|
||||||
|
{
|
||||||
|
FastVector<Key> keys = list_of(2)(4)(1);
|
||||||
|
EXPECT_LONGS_EQUAL(0, GaussianFactor::Slot(keys,2));
|
||||||
|
EXPECT_LONGS_EQUAL(1, GaussianFactor::Slot(keys,4));
|
||||||
|
EXPECT_LONGS_EQUAL(2, GaussianFactor::Slot(keys,1));
|
||||||
|
EXPECT_LONGS_EQUAL(3, GaussianFactor::Slot(keys,5)); // does not exist
|
||||||
|
}
|
||||||
|
|
||||||
/* ************************************************************************* */
|
/* ************************************************************************* */
|
||||||
TEST(HessianFactor, emptyConstructor)
|
TEST(HessianFactor, emptyConstructor)
|
||||||
{
|
{
|
||||||
|
@ -302,15 +312,17 @@ TEST(HessianFactor, CombineAndEliminate)
|
||||||
gfg.add(0, A10, 1, A11, b1, noiseModel::Diagonal::Sigmas(s1, true));
|
gfg.add(0, A10, 1, A11, b1, noiseModel::Diagonal::Sigmas(s1, true));
|
||||||
gfg.add(1, A21, b2, noiseModel::Diagonal::Sigmas(s2, true));
|
gfg.add(1, A21, b2, noiseModel::Diagonal::Sigmas(s2, true));
|
||||||
|
|
||||||
Matrix zero3x3 = zeros(3,3);
|
Matrix93 A0; A0 << A10, Z_3x3, Z_3x3;
|
||||||
Matrix A0 = gtsam::stack(3, &A10, &zero3x3, &zero3x3);
|
Matrix93 A1; A1 << A11, A01, A21;
|
||||||
Matrix A1 = gtsam::stack(3, &A11, &A01, &A21);
|
|
||||||
Vector9 b; b << b1, b0, b2;
|
Vector9 b; b << b1, b0, b2;
|
||||||
Vector9 sigmas; sigmas << s1, s0, s2;
|
Vector9 sigmas; sigmas << s1, s0, s2;
|
||||||
|
|
||||||
// create a full, uneliminated version of the factor
|
// create a full, uneliminated version of the factor
|
||||||
JacobianFactor expectedFactor(0, A0, 1, A1, b, noiseModel::Diagonal::Sigmas(sigmas, true));
|
JacobianFactor expectedFactor(0, A0, 1, A1, b, noiseModel::Diagonal::Sigmas(sigmas, true));
|
||||||
|
|
||||||
|
// Make sure combining works
|
||||||
|
EXPECT(assert_equal(HessianFactor(expectedFactor), HessianFactor(gfg), 1e-6));
|
||||||
|
|
||||||
// perform elimination on jacobian
|
// perform elimination on jacobian
|
||||||
GaussianConditional::shared_ptr expectedConditional;
|
GaussianConditional::shared_ptr expectedConditional;
|
||||||
JacobianFactor::shared_ptr expectedRemainingFactor;
|
JacobianFactor::shared_ptr expectedRemainingFactor;
|
||||||
|
|
|
@ -149,7 +149,7 @@ namespace gtsam {
|
||||||
: JacobianFactor(i1, A1, i2, A2, b, model), AC_(A1), AL_(A2), b_(b) {}
|
: JacobianFactor(i1, A1, i2, A2, b, model), AC_(A1), AL_(A2), b_(b) {}
|
||||||
|
|
||||||
// Fixed-size matrix update
|
// Fixed-size matrix update
|
||||||
void updateHessian(const Scatter& scatter, SymmetricBlockMatrix* info) const {
|
void updateHessian(const FastVector<Key>& infoKeys, SymmetricBlockMatrix* info) const {
|
||||||
gttic(updateHessian_LinearizedFactor);
|
gttic(updateHessian_LinearizedFactor);
|
||||||
|
|
||||||
// Whiten the factor if it has a noise model
|
// Whiten the factor if it has a noise model
|
||||||
|
@ -160,15 +160,12 @@ namespace gtsam {
|
||||||
"JacobianFactor::updateHessian: cannot update information with "
|
"JacobianFactor::updateHessian: cannot update information with "
|
||||||
"constrained noise model");
|
"constrained noise model");
|
||||||
JacobianFactor whitenedFactor = whiten();
|
JacobianFactor whitenedFactor = whiten();
|
||||||
whitenedFactor.updateHessian(scatter, info);
|
whitenedFactor.updateHessian(infoKeys, info);
|
||||||
} else {
|
} else {
|
||||||
// N is number of variables in information matrix
|
|
||||||
DenseIndex N = info->nBlocks() - 1;
|
|
||||||
|
|
||||||
// First build an array of slots
|
// First build an array of slots
|
||||||
DenseIndex slotC = scatter.slot(keys_.front());
|
DenseIndex slotC = Slot(infoKeys, keys_.front());
|
||||||
DenseIndex slotL = scatter.slot(keys_.back());
|
DenseIndex slotL = Slot(infoKeys, keys_.back());
|
||||||
DenseIndex slotB = N;
|
DenseIndex slotB = info->nBlocks() - 1;
|
||||||
|
|
||||||
// We perform I += A'*A to the upper triangle
|
// We perform I += A'*A to the upper triangle
|
||||||
(*info)(slotC, slotC).knownOffDiagonal() += AC_.transpose() * AC_;
|
(*info)(slotC, slotC).knownOffDiagonal() += AC_.transpose() * AC_;
|
||||||
|
|
|
@ -115,7 +115,7 @@ public:
|
||||||
return D;
|
return D;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void updateHessian(const Scatter& scatter,
|
virtual void updateHessian(const FastVector<Key>& keys,
|
||||||
SymmetricBlockMatrix* info) const {
|
SymmetricBlockMatrix* info) const {
|
||||||
throw std::runtime_error(
|
throw std::runtime_error(
|
||||||
"RegularImplicitSchurFactor::updateHessian non implemented");
|
"RegularImplicitSchurFactor::updateHessian non implemented");
|
||||||
|
|
Loading…
Reference in New Issue