43 using Dims = std::vector<Eigen::Index>;
44 using Pairs = std::vector<std::pair<Eigen::Index, Matrix>>;
47 JacobianFactor::JacobianFactor() :
55 if (
const JacobianFactor* asJacobian = dynamic_cast<const JacobianFactor*>(&gf))
57 else if (
const HessianFactor* asHessian = dynamic_cast<const HessianFactor*>(&gf))
60 throw std::invalid_argument(
61 "In JacobianFactor(const GaussianFactor& rhs), rhs is neither a JacobianFactor nor a HessianFactor");
101 if (success || maxrank == factor.
rows() - 1) {
104 Matrix::Zero(maxrank,
Ab_.
matrix().cols());
117 std::tuple<FastVector<DenseIndex>,
DenseIndex, DenseIndex> _countDims(
121 #ifdef GTSAM_EXTRA_CONSISTENCY_CHECKS 129 for (
size_t jointVarpos = 0; jointVarpos < variableSlots.size();
131 const VariableSlots::const_iterator& slots = variableSlots[jointVarpos];
133 assert(slots->second.size() == factors.size());
135 bool foundVariable =
false;
136 for (
size_t sourceFactorI = 0; sourceFactorI < slots->second.size();
138 const size_t sourceVarpos = slots->second[sourceFactorI];
141 if (sourceFactor.
cols() > 1) {
142 foundVariable =
true;
143 DenseIndex vardim = sourceFactor.
getDim(
144 sourceFactor.
begin() + sourceVarpos);
146 #ifdef GTSAM_EXTRA_CONSISTENCY_CHECKS 148 varDims[jointVarpos] = vardim;
151 if(!(varDims[jointVarpos] == vardim)) {
152 std::stringstream
ss;
154 " has different dimensionality of " << vardim <<
" instead of " << varDims[jointVarpos];
155 throw std::runtime_error(ss.str());
160 varDims[jointVarpos] = vardim;
169 throw std::invalid_argument(
170 "Unable to determine dimensionality for all variables");
177 #if !defined(NDEBUG) && defined(GTSAM_EXTRA_CONSISTENCY_CHECKS) 178 for(DenseIndex
d: varDims) {
189 gttic(Convert_to_Jacobians);
191 jacobians.reserve(factors.
size());
196 jacobians.push_back(jf);
198 jacobians.push_back(std::make_shared<JacobianFactor>(*factor));
214 const auto [varDims,
m,
n] = _countDims(jacobians, orderedSlots);
223 [](
const VariableSlots::const_iterator& it) {
return it->first;});
228 size_t combinedSlot = 0;
229 for(VariableSlots::const_iterator varslot: orderedSlots) {
233 for (
size_t factorI = 0; factorI < jacobians.size(); ++factorI) {
235 const size_t sourceSlot = varslot->second[factorI];
236 const DenseIndex sourceRows = jacobians[factorI]->rows();
237 if (sourceRows > 0) {
239 destSlot.middleRows(nextRow, sourceRows));
242 destBlock = jacobians[factorI]->getA(
243 jacobians[factorI]->
begin() + sourceSlot);
246 nextRow += sourceRows;
255 bool anyConstrained =
false;
256 std::optional<Vector>
sigmas;
259 for (
size_t factorI = 0; factorI < jacobians.size(); ++factorI) {
260 const DenseIndex sourceRows = jacobians[factorI]->rows();
261 if (sourceRows > 0) {
262 this->
getb().segment(nextRow, sourceRows) = jacobians[factorI]->getb();
266 sigmas = Vector::Constant(m, 1.0);
267 sigmas->segment(nextRow, sourceRows) =
268 jacobians[factorI]->get_model()->sigmas();
270 anyConstrained =
true;
272 nextRow += sourceRows;
278 this->
setModel(anyConstrained, *sigmas);
291 orderedSlots.reserve(variableSlots.size());
295 size_t nOrderingSlotsUsed = 0;
296 orderedSlots.resize(ordering.size());
298 for (VariableSlots::const_iterator item = variableSlots.begin();
299 item != variableSlots.end(); ++item) {
301 inverseOrdering.find(item->first);
302 if (orderingPosition == inverseOrdering.end()) {
303 unorderedSlots.push_back(item);
305 orderedSlots[orderingPosition->second] = item;
306 ++nOrderingSlotsUsed;
309 if (nOrderingSlotsUsed != ordering.size())
310 throw std::invalid_argument(
311 "The ordering provided to the JacobianFactor combine constructor\n" 312 "contained extra variables that did not appear in the factors to combine.");
314 for(VariableSlots::const_iterator item: unorderedSlots) {
315 orderedSlots.push_back(item);
325 gttic(JacobianFactor_combine_constructor);
336 orderedSlots.reserve(variableSlots.size());
340 for (VariableSlots::const_iterator item = variableSlots.begin();
341 item != variableSlots.end(); ++item)
342 orderedSlots.push_back(item);
351 gttic(JacobianFactor_combine_constructor);
361 orderedSlots.reserve(variableSlots.size());
365 for (VariableSlots::const_iterator item = variableSlots.begin();
366 item != variableSlots.end(); ++item)
367 orderedSlots.push_back(item);
376 gttic(JacobianFactor_combine_constructor);
393 gttic(JacobianFactor_combine_constructor);
413 model_->print(
" Noise model: ");
415 cout <<
" No noise model" << endl;
421 static const bool verbose =
false;
422 if (!dynamic_cast<const JacobianFactor*>(&f_)) {
424 cout <<
"JacobianFactor::equals: Incorrect type" << endl;
432 cout <<
"JacobianFactor::equals: keys do not match" << endl;
439 cout <<
"JacobianFactor::equals: noise model mismatch" << endl;
444 cout <<
"JacobianFactor::equals: noise modesl are not equal" << endl;
451 cout <<
"JacobianFactor::equals: augmented size mismatch" << endl;
462 cout <<
"JacobianFactor::equals: matrix mismatch at row " <<
row << endl;
489 if (
model_)
return 0.5 *
model_->squaredMahalanobisDistance(e);
490 return 0.5 * e.dot(e);
497 model_->WhitenInPlace(AbWhitened);
498 return AbWhitened.transpose() * AbWhitened;
508 model_->WhitenInPlace(AWhitened);
509 return AWhitened.transpose() * AWhitened;
511 return this->
getA().transpose() * this->
getA();
524 for (
size_t k = 0; k < nj; ++k) {
527 Vector column_k_copy = column_k;
528 model_->whitenInPlace(column_k_copy);
530 dj(k) +=
dot(column_k_copy, column_k_copy);
532 dj(k) =
dot(column_k_copy, column_k_copy);
535 dj(k) +=
dot(column_k, column_k);
537 dj(k) =
dot(column_k, column_k);
546 throw std::runtime_error(
"JacobianFactor::hessianDiagonal raw memory access is allowed for Regular Factors only");
551 map<Key, Matrix> blocks;
557 blocks.emplace(j, Aj.transpose() * Aj);
565 gttic(updateHessian_JacobianFactor);
567 if (
rows() == 0)
return;
571 if (model && !model->isUnit()) {
572 if (model->isConstrained())
573 throw invalid_argument(
574 "JacobianFactor::updateHessian: cannot update information with " 575 "constrained noise model");
584 vector<DenseIndex> slots(n+1);
621 E.noalias() = alpha *
e;
630 it->second.noalias() +=
Ab_(
pos).transpose() *
E;
654 const std::vector<size_t>& accumulatedDims)
const {
669 size_t dim = accumulatedDims[keys_[
pos] + 1] -
offset;
670 Ax +=
Ab_(
pos) * ConstVectorMap(x + offset, dim);
674 model_->whitenInPlace(Ax);
675 model_->whitenInPlace(Ax);
684 size_t dim = accumulatedDims[keys_[
pos] + 1] -
offset;
685 VectorMap(y + offset, dim) +=
Ab_(
pos).transpose() * Ax;
703 throw std::runtime_error(
"JacobianFactor::gradientAtZero raw memory access is allowed for Regular Factors only");
718 model_->WhitenSystem(result.first, result.second);
726 return make_pair(
A, b);
733 model_->WhitenInPlace(Ab);
769 if ((
size_t) sigmas.size() != this->
rows())
778 std::pair<GaussianConditional::shared_ptr, JacobianFactor::shared_ptr>
EliminateQR(
784 jointFactor = std::make_shared<JacobianFactor>(
factors,
keys);
785 }
catch (std::invalid_argument&) {
787 "EliminateQR was called with a request to eliminate variables that are not\n" 788 "involved in the provided factors.");
795 if (jointFactor->model_) {
799 jointFactor->model_ = jointFactor->model_->QR(Ab.
matrix());
807 size_t maxRank =
min(m,
n);
812 GaussianConditional::shared_ptr conditional =
813 jointFactor->splitConditional(keys.size());
815 return make_pair(conditional, jointFactor);
820 gttic(JacobianFactor_splitConditional);
823 throw std::invalid_argument(
824 "JacobianFactor::splitConditional cannot be given a nullptr noise model");
827 if (nrFrontals >
size()) {
828 throw std::invalid_argument(
829 "JacobianFactor::splitConditional was requested to split off more variables than exist.");
844 conditionalNoiseModel =
846 GaussianConditional::shared_ptr conditional =
847 std::make_shared<GaussianConditional>(
Base::keys_, nrFrontals,
Ab_, conditionalNoiseModel);
850 std::min(Ab_.cols(), originalRowEnd) - Ab_.rowStart() - frontalDim;
852 Ab_.rowStart() += frontalDim;
853 Ab_.rowEnd() = Ab_.rowStart() + remainingRows;
854 Ab_.firstBlock() += nrFrontals;
859 if (
model_->isConstrained())
const gtsam::Symbol key('X', 0)
void transposeMultiplyAdd(double alpha, const Vector &e, VectorValues &x) const
std::string formatMatrixIndented(const std::string &label, const Matrix &matrix, bool makeVectorHorizontal)
bool empty() const
Whether the factor is empty (involves zero variables).
JacobianFactor whiten() const
std::pair< std::shared_ptr< GaussianConditional >, shared_ptr > eliminate(const Ordering &keys)
std::vector< Eigen::Index > Dims
std::shared_ptr< This > shared_ptr
shared_ptr to this class
DenseIndex cols() const
Column size.
const MATRIX::ConstRowXpr row(const MATRIX &A, size_t j)
Vector operator*(const VectorValues &x) const
void inplace_QR(Matrix &A)
friend GTSAM_EXPORT std::pair< std::shared_ptr< GaussianConditional >, shared_ptr > EliminateQR(const GaussianFactorGraph &factors, const Ordering &keys)
double dot(const V1 &a, const V2 &b)
double error(const VectorValues &c) const override
Matrix augmentedInformation() const override
DenseIndex nBlocks() const
Block count.
GaussianFactor::shared_ptr negate() const override
noiseModel::Diagonal::shared_ptr model
void multiplyHessianAdd(double alpha, const VectorValues &x, VectorValues &y) const override
void updateHessian(const KeyVector &keys, SymmetricBlockMatrix *info) const override
A matrix or vector expression mapping an existing array of data.
void setModel(bool anyConstrained, const Vector &sigmas)
void hessianDiagonalAdd(VectorValues &d) const override
Add the current diagonal to a VectorValues instance.
DenseIndex rows() const
Row size.
noiseModel::Diagonal::shared_ptr model_
std::vector< Eigen::Index > Dims
std::vector< T, typename internal::FastDefaultVectorAllocator< T >::type > FastVector
set noclip points set clip one set noclip two set bar set border lt lw set xdata set ydata set zdata set x2data set y2data set boxwidth set dummy y set format x g set format y g set format x2 g set format y2 g set format z g set angles radians set nogrid set key title set key left top Right noreverse box linetype linewidth samplen spacing width set nolabel set noarrow set nologscale set logscale x set set pointsize set encoding default set nopolar set noparametric set set set set surface set nocontour set clabel set mapping cartesian set nohidden3d set cntrparam order set cntrparam linear set cntrparam levels auto set cntrparam points set size set set xzeroaxis lt lw set x2zeroaxis lt lw set yzeroaxis lt lw set y2zeroaxis lt lw set tics in set ticslevel set tics set mxtics default set mytics default set mx2tics default set my2tics default set xtics border mirror norotate autofreq set ytics border mirror norotate autofreq set ztics border nomirror norotate autofreq set nox2tics set noy2tics set timestamp bottom norotate offset
const GaussianFactorGraph factors
const Matrix & matrix() const
KeyVector keys_
The keys involved in this factor.
Matrix information() const override
iterator end()
Iterator over variables.
Matrix< SCALARA, Dynamic, Dynamic, opt_A > A
std::shared_ptr< GaussianConditional > splitConditional(size_t nrFrontals)
Block< Derived, Dynamic, internal::traits< Derived >::ColsAtCompileTime, IsRowMajor > RowsBlockXpr
NonlinearFactorGraph graph
Vector gradient(Key key, const VectorValues &x) const override
Compute the gradient wrt a key at any values.
static const KeyFormatter DefaultKeyFormatter
Matrix augmentedJacobian() const override
static enum @1107 ordering
ptrdiff_t DenseIndex
The index type for Eigen objects.
void g(const string &key, int i)
std::pair< Matrix, Vector > jacobianUnweighted() const
Returns (dense) A,b pair associated with factor, does not bake in weights.
Vector unweighted_error(const VectorValues &c) const
const KeyFormatter & formatter
static shared_ptr Create(size_t dim)
pair< size_t, bool > choleskyCareful(Matrix &ATA, int order)
VariableSlots describes the structure of a combined factor in terms of where each block comes from in...
std::pair< VectorValues::iterator, bool > emplace(Key j, Args &&... args)
bool isConstrained() const
const_iterator end() const
std::pair< Matrix, Vector > jacobian() const override
Returns (dense) A,b pair associated with factor, bakes in the weights.
VectorValues hessianDiagonal() const
Return the diagonal of the Hessian for this factor.
const Eigen::IOFormat & matlabFormat()
void add(const GaussianFactor &factor)
Eigen::SelfAdjointView< constBlock, Eigen::Upper > selfadjointView(DenseIndex I, DenseIndex J) const
Return the square sub-matrix that contains blocks(i:j, i:j).
DenseIndex nBlocks() const
Block count.
static shared_ptr MixedSigmas(const Vector &mu, const Vector &sigmas)
const DenseIndex & rowEnd() const
Vector error_vector(const VectorValues &c) const
void print(const std::string &s="", const KeyFormatter &formatter=DefaultKeyFormatter) const override
print with optional string
const constBVector getb() const
bool equals(const GaussianFactor &lf, double tol=1e-9) const override
assert equality up to a tolerance
void fillTerms(const TERMS &terms, const Vector &b, const SharedDiagonal &noiseModel)
Internal function to fill blocks and set dimensions.
Point2(* f)(const Point3 &, OptionalJacobian< 2, 3 >)
Array< double, 1, 3 > e(1./3., 0.5, 2.)
DenseIndex getDim(const_iterator variable) const override
Conditional Gaussian Base class.
Linear Factor Graph where all factors are Gaussians.
static GTSAM_EXPORT const size_t Empty
EIGEN_DONT_INLINE void transform(const Transformation &t, Data &data)
JacobiRotation< float > J
std::shared_ptr< This > shared_ptr
shared_ptr to this class
std::function< std::string(Key)> KeyFormatter
Typedef for a function to format a key, i.e. to convert it to a string.
GaussianFactor::shared_ptr negate() const override
std::shared_ptr< This > shared_ptr
shared_ptr to this class
Maps global variable indices to slot indices.
Exceptions that may be thrown by linear solver components.
static std::stringstream ss
bool equal_with_abs_tol(const Eigen::DenseBase< MATRIX > &A, const Eigen::DenseBase< MATRIX > &B, double tol=1e-9)
Block range(DenseIndex startBlock, DenseIndex endBlock)
A matrix or vector expression mapping an existing expression.
noiseModel::Diagonal::shared_ptr SharedDiagonal
VectorValues gradientAtZero() const override
A'*b for Jacobian.
Matrix augmentedJacobianUnweighted() const
A thin wrapper around std::map that uses boost's fast_pool_allocator.
Expression of a fixed-size or dynamic-size block.
static shared_ptr Sigmas(const Vector &sigmas, bool smart=true)
A Gaussian factor using the canonical parameters (information form)
const KeyVector & keys() const
Access the factor's involved variable keys.
void updateOffDiagonalBlock(DenseIndex I, DenseIndex J, const XprType &xpr)
FastVector< VariableSlots::const_iterator > orderedSlotsHelper(const Ordering &ordering, const VariableSlots &variableSlots)
Eigen::SelfAdjointView< Block, Eigen::Upper > diagonalBlock(DenseIndex J)
Return the J'th diagonal block as a self adjoint view.
KeyVector::const_iterator const_iterator
Const iterator over keys.
Vector gradient(Key key, const VectorValues &x) const override
FastVector< Key > KeyVector
Define collection type once and for all - also used in wrappers.
const_iterator begin() const
FastMap< Key, size_t > invert() const
Invert (not reverse) the ordering - returns a map from key to order position.
set noclip points set clip one set noclip two set bar set border lt lw set xdata set ydata set zdata set x2data set y2data set boxwidth set dummy x
const SymmetricBlockMatrix & info() const
Return underlying information matrix.
static DenseIndex Slot(const CONTAINER &keys, Key key)
const DenseIndex & rowStart() const
std::uint64_t Key
Integer nonlinear key type.
const SharedDiagonal & get_model() const
void JacobianFactorHelper(const GaussianFactorGraph &graph, const FastVector< VariableSlots::const_iterator > &orderedSlots)
std::map< Key, Matrix > hessianBlockDiagonal() const override
Return the block diagonal of the Hessian for this factor.
Efficient incomplete Cholesky on rank-deficient matrices, todo: constrained Cholesky.
std::vector< std::pair< Eigen::Index, Matrix > > Pairs