gtsam
Loading...
Searching...
No Matches
WnoaInterpFactor.h
Go to the documentation of this file.
1/* ----------------------------------------------------------------------------
2
3 * GTSAM Copyright 2010, Georgia Tech Research Corporation,
4 * Atlanta, Georgia 30332-0415
5 * All Rights Reserved
6 * Authors: Frank Dellaert, et al. (see THANKS for the full author list)
7
8 * See LICENSE for the license information
9
10 * -------------------------------------------------------------------------- */
11
20
21#pragma once
22
23#include <gtsam/base/Lie.h>
24#include <gtsam/base/Testable.h>
25#include <gtsam/base/VectorSpace.h>
26#include <gtsam/base/timing.h>
32#include <gtsam/inference/Key.h>
37
38#include <array>
39#include <stdexcept>
40#include <unordered_set>
41#include <utility>
42#include <vector>
43
44namespace gtsam {
45
91template <class PoseType>
93 private:
94 using Base = NoiseModelFactor;
95 using This = WnoaInterpFactor<PoseType>;
96 using VelocityType = typename gtsam::traits<PoseType>::TangentVector;
97 static constexpr int dim = traits<PoseType>::dimension;
98
99 // Convenient matrices
100 using Matrix2N = Eigen::Matrix<double, 2 * dim, 2 * dim>;
101 using MatrixN = Eigen::Matrix<double, dim, dim>;
102 using LambdaPsiMats = typename Interpolator<PoseType>::LambdaPsiMats;
103
104 // Tell the compiler to import the base class's version of error
105 // Note: this is required because we don't define error( const HybridValues& )
106 // in this class, and without this line, the base class's error(const
107 // HybridValues&) is hidden by the error(const Values&, OptionalMatrixVecType)
108 // defined in this class.
109 using Base::error;
110
111 // Inner factor that is called on interpolated values
112 const NoiseModelFactor::shared_ptr inner_factor_;
113 // Interpolator object for the given PoseType
114 const Interpolator<PoseType> interpolator_;
115 // disable noise model updates
116 const bool fixed_noise_model_;
117 // map keys to interpolated state
118 std::unordered_map<Key, StateData> key_to_interp_;
119 // map interpolated state to border states.
120 std::unordered_map<StateData, std::pair<StateData, StateData>>
121 interp_to_borders_;
122 // map outer key to outer key index (for Jacobians)
123 std::unordered_map<Key, int> outer_key_to_index_;
124 // map of precomputed matrices for interpolation, keyed by StateData
125 std::unordered_map<StateData, std::shared_ptr<LambdaPsiMats>>
126 lambda_psi_pre_comp_;
127
128 // Cache inner key -> index mapping to avoid rebuilding in noise model calc
129 std::unordered_map<Key, int> inner_key_to_index_;
130
131 // This struct contains the indices of the contributing outer keys as well as
132 // flags for whether the inner key is interpolated or not. Keeps track of
133 // which estimated states contribute to a given interpolated key, and the
134 // corresponding Jacobian blocks for efficient linearization.
135 struct InnerKeyMapping {
136 bool isInterpolated = false;
137 // For non-interpolated keys
138 int directOuterIndex = -1;
139 // For interpolated keys: cached outer indices and keys
140 int indexPoseLeft = -1, indexVelLeft = -1, indexPoseRight = -1,
141 indexVelRight = -1;
142 Key keyPoseLeft = 0, keyVelLeft = 0, keyPoseRight = 0, keyVelRight = 0;
143 };
144 std::vector<InnerKeyMapping> inner_key_mappings_;
145
146 public:
161
166 std::unordered_map<Key, std::array<Matrix, 4>> jacobians;
167
169 std::unordered_map<StateData, Matrix2N> condCovs;
170 };
171
192 const std::set<StateData> estimated_states,
193 const std::set<StateData> interp_states,
194 const Eigen::Matrix<double, dim, 1> q_psd_diag,
195 const bool fixed_noise_model = false,
196 const bool precomp_interp_mats = true)
197 : Base(inner_factor->noiseModel()),
198 inner_factor_(inner_factor),
199 interpolator_(q_psd_diag),
200 fixed_noise_model_(fixed_noise_model) {
201 // PROCESS INTERPOLATED STATES
202 // loop through interpolated states
203 for (const StateData& state : interp_states) {
204 // search for estimated state that upper bound current interpolated state
205 // Note: lower_bound finds the least upper bound using time-based
206 // comparator of StateData. We can use it to find the right border state
207 // for interpolation.
208 auto iter_est_state = estimated_states.lower_bound(state);
209 // Check if right border state is out of bounds (i.e., interp time is
210 // outside the range of estimated times)
211 if (iter_est_state == estimated_states.begin()) {
212 throw std::runtime_error(
213 "Interpolated state time is before all estimated state times");
214 } else if (iter_est_state == estimated_states.end()) {
215 throw std::runtime_error(
216 "Interpolated state time is after all estimated state times");
217 } else {
218 // decrement iterator (points to left border state)
219 iter_est_state--;
220 // map interpolated state to borderstates
221 interp_to_borders_[state] =
222 std::pair(*iter_est_state, *std::next(iter_est_state));
223 // Keep track of the inner keys corresponding to a given interpolated
224 // state for easy lookup when building outer keys and mapping jacobians
225 // later
226 key_to_interp_[state.pose] = state;
227 key_to_interp_[state.velocity] = state;
228 }
229 // Precompute Lambda and Psi WNOA interpolation matrices
230 if (precomp_interp_mats) {
231 lambda_psi_pre_comp_[state] =
232 std::make_shared<LambdaPsiMats>(interpolator_.getLambdaPsi(
233 interp_to_borders_[state].first.time,
234 interp_to_borders_[state].second.time, state.time));
235 } else {
236 lambda_psi_pre_comp_[state] = nullptr;
237 }
238 }
239 // DEFINE KEYS
240 // Define set of "outer" keys that this wrapper factor is defined on.
241 std::unordered_set<Key> outer_key_set;
242 for (Key key : inner_factor->keys()) {
243 if (key_to_interp_.find(key) == key_to_interp_.end()) {
244 // inner key is not interpolated, add to outer keys
245 outer_key_set.insert(key);
246 } else {
247 // inner key is interpolated, add associated border state keys to this
248 // factor's keys
249 StateData& interp = key_to_interp_.at(key); // get state
250 auto [left, right] = interp_to_borders_.at(interp); // get borders
251 outer_key_set.insert(left.pose); // add border keys
252 outer_key_set.insert(left.velocity);
253 outer_key_set.insert(right.pose);
254 outer_key_set.insert(right.velocity);
255 }
256 }
257 // Convert to key vector (from set)
258 keys_ = KeyVector(outer_key_set.begin(), outer_key_set.end());
259
260 // map outer keys to their associated index (used when mapping jacobians
261 // later)
262 for (size_t i = 0; i < this->keys_.size(); i++) {
263 outer_key_to_index_[this->keys_[i]] = i;
264 }
265 // Build inner key mappings once and cache inner key indices
266 // We will use this mapping to know how to map inner Jacobian blocks to
267 // outer
268
269 // number of inner keys (keys associated with just the inner factor)
270 const KeyVector& inner_keys_init = inner_factor_->keys();
271
272 // Vector of structs that stores the mapping information for each inner key
273 // (whether it's interpolated, and the corresponding outer key indices)
274 inner_key_mappings_.resize(inner_keys_init.size());
275
276 // This map allows us to quickly find the index of an inner key in the inner
277 // factor's key ordering This is important for correctly mapping Jacobian
278 // blocks during linearization. We build this map once in the constructor to
279 // avoid redundant work later (slight speed up)
280 inner_key_to_index_.reserve(inner_keys_init.size());
281
282 // Loop through all inner keys and save the relevant mappings to outer keys
283 for (size_t i = 0; i < inner_keys_init.size(); ++i) {
284 // inner key
285 Key innerKey = inner_keys_init[i];
286 // current index
287 inner_key_to_index_[innerKey] = static_cast<int>(i);
288 InnerKeyMapping mapping;
289 auto itInterp = key_to_interp_.find(innerKey);
290
291 // If this condition is met, then this inner key is not interpolated and
292 // directly corresponds to an outer key We can map the Jacobian block for
293 // this inner key directly to the corresponding outer key index
294 if (itInterp == key_to_interp_.end()) {
295 auto itOuter = outer_key_to_index_.find(innerKey);
296 if (itOuter != outer_key_to_index_.end())
297 mapping.directOuterIndex = itOuter->second;
298 } else {
299 // Otherwise, this inner key is interpolated and we need to map it to
300 // its corresponding border states The Jacobian blocks that connect them
301 // to the inner key
302 mapping.isInterpolated = true;
303
304 // get border states for this interpolated key using the
305 // interp_to_borders_ map we built earlier
306 const StateData& sd = itInterp->second;
307 const auto& br = interp_to_borders_.at(sd);
308 const StateData& left = br.first;
309 const StateData& right = br.second;
310
311 // Map the border states to their corresponding outer key indices
312 // This uses the outer_key_to_index_ map we built earlier
313 // We will need these indices to know where to map Jacobian blocks
314 // during linearization
315 mapping.indexPoseLeft = outer_key_to_index_.at(left.pose);
316 mapping.indexVelLeft = outer_key_to_index_.at(left.velocity);
317 mapping.indexPoseRight = outer_key_to_index_.at(right.pose);
318 mapping.indexVelRight = outer_key_to_index_.at(right.velocity);
319
320 // also save the actual keys for clarity (might not be accessed during
321 // compute)
322 mapping.keyPoseLeft = left.pose;
323 mapping.keyVelLeft = left.velocity;
324 mapping.keyPoseRight = right.pose;
325 mapping.keyVelRight = right.velocity;
326 }
327 inner_key_mappings_[i] = mapping;
328 }
329 };
330
334 ~WnoaInterpFactor() override {};
335
343 void print(
344 const std::string& s = "",
345 const KeyFormatter& keyFormatter = DefaultKeyFormatter) const override {
346 std::cout << s << "WnoaInterpFactor on ";
347 for (const auto& k : this->keys()) {
348 std::cout << keyFormatter(k) << " "; // raw numeric key
349 }
350 std::cout << std::endl;
351 this->inner_factor_->print("Inner Factor: ");
352 }
353
356 bool equals(const NonlinearFactor& expected,
357 double tol = 1e-9) const override {
358 const This* e = dynamic_cast<const This*>(&expected);
359 return e != nullptr && Base::equals(*e, tol);
360 }
361
365 using Base::unwhitenedError;
366
374 Vector unwhitenedError(const Values& values,
375 OptionalMatrixVecType H = nullptr) const override {
376 return computeInterpolatedError(values, H);
377 }
378
387 std::shared_ptr<GaussianFactor> linearize(const Values& x) const override {
388 // Only linearize if the factor is active
389 if (!active(x)) return std::shared_ptr<JacobianFactor>();
390
391 // Compute residual and effective noise model.
392 std::vector<Matrix> A(size());
393 Vector b;
394 auto noise_model = eval(x, nullptr, b, &A);
395 return makeJacobianFactor(A, b, noise_model);
396 }
397
406 std::shared_ptr<GaussianFactor> linearize(
407 const Values& x, PassedInterpData* passedInterpData) const {
408 // Only linearize if the factor is active
409 if (!active(x)) return std::shared_ptr<JacobianFactor>();
410
411 // Compute residual and effective noise model.
412 std::vector<Matrix> A(size());
413 Vector b;
414 auto noise_model = eval(x, passedInterpData, b, &A);
415 return makeJacobianFactor(A, b, noise_model);
416 }
417
424 double error(const Values& c) const override {
425 if (!active(c)) return 0.0;
426
427 Vector b;
428 auto noise_model = eval(c, nullptr, b, nullptr);
429 return loss(b, noise_model);
430 }
431
438 double error(const Values& c, PassedInterpData* passedInterpData) const {
439 if (!active(c)) return 0.0;
440
441 Vector b;
442 auto noise_model = eval(c, passedInterpData, b, nullptr);
443 return loss(b, noise_model);
444 }
445
454 SharedGaussian noiseModel(Values& x) const {
455 // if fixed noise then just return the standard gaussian model
456 if (fixed_noise_model_) {
457 return std::dynamic_pointer_cast<noiseModel::Gaussian>(
459 }
460 // Call evaluate error to get inner Jacobians and convariances
461 std::vector<Matrix> JacInner(inner_factor_->size());
462 std::unordered_map<StateData, Matrix2N> InterpCondCovs;
463 Vector b =
464 -computeInterpolatedError(x, nullptr, &JacInner, &InterpCondCovs);
465 // get interpolated noise model
466 return getInterpolatedNoiseModel(JacInner, InterpCondCovs);
467 }
468
474 std::unordered_map<Key, StateData> getInterpolatedKeys() const {
475 return key_to_interp_;
476 }
477
483 std::unordered_map<StateData, std::pair<StateData, StateData>>
485 return interp_to_borders_;
486 }
487
488 private:
490 noiseModel::Gaussian::shared_ptr eval(const Values& values,
491 PassedInterpData* passedInterpData,
492 Vector& b,
493 std::vector<Matrix>* A) const {
494 if (A && (A->size() != size())) A->resize(size());
495
496 return fixed_noise_model_ ? evalFixed(values, A, passedInterpData, b)
497 : evalInterp(values, A, passedInterpData, b);
498 }
499
501 noiseModel::Gaussian::shared_ptr evalFixed(const Values& values,
502 std::vector<Matrix>* A,
503 PassedInterpData* passedInterpData,
504 Vector& b) const {
505 b = -computeInterpolatedError(values, A, nullptr, nullptr,
506 passedInterpData);
507 return std::dynamic_pointer_cast<noiseModel::Gaussian>(Base::noiseModel());
508 }
509
511 noiseModel::Gaussian::shared_ptr evalInterp(
512 const Values& values, std::vector<Matrix>* A,
513 PassedInterpData* passedInterpData, Vector& b) const {
514 std::vector<Matrix> jacInner(inner_factor_->size());
515
516 if (passedInterpData) {
517 b = -computeInterpolatedError(values, A, &jacInner, nullptr,
518 passedInterpData);
519 return getInterpolatedNoiseModel(jacInner, passedInterpData->condCovs);
520 }
521
522 std::unordered_map<StateData, Matrix2N> localInterpCondCovs;
523 b = -computeInterpolatedError(values, A, &jacInner, &localInterpCondCovs);
524 return getInterpolatedNoiseModel(jacInner, localInterpCondCovs);
525 }
526
528 std::shared_ptr<GaussianFactor> makeJacobianFactor(
529 std::vector<Matrix>& A, Vector& b,
530 const noiseModel::Gaussian::shared_ptr& noise_model) const {
531 noise_model->WhitenSystem(A, b);
532
533 std::vector<std::pair<Key, Matrix>> terms(size());
534 for (size_t j = 0; j < size(); ++j) {
535 terms[j].first = keys()[j];
536 terms[j].second.swap(A[j]);
537 }
538
540 if (noiseModel_ && noiseModel_->isConstrained()) {
541 return std::make_shared<JacobianFactor>(
542 terms, b, std::static_pointer_cast<Constrained>(noiseModel_)->unit());
543 }
544 return std::make_shared<JacobianFactor>(terms, b);
545 }
546
548 double loss(const Vector& b,
549 const noiseModel::Gaussian::shared_ptr& noise_model) const {
550 if (noise_model)
551 return noise_model->loss(noise_model->squaredMahalanobisDistance(b));
552 return 0.5 * b.squaredNorm();
553 }
554
577 Vector computeInterpolatedError(
578 const Values& values, OptionalMatrixVecType H = nullptr,
579 OptionalMatrixVecType H_inner = nullptr,
580 std::unordered_map<StateData, Matrix2N>* InterpCondCovs = nullptr,
581 PassedInterpData* passedInterpData = nullptr) const {
582 // Interpolation Jacobians stored as flattened map: per interpolated key ->
583 // 4 blocks
584 std::unordered_map<Key, std::array<Matrix, 4>> interpJacobiansLocal;
585 Values valuesInterpLocal;
586
587 std::unordered_map<Key, std::array<Matrix, 4>>* InterpJacobians = nullptr;
588 Values* values_interp = nullptr;
589
590 if (passedInterpData) {
591 values_interp = &passedInterpData->values;
592 if (H) InterpJacobians = &passedInterpData->jacobians;
593 if (InterpCondCovs) {
594 InterpCondCovs = &passedInterpData->condCovs;
595 }
596 } else {
597 if (H) {
598 InterpJacobians = &interpJacobiansLocal;
599 valuesInterpLocal =
600 getInterpolatedValues(values, InterpJacobians, InterpCondCovs);
601 values_interp = &valuesInterpLocal;
602 } else {
603 valuesInterpLocal =
604 getInterpolatedValues(values, nullptr, InterpCondCovs);
605 values_interp = &valuesInterpLocal;
606 }
607 }
608
609 // cache inner keys once
610 const KeyVector& inner_keys = inner_factor_->keys();
611
612 // construct values for inner factor using mappings
613 Values values_inner;
614 for (size_t i = 0; i < inner_keys.size(); ++i) {
615 Key key = inner_keys[i];
616 if (inner_key_mappings_[i].isInterpolated) {
617 auto it_interp = values_interp->find(key);
618 if (it_interp == values_interp->end())
619 throw std::runtime_error("Interpolated key missing in values_interp");
620 values_inner.insert(key, it_interp->value);
621 } else {
622 auto it_outer = values.find(key);
623 if (it_outer == values.end())
624 throw std::runtime_error("Key " + DefaultKeyFormatter(key) +
625 " not found in outer values");
626 values_inner.insert(key, it_outer->value);
627 }
628 }
629
630 // Call inner factor error function with interpolated values.
631 std::vector<Matrix> H_inner_local;
632 Vector error;
633 if (!H_inner) {
634 // if H_inner not passed in, use local variable.
635 H_inner_local.resize(inner_keys.size());
636 H_inner = &H_inner_local;
637 }
638 if (H || !fixed_noise_model_) {
639 error = inner_factor_->unwhitenedError(values_inner, H_inner);
640 } else {
641 error = inner_factor_->unwhitenedError(values_inner);
642 }
643
644 // compute Jacobians for outer keys
645 if (H) {
646 // loop through inner keys and update outer keys via backpropagation
647 // NOTE: it is possible for two inner keys to affect the same outer key
648 for (size_t i = 0; i < inner_keys.size(); i++) {
649 const Key inner_key = inner_keys[i];
650 const Matrix& Jinner = (*H_inner)[i];
651 const InnerKeyMapping& mapping = inner_key_mappings_[i];
652 if (mapping.isInterpolated) {
653 const std::array<Matrix, 4>& J4 = InterpJacobians->at(inner_key);
654 // Order: 0:LPose, 1:LVel, 2:RPose, 3:RVel
655 if (mapping.indexPoseLeft >= 0) {
656 const Matrix& Jblock = J4[0];
657 if ((*H)[mapping.indexPoseLeft].size() == 0)
658 (*H)[mapping.indexPoseLeft].setZero(Jinner.rows(), Jblock.cols());
659 (*H)[mapping.indexPoseLeft].noalias() += Jinner * Jblock;
660 }
661 if (mapping.indexVelLeft >= 0) {
662 const Matrix& Jblock = J4[1];
663 if ((*H)[mapping.indexVelLeft].size() == 0)
664 (*H)[mapping.indexVelLeft].setZero(Jinner.rows(), Jblock.cols());
665 (*H)[mapping.indexVelLeft].noalias() += Jinner * Jblock;
666 }
667 if (mapping.indexPoseRight >= 0) {
668 const Matrix& Jblock = J4[2];
669 if ((*H)[mapping.indexPoseRight].size() == 0)
670 (*H)[mapping.indexPoseRight].setZero(Jinner.rows(),
671 Jblock.cols());
672 (*H)[mapping.indexPoseRight].noalias() += Jinner * Jblock;
673 }
674 if (mapping.indexVelRight >= 0) {
675 const Matrix& Jblock = J4[3];
676 if ((*H)[mapping.indexVelRight].size() == 0)
677 (*H)[mapping.indexVelRight].setZero(Jinner.rows(), Jblock.cols());
678 (*H)[mapping.indexVelRight].noalias() += Jinner * Jblock;
679 }
680 } else {
681 const int k = mapping.directOuterIndex;
682 if ((*H)[k].size() == 0)
683 (*H)[k].setZero(Jinner.rows(), Jinner.cols());
684 (*H)[k].noalias() += Jinner;
685 }
686 }
687 }
688
689 return error;
690 }
691
715 Values getInterpolatedValues(
716 const Values& values,
717 std::unordered_map<Key, std::array<Matrix, 4>>* InterpJacobians = nullptr,
718 std::unordered_map<StateData, Matrix2N>* InterpCondCovs = nullptr) const {
719 Values values_interp; // interpolated values
720
721 // loop through interpolated state map and compute values
722 for (const auto& [interp_state, border_states] : interp_to_borders_) {
723 // unpack border states
724 auto& [left, right] = border_states;
725 // retrieve estimated state values
726 const auto state_left = TimestampedPoseVelocity<PoseType>(
727 values.at<PoseType>(left.pose),
728 values.at<VelocityType>(left.velocity), left.time);
729
730 const auto state_right = TimestampedPoseVelocity<PoseType>(
731 values.at<PoseType>(right.pose),
732 values.at<VelocityType>(right.velocity), right.time);
733
734 // Get interpolated state velocity pair
736
737 std::vector<Matrix> H(8);
738 if (InterpJacobians) {
739 result = interpolator_.interpolatePoseAndVelocity(
740 state_left, state_right, interp_state.time, &H, nullptr, nullptr,
741 lambda_psi_pre_comp_.at(interp_state));
742 } else {
743 result = interpolator_.interpolatePoseAndVelocity(
744 state_left, state_right, interp_state.time, nullptr, nullptr,
745 nullptr, lambda_psi_pre_comp_.at(interp_state));
746 }
747
748 // insert into values structure
749 values_interp.insert(interp_state.pose, result.pose);
750 values_interp.insert(interp_state.velocity, result.vel);
751
752 // arrange jacobians in flattened map (fixed order blocks)
753 if (InterpJacobians) {
754 (*InterpJacobians)[interp_state.pose] =
755 std::array<Matrix, 4>{H[0], H[1], H[2], H[3]};
756 (*InterpJacobians)[interp_state.velocity] =
757 std::array<Matrix, 4>{H[4], H[5], H[6], H[7]};
758 }
759
760 // Conditional covariance of interpolated states for noise model update
761 if (InterpCondCovs) {
762 auto state_tau =
763 TimestampedPoseVelocity<PoseType>(result, interp_state.time);
764 Matrix2N Sigma_tau = interpolator_.computeConditionalCov(
765 state_left, state_right, state_tau);
766 (*InterpCondCovs)[interp_state] =
767 Sigma_tau; // assumed preallocated vector
768 }
769 }
770
771 return values_interp;
772 }
773
793 SharedGaussian getInterpolatedNoiseModel(
794 const std::vector<Matrix>& Jacobians,
795 const std::unordered_map<StateData, Matrix2N>& InterpCondCovs) const {
796 // Get noise model of inner factor
797 noiseModel::Gaussian::shared_ptr noise_model_ptr =
798 std::dynamic_pointer_cast<noiseModel::Gaussian>(
799 inner_factor_->noiseModel());
800 // Check that the measurement noise is set up as a gaussian
801 assert(noise_model_ptr &&
802 "Noise model of inner factor must be noiseModel::Gaussian or "
803 "derivative");
804
805 // Initialize new covariance with the existing measurement covariance
806 int err_dim = noise_model_ptr->dim();
807 Matrix noise_cov = noise_model_ptr->covariance();
808
809 // Use cached mapping from inner keys to indices for Jacobian lookup
810 // Compute the covariance update based on interpolated states
811 // Note: Here, we leverage the block-diagonal approximation of the
812 // interpolated covariances (i.e., independence approximation)
813 for (auto& [state, borders] : interp_to_borders_) {
814 // Retrieve Jacobians from inner factor
815 Matrix G_pose(err_dim, dim);
816 Matrix G_vel(err_dim, dim);
817 auto itPose = inner_key_to_index_.find(state.pose);
818 if (itPose != inner_key_to_index_.end()) {
819 G_pose = Jacobians[itPose->second];
820 } else {
821 G_pose.setZero();
822 }
823 auto itVel = inner_key_to_index_.find(state.velocity);
824 if (itVel != inner_key_to_index_.end()) {
825 G_vel = Jacobians[itVel->second];
826 } else {
827 G_vel.setZero();
828 }
829 Matrix G_tau(err_dim, 2 * dim);
830 G_tau << G_pose, G_vel;
831 // add covariance
832
833 const Matrix2N& Sigma_tau = InterpCondCovs.at(state);
834 noise_cov += G_tau * Sigma_tau * G_tau.transpose();
835 }
836
837 // Return interpolated noise model
838 return noiseModel::Gaussian::Covariance(noise_cov);
839 }
840};
841
843template <class POSE>
845 : public Testable<WnoaInterpFactor<POSE>> {};
846
847} // namespace gtsam
Timing utilities.
Concept check for values that can be used in unit tests.
Base class and basic functions for Lie types.
3D Point
3D Pose manifold SO(3) x R^3 and group SE(3)
2D Point
2D Pose
1D Point
Interpolator class implementation for interpolating poses and velocities between two bordering states...
A non-templated config holding any types of Manifold-group elements.
Introduces a lightweight struct for identifying states in continuous-time estimation and interpolatio...
Non-linear factor base classes.
Global functions in a separate testing namespace.
Definition chartTesting.h:28
KeyFormatter DefaultKeyFormatter
Assign default key formatter.
Definition Key.cpp:30
FastVector< Key > KeyVector
Define collection type once and for all - also used in wrappers.
Definition Key.h:91
std::function< std::string(Key)> KeyFormatter
Typedef for a function to format a key, i.e. to convert it to a string.
Definition Key.h:35
std::vector< Matrix > * OptionalMatrixVecType
The OptionalMatrixVecType is a pointer to a vector of matrices.
Definition NonlinearFactor.h:63
std::uint64_t Key
Integer nonlinear key type.
Definition types.h:43
A manifold defines a space in which there is a notion of a linear tangent space that can be centered ...
Definition Group.h:37
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
size_t size() const
Definition Factor.h:160
static shared_ptr Covariance(const Matrix &covariance, bool smart=true)
A Gaussian noise model created by specifying a covariance matrix.
Definition NoiseModel.cpp:116
A Constrained constrained model is a specialization of Diagonal which allows some or all of the sigma...
Definition NoiseModel.h:436
Nonlinear factor base class.
Definition NonlinearFactor.h:70
virtual bool active(const Values &c) const
Checks whether a factor should be used based on a set of values.
Definition NonlinearFactor.h:143
std::shared_ptr< This > shared_ptr
Noise model.
Definition NonlinearFactor.h:220
bool equals(const NonlinearFactor &f, double tol=1e-9) const override
Check if two factors are equal.
Definition NonlinearFactor.cpp:90
double error(const Values &c) const override
Calculate the error of the factor.
Definition NonlinearFactor.cpp:146
NoiseModelFactor()
Default constructor for I/O only.
Definition NonlinearFactor.h:223
const SharedNoiseModel & noiseModel() const
access to the noise model
Definition NonlinearFactor.h:258
A non-templated config holding any types of Manifold-group elements.
Definition Values.h:65
Wrapper factor that evaluates an inner NoiseModelFactor on states interpolated from neighboring estim...
Definition WnoaInterpFactor.h:92
SharedGaussian noiseModel(Values &x) const
Return an augmented noise model accounting for interpolation.
Definition WnoaInterpFactor.h:454
std::shared_ptr< GaussianFactor > linearize(const Values &x) const override
Linearize the wrapper factor, computing a JacobianFactor.
Definition WnoaInterpFactor.h:387
WnoaInterpFactor(const NoiseModelFactor::shared_ptr inner_factor, const std::set< StateData > estimated_states, const std::set< StateData > interp_states, const Eigen::Matrix< double, dim, 1 > q_psd_diag, const bool fixed_noise_model=false, const bool precomp_interp_mats=true)
Construct a WNOA interpolation wrapper factor.
Definition WnoaInterpFactor.h:191
std::unordered_map< Key, StateData > getInterpolatedKeys() const
Get the mapping from outer Keys to their corresponding interpolated StateData.
Definition WnoaInterpFactor.h:474
std::shared_ptr< GaussianFactor > linearize(const Values &x, PassedInterpData *passedInterpData) const
Linearize using externally provided interpolation data.
Definition WnoaInterpFactor.h:406
bool equals(const NonlinearFactor &expected, double tol=1e-9) const override
Equality test used by unit tests and debug checks.
Definition WnoaInterpFactor.h:356
void print(const std::string &s="", const KeyFormatter &keyFormatter=DefaultKeyFormatter) const override
Implement functions needed for Testable.
Definition WnoaInterpFactor.h:343
double error(const Values &c) const override
Compute the factor error (unwhitened) using the current Values.
Definition WnoaInterpFactor.h:424
Vector unwhitenedError(const Values &values, OptionalMatrixVecType H=nullptr) const override
Compute the unwhitened residual vector for the wrapped inner factor.
Definition WnoaInterpFactor.h:374
~WnoaInterpFactor() override
Default destructor.
Definition WnoaInterpFactor.h:334
std::unordered_map< StateData, std::pair< StateData, StateData > > getInterpToBorders() const
Get the mapping from each interpolated StateData to its bordering states.
Definition WnoaInterpFactor.h:484
double error(const Values &c, PassedInterpData *passedInterpData) const
Error computation accepting precomputed interpolation data.
Definition WnoaInterpFactor.h:438
Container for externally-computed interpolation data.
Definition WnoaInterpFactor.h:158
Values values
Interpolated Values (pose and velocity entries at interpolated times).
Definition WnoaInterpFactor.h:160
std::unordered_map< Key, std::array< Matrix, 4 > > jacobians
Flattened jacobian blocks for each inner key mapping to its contributing outer keys.
Definition WnoaInterpFactor.h:166
std::unordered_map< StateData, Matrix2N > condCovs
Conditional covariance (2N x 2N) for each interpolated StateData.
Definition WnoaInterpFactor.h:169
Simple container for a pose and its corresponding velocity.
Definition WnoaInterpolator.h:57
Timestamped pose and velocity container.
Definition WnoaInterpolator.h:76
Interpolator for poses and velocities under a motion prior.
Definition WnoaInterpolator.h:106
Matrix2N computeConditionalCov(const TimestampedPoseVel &pvk, const TimestampedPoseVel &pvkp1, const TimestampedPoseVel &pvtau, OptionalMatrixType Lambda=nullptr, OptionalMatrixType Psi=nullptr) const
Compute the conditional covariance of the interpolated state.
Definition WnoaInterpolator.cpp:670
PoseVel interpolatePoseAndVelocity(const std::optional< TimestampedPoseVel > &Tvarpi_k, const std::optional< TimestampedPoseVel > &Tvarpi_kp1, double t_tau, OptionalMatrixVecType H=nullptr, const std::shared_ptr< Matrix > &mainSolveMarginalMatrix=nullptr, Matrix *covarianceOut=nullptr, const std::shared_ptr< const LambdaPsiMats > &LambdaPsiPreComp=nullptr, const std::shared_ptr< const LocalStateVecs > &localStateVecsPreComp=nullptr, const std::shared_ptr< const StateJacobians > &stateJacobiansPreComp=nullptr) const
Interpolate the pose and velocity at time t_tau.
Definition WnoaInterpolator.cpp:65
Lightweight container for states used for continuous-time estimation and interpolation.
Definition WnoaStateData.h:39
In nonlinear factors, the error function returns the negative log-likelihood as a non-linear function...