22#include <gtsam/linear/internal/FixedJacobianFactorOps.h>
35template <
size_t I,
int Default,
int... Dimensions>
38template <
size_t I,
int Default,
int First,
int... Rest>
42template <
int Default,
int First,
int... Rest>
44 : std::integral_constant<int, First> {};
47template <
typename OutputVec,
typename... ValueTypes>
49 inline constexpr static size_t arity =
sizeof...(ValueTypes);
51 inline constexpr static std::array<int, arity + 1> dimensions{
54 inline constexpr static int N = dimensions.at(I + 1);
55 inline constexpr static bool allFixed =
56 M != Eigen::Dynamic &&
61template <
typename Dimensions,
size_t... Is>
63 std::index_sequence<Is...>) {
64 return ((jacobians[Is].rows() == Dimensions::M &&
65 jacobians[Is].cols() == Dimensions::template N<Is>) &&
75template <
int M,
int... Ns>
78 inline constexpr static size_t arity =
sizeof...(Ns);
81 inline constexpr static std::array<int, arity>
dimensions{Ns...};
87 inline constexpr static std::array<DenseIndex, arity + 1> offsets = [] {
88 std::array<DenseIndex, arity + 1> result{};
89 for (
size_t i = 0; i <
arity; ++i) {
95 static VerticalBlockMatrix augmentedMatrix(
96 const std::vector<Matrix>& jacobians,
const Vector& b) {
97 if (jacobians.size() !=
arity || b.size() != M) {
98 throw std::invalid_argument(
99 "FixedJacobianFactor: error or Jacobian count mismatch");
102 const std::array<size_t, arity> blockDimensions{
static_cast<size_t>(Ns)...};
103 VerticalBlockMatrix result(blockDimensions, M,
true);
104 for (
size_t i = 0; i <
arity; ++i) {
106 throw std::invalid_argument(
107 "FixedJacobianFactor: Jacobian dimension mismatch");
109 result(i) = jacobians[i];
116 internal::FixedJacobianBlock<M, N<I>> block()
const {
117 return internal::FixedJacobianBlock<M, N<I>>(Ab_.matrix(), 0, offsets[I]);
120 template <
size_t... Is>
121 void hessianDiagonalAdd(VectorValues& diagonal,
122 std::index_sequence<Is...>)
const {
123 (internal::accumulateHessianDiagonal<M, N<Is>>(
keys_[Is], block<Is>(),
128 template <
size_t... Is>
129 void accumulateResidual(
const VectorValues& values,
130 Eigen::Matrix<double, M, 1>& residual,
131 std::index_sequence<Is...>)
const {
132 (internal::accumulateResidual<M, N<Is>>(block<Is>(), values.at(
keys_[Is]),
137 template <
size_t... Is>
138 std::array<DenseIndex, arity> slots(
const KeyVector& infoKeys,
139 std::index_sequence<Is...>)
const {
140 return {{Slot(infoKeys,
keys_[Is])...}};
143 template <
size_t I,
size_t... Js>
144 void updateCrossHessiansFor(
const std::array<DenseIndex, arity>& factorSlots,
145 SymmetricBlockMatrix* info,
146 std::index_sequence<Js...>)
const {
147 (internal::updateCrossHessian<M, N<I>, N<I + Js + 1>>(
148 factorSlots[I], block<I>(), factorSlots[I + Js + 1],
149 block<I + Js + 1>(), info),
153 template <
size_t... Is>
154 void updateCrossHessians(
const std::array<DenseIndex, arity>& factorSlots,
155 SymmetricBlockMatrix* info,
156 std::index_sequence<Is...>)
const {
157 (updateCrossHessiansFor<Is>(factorSlots, info,
158 std::make_index_sequence<arity - Is - 1>{}),
162 template <
size_t... Is>
163 void updateJacobianHessians(
const std::array<DenseIndex, arity>& factorSlots,
165 const internal::FixedJacobianBlock<M, 1>& b,
166 SymmetricBlockMatrix* info,
167 std::index_sequence<Is...>)
const {
168 (internal::updateJacobianHessian<M, N<Is>>(factorSlots[Is], block<Is>(),
173 template <
size_t I,
typename OwnsColumn,
size_t... Js>
174 void updateOwnedCrossHessiansFor(
175 const std::array<DenseIndex, arity>& factorSlots,
176 const OwnsColumn& ownsColumn, SymmetricBlockMatrix* info,
177 std::index_sequence<Js...>)
const {
178 ((ownsColumn(std::max(factorSlots[I], factorSlots[I + Js + 1]))
180 internal::updateCrossHessian<M, N<I>, N<I + Js + 1>>(
181 factorSlots[I], block<I>(), factorSlots[I + Js + 1],
182 block<I + Js + 1>(), info))
183 : static_cast<void>(0)),
187 template <
typename OwnsColumn,
size_t... Is>
188 void updateOwnedCrossHessians(
189 const std::array<DenseIndex, arity>& factorSlots,
190 const OwnsColumn& ownsColumn, SymmetricBlockMatrix* info,
191 std::index_sequence<Is...>)
const {
192 (updateOwnedCrossHessiansFor<Is>(
193 factorSlots, ownsColumn, info,
194 std::make_index_sequence<arity - Is - 1>{}),
198 template <
typename OwnsColumn,
size_t... Is>
199 void updateOwnedSelfAndRhsHessians(
200 const std::array<DenseIndex, arity>& factorSlots,
DenseIndex slotB,
201 const internal::FixedJacobianBlock<M, 1>& b,
const OwnsColumn& ownsColumn,
202 SymmetricBlockMatrix* info, std::index_sequence<Is...>)
const {
203 ((ownsColumn(factorSlots[Is])
204 ?
static_cast<void>(internal::updateSelfHessian<M, N<Is>>(
205 factorSlots[Is], block<Is>(), info))
206 : static_cast<void>(0)),
208 ((ownsColumn(std::max(factorSlots[Is], slotB))
209 ?
static_cast<void>(internal::updateCrossHessian<M, N<Is>, 1>(
210 factorSlots[Is], block<Is>(), slotB, b, info))
211 : static_cast<void>(0)),
216 static_assert(
arity > 0 && M > 0 && ((Ns > 0) && ...),
217 "Fixed factor arity and dimensions must be positive");
226 const std::vector<Matrix>& jacobians,
const Vector& b,
227 const SharedDiagonal& model = SharedDiagonal())
232 const SharedDiagonal& model =
get_model();
233 if (model && !model->isUnit()) {
237 hessianDiagonalAdd(diagonal, std::make_index_sequence<arity>{});
242 double* newError =
nullptr)
const override {
243 const SharedDiagonal& model =
get_model();
244 if (model && !model->isUnit()) {
248 const internal::FixedJacobianBlock<M, 1> b(Ab_.matrix(), 0, offsets[
arity]);
249 Eigen::Matrix<double, M, 1>
error = -b;
250 accumulateResidual(values,
error, std::make_index_sequence<arity>{});
252 const double oldValue = 0.5 * b.squaredNorm();
253 const double newValue = 0.5 *
error.squaredNorm();
254 if (oldError) *oldError = oldValue;
255 if (newError) *newError = newValue;
256 return oldValue - newValue;
262 gttic(updateHessian_FixedJacobianFactor);
263 const SharedDiagonal& model =
get_model();
264 if (model && !model->isUnit()) {
265 if (model->isConstrained()) {
266 throw std::invalid_argument(
267 "FixedJacobianFactor::updateHessian: cannot update information "
268 "with constrained noise model");
270 std::vector<Matrix> whitenedJacobians;
271 whitenedJacobians.reserve(
arity);
272 for (
auto variable =
begin(); variable !=
end(); ++variable) {
273 whitenedJacobians.push_back(model->Whiten(
getA(variable)));
276 model->whiten(
getb()));
281 const auto factorSlots = slots(infoKeys, std::make_index_sequence<arity>{});
283 const internal::FixedJacobianBlock<M, 1> b(Ab_.matrix(), 0, offsets[
arity]);
284 updateJacobianHessians(factorSlots, slotB, b, info,
285 std::make_index_sequence<arity>{});
286 if constexpr (
arity > 1) {
287 updateCrossHessians(factorSlots, info,
288 std::make_index_sequence<arity - 1>{});
290 internal::updateSelfHessian<M, 1>(slotB, b, info);
296 gttic(updateHessianRange_FixedJacobianFactor);
297 const SharedDiagonal& model =
get_model();
298 if (model && !model->isUnit()) {
303 const auto factorSlots = slots(infoKeys, std::make_index_sequence<arity>{});
306 const internal::FixedJacobianBlock<M, 1> b(Ab_.matrix(), 0, offsets[
arity]);
307 updateOwnedSelfAndRhsHessians(factorSlots, slotB, b, ownsColumn, info,
308 std::make_index_sequence<arity>{});
309 if constexpr (
arity > 1) {
310 updateOwnedCrossHessians(factorSlots, ownsColumn, info,
311 std::make_index_sequence<arity - 1>{});
313 if (ownsColumn(slotB)) {
314 internal::updateSelfHessian<M, 1>(slotB, b, info);
319template <
int M,
int... Ns>
321 :
Testable<FixedJacobianFactor<M, Ns...>> {};
326template <
int M,
int... Ns>
330 M != Eigen::Dynamic && ((Ns != Eigen::Dynamic) && ...);
333 static std::shared_ptr<GaussianFactor>
create(
334 const KeyVector& keys,
const std::vector<Matrix>& jacobians,
335 const Vector& b,
const SharedDiagonal& model) {
Base class and basic functions for Manifold types.
bool dimensionsMatch(const std::vector< Matrix > &jacobians, std::index_sequence< Is... >)
Check dynamic Jacobian blocks against their compile-time dimensions.
Definition FixedJacobianFactor.h:62
Global functions in a separate testing namespace.
Definition chartTesting.h:28
ptrdiff_t DenseIndex
The index type for Eigen objects.
Definition types.h:49
FastVector< Key > KeyVector
Define collection type once and for all - also used in wrappers.
Definition Key.h:91
A manifold defines a space in which there is a notion of a linear tangent space that can be centered ...
Definition Group.h:37
Half-open range of physical upper-triangular block columns.
Definition SymmetricBlockMatrix.h:48
This class stores a dense matrix and allows it to be accessed as a collection of blocks.
Definition SymmetricBlockMatrix.h:80
DenseIndex nBlocks() const
Block count.
Definition SymmetricBlockMatrix.h:162
A helper that implements the traits interface for GTSAM types.
Definition Testable.h:152
const KeyVector & keys() const
Access the factor's involved variable keys.
Definition Factor.h:143
KeyVector keys_
The keys involved in this factor.
Definition Factor.h:88
const_iterator begin() const
Iterator at beginning of involved variable keys.
Definition Factor.h:146
const_iterator end() const
Iterator at end of involved variable keys.
Definition Factor.h:149
Return the element at I in a compile-time integer pack, or Default.
Definition FixedJacobianFactor.h:36
Compile-time residual and variable dimensions for a factor of any arity.
Definition FixedJacobianFactor.h:48
A JacobianFactor whose residual and variable dimensions are known at compile time.
Definition FixedJacobianFactor.h:76
FixedJacobianFactor(const KeyVector &keys, const std::vector< Matrix > &jacobians, const Vector &b, const SharedDiagonal &model=SharedDiagonal())
Construct from keys, Jacobian blocks, and a right-hand side.
Definition FixedJacobianFactor.h:225
static constexpr std::array< int, arity > dimensions
Compile-time dimension of each variable block.
Definition FixedJacobianFactor.h:81
void updateHessian(const KeyVector &infoKeys, SymmetricBlockMatrix *info) const override
Update the complete augmented Hessian using fixed-size products.
Definition FixedJacobianFactor.h:260
void hessianDiagonalAdd(VectorValues &diagonal) const override
Add the Hessian diagonal using fixed-size matrix operations.
Definition FixedJacobianFactor.h:231
void updateHessian(const KeyVector &infoKeys, SymmetricBlockMatrix *info, DenseIndex beginCol, DenseIndex endCol) const override
Update selected augmented-Hessian block columns.
Definition FixedJacobianFactor.h:294
double deltaError(const VectorValues &values, double *oldError=nullptr, double *newError=nullptr) const override
Compute the error change using a fixed-size residual.
Definition FixedJacobianFactor.h:241
static constexpr size_t arity
Number of variable blocks in the factor.
Definition FixedJacobianFactor.h:78
Construct the fixed-size Jacobian factor for a dimension pack.
Definition FixedJacobianFactor.h:327
static constexpr bool available
Whether every factor dimension is fixed at compile time.
Definition FixedJacobianFactor.h:329
static std::shared_ptr< GaussianFactor > create(const KeyVector &keys, const std::vector< Matrix > &jacobians, const Vector &b, const SharedDiagonal &model)
Construct a fixed-size factor behind the GaussianFactor interface.
Definition FixedJacobianFactor.h:333
const constBVector getb() const
Get a view of the r.h.s.
Definition JacobianFactor.h:344
const SharedDiagonal & get_model() const
get a copy of model
Definition JacobianFactor.h:338
JacobianFactor(const GaussianFactor &gf)
Convert from other GaussianFactor.
Definition JacobianFactor.cpp:51
void hessianDiagonalAdd(VectorValues &d) const override
Add the current diagonal to a VectorValues instance.
Definition JacobianFactor.cpp:625
double deltaError(const VectorValues &c, double *oldError=nullptr, double *newError=nullptr) const override
Compute the change in error from zero to c, optionally returning the old and new errors.
Definition JacobianFactor.cpp:579
double error(const VectorValues &c) const override
0.5*(A*x-b)'D(A*x-b).
Definition JacobianFactor.cpp:570
size_t rows() const
return the number of rows in the corresponding linear system
Definition JacobianFactor.h:330
size_t cols() const
return the number of columns in the corresponding linear system
Definition JacobianFactor.h:335
void updateHessian(const KeyVector &keys, SymmetricBlockMatrix *info) const override
Update an information matrix by adding the information corresponding to this factor (used internally ...
Definition JacobianFactor.cpp:673
constABlock getA(const_iterator variable) const
Get a view of the A matrix for the variable pointed to by the given key iterator.
Definition JacobianFactor.h:347
VectorValues represents a collection of vector-valued variables associated each with a unique integer...
Definition VectorValues.h:73