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;
116 const bool fixed_noise_model_;
118 std::unordered_map<Key, StateData> key_to_interp_;
120 std::unordered_map<StateData, std::pair<StateData, StateData>>
123 std::unordered_map<Key, int> outer_key_to_index_;
125 std::unordered_map<StateData, std::shared_ptr<LambdaPsiMats>>
126 lambda_psi_pre_comp_;
129 std::unordered_map<Key, int> inner_key_to_index_;
135 struct InnerKeyMapping {
136 bool isInterpolated =
false;
138 int directOuterIndex = -1;
140 int indexPoseLeft = -1, indexVelLeft = -1, indexPoseRight = -1,
142 Key keyPoseLeft = 0, keyVelLeft = 0, keyPoseRight = 0, keyVelRight = 0;
144 std::vector<InnerKeyMapping> inner_key_mappings_;
166 std::unordered_map<Key, std::array<Matrix, 4>>
jacobians;
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)
198 inner_factor_(inner_factor),
199 interpolator_(q_psd_diag),
200 fixed_noise_model_(fixed_noise_model) {
203 for (
const StateData& state : interp_states) {
208 auto iter_est_state = estimated_states.lower_bound(state);
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");
221 interp_to_borders_[state] =
222 std::pair(*iter_est_state, *std::next(iter_est_state));
226 key_to_interp_[state.pose] = state;
227 key_to_interp_[state.velocity] = state;
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));
236 lambda_psi_pre_comp_[state] =
nullptr;
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()) {
245 outer_key_set.insert(key);
249 StateData& interp = key_to_interp_.at(key);
250 auto [left, right] = interp_to_borders_.at(interp);
251 outer_key_set.insert(left.pose);
252 outer_key_set.insert(left.velocity);
253 outer_key_set.insert(right.pose);
254 outer_key_set.insert(right.velocity);
262 for (
size_t i = 0; i < this->
keys_.size(); i++) {
263 outer_key_to_index_[this->
keys_[i]] = i;
270 const KeyVector& inner_keys_init = inner_factor_->
keys();
274 inner_key_mappings_.resize(inner_keys_init.size());
280 inner_key_to_index_.reserve(inner_keys_init.size());
283 for (
size_t i = 0; i < inner_keys_init.size(); ++i) {
285 Key innerKey = inner_keys_init[i];
287 inner_key_to_index_[innerKey] =
static_cast<int>(i);
288 InnerKeyMapping mapping;
289 auto itInterp = key_to_interp_.find(innerKey);
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;
302 mapping.isInterpolated =
true;
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;
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);
322 mapping.keyPoseLeft = left.pose;
323 mapping.keyVelLeft = left.velocity;
324 mapping.keyPoseRight = right.pose;
325 mapping.keyVelRight = right.velocity;
327 inner_key_mappings_[i] = mapping;
344 const std::string& s =
"",
346 std::cout << s <<
"WnoaInterpFactor on ";
347 for (
const auto& k : this->
keys()) {
348 std::cout << keyFormatter(k) <<
" ";
350 std::cout << std::endl;
351 this->inner_factor_->print(
"Inner Factor: ");
357 double tol = 1e-9)
const override {
358 const This* e =
dynamic_cast<const This*
>(&expected);
365 using Base::unwhitenedError;
376 return computeInterpolatedError(values, H);
389 if (!
active(x))
return std::shared_ptr<JacobianFactor>();
392 std::vector<Matrix> A(
size());
394 auto noise_model = eval(x,
nullptr, b, &A);
395 return makeJacobianFactor(A, b, noise_model);
409 if (!
active(x))
return std::shared_ptr<JacobianFactor>();
412 std::vector<Matrix> A(
size());
414 auto noise_model = eval(x, passedInterpData, b, &A);
415 return makeJacobianFactor(A, b, noise_model);
425 if (!
active(c))
return 0.0;
428 auto noise_model = eval(c,
nullptr, b,
nullptr);
429 return loss(b, noise_model);
439 if (!
active(c))
return 0.0;
442 auto noise_model = eval(c, passedInterpData, b,
nullptr);
443 return loss(b, noise_model);
456 if (fixed_noise_model_) {
457 return std::dynamic_pointer_cast<noiseModel::Gaussian>(
461 std::vector<Matrix> JacInner(inner_factor_->size());
462 std::unordered_map<StateData, Matrix2N> InterpCondCovs;
464 -computeInterpolatedError(x,
nullptr, &JacInner, &InterpCondCovs);
466 return getInterpolatedNoiseModel(JacInner, InterpCondCovs);
475 return key_to_interp_;
483 std::unordered_map<StateData, std::pair<StateData, StateData>>
485 return interp_to_borders_;
490 noiseModel::Gaussian::shared_ptr eval(
const Values& values,
491 PassedInterpData* passedInterpData,
493 std::vector<Matrix>* A)
const {
494 if (A && (A->size() != size())) A->resize(size());
496 return fixed_noise_model_ ? evalFixed(values, A, passedInterpData, b)
497 : evalInterp(values, A, passedInterpData, b);
501 noiseModel::Gaussian::shared_ptr evalFixed(
const Values& values,
502 std::vector<Matrix>* A,
503 PassedInterpData* passedInterpData,
505 b = -computeInterpolatedError(values, A,
nullptr,
nullptr,
507 return std::dynamic_pointer_cast<noiseModel::Gaussian>(Base::noiseModel());
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());
516 if (passedInterpData) {
517 b = -computeInterpolatedError(values, A, &jacInner,
nullptr,
519 return getInterpolatedNoiseModel(jacInner, passedInterpData->condCovs);
522 std::unordered_map<StateData, Matrix2N> localInterpCondCovs;
523 b = -computeInterpolatedError(values, A, &jacInner, &localInterpCondCovs);
524 return getInterpolatedNoiseModel(jacInner, localInterpCondCovs);
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);
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]);
540 if (noiseModel_ && noiseModel_->isConstrained()) {
541 return std::make_shared<JacobianFactor>(
542 terms, b, std::static_pointer_cast<Constrained>(noiseModel_)->unit());
544 return std::make_shared<JacobianFactor>(terms, b);
548 double loss(
const Vector& b,
549 const noiseModel::Gaussian::shared_ptr& noise_model)
const {
551 return noise_model->loss(noise_model->squaredMahalanobisDistance(b));
552 return 0.5 * b.squaredNorm();
577 Vector computeInterpolatedError(
580 std::unordered_map<StateData, Matrix2N>* InterpCondCovs =
nullptr,
581 PassedInterpData* passedInterpData =
nullptr)
const {
584 std::unordered_map<Key, std::array<Matrix, 4>> interpJacobiansLocal;
587 std::unordered_map<Key, std::array<Matrix, 4>>* InterpJacobians =
nullptr;
588 Values* values_interp =
nullptr;
590 if (passedInterpData) {
591 values_interp = &passedInterpData->values;
592 if (H) InterpJacobians = &passedInterpData->jacobians;
593 if (InterpCondCovs) {
594 InterpCondCovs = &passedInterpData->condCovs;
598 InterpJacobians = &interpJacobiansLocal;
600 getInterpolatedValues(values, InterpJacobians, InterpCondCovs);
601 values_interp = &valuesInterpLocal;
604 getInterpolatedValues(values,
nullptr, InterpCondCovs);
605 values_interp = &valuesInterpLocal;
610 const KeyVector& inner_keys = inner_factor_->keys();
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);
622 auto it_outer = values.find(key);
623 if (it_outer == values.end())
625 " not found in outer values");
626 values_inner.insert(key, it_outer->value);
631 std::vector<Matrix> H_inner_local;
635 H_inner_local.resize(inner_keys.size());
636 H_inner = &H_inner_local;
638 if (H || !fixed_noise_model_) {
639 error = inner_factor_->unwhitenedError(values_inner, H_inner);
641 error = inner_factor_->unwhitenedError(values_inner);
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);
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;
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;
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(),
672 (*H)[mapping.indexPoseRight].noalias() += Jinner * Jblock;
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;
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;
715 Values getInterpolatedValues(
717 std::unordered_map<
Key, std::array<Matrix, 4>>* InterpJacobians =
nullptr,
718 std::unordered_map<StateData, Matrix2N>* InterpCondCovs =
nullptr)
const {
722 for (
const auto& [interp_state, border_states] : interp_to_borders_) {
724 auto& [left, right] = border_states;
727 values.at<PoseType>(left.pose),
728 values.at<VelocityType>(left.velocity), left.time);
731 values.at<PoseType>(right.pose),
732 values.at<VelocityType>(right.velocity), right.time);
737 std::vector<Matrix> H(8);
738 if (InterpJacobians) {
740 state_left, state_right, interp_state.time, &H,
nullptr,
nullptr,
741 lambda_psi_pre_comp_.at(interp_state));
744 state_left, state_right, interp_state.time,
nullptr,
nullptr,
745 nullptr, lambda_psi_pre_comp_.at(interp_state));
749 values_interp.insert(interp_state.pose, result.pose);
750 values_interp.insert(interp_state.velocity, result.vel);
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]};
761 if (InterpCondCovs) {
765 state_left, state_right, state_tau);
766 (*InterpCondCovs)[interp_state] =
771 return values_interp;
793 SharedGaussian getInterpolatedNoiseModel(
794 const std::vector<Matrix>& Jacobians,
795 const std::unordered_map<StateData, Matrix2N>& InterpCondCovs)
const {
797 noiseModel::Gaussian::shared_ptr noise_model_ptr =
798 std::dynamic_pointer_cast<noiseModel::Gaussian>(
799 inner_factor_->noiseModel());
801 assert(noise_model_ptr &&
802 "Noise model of inner factor must be noiseModel::Gaussian or "
806 int err_dim = noise_model_ptr->dim();
807 Matrix noise_cov = noise_model_ptr->covariance();
813 for (
auto& [state, borders] : interp_to_borders_) {
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];
823 auto itVel = inner_key_to_index_.find(state.velocity);
824 if (itVel != inner_key_to_index_.end()) {
825 G_vel = Jacobians[itVel->second];
829 Matrix G_tau(err_dim, 2 * dim);
830 G_tau << G_pose, G_vel;
833 const Matrix2N& Sigma_tau = InterpCondCovs.at(state);
834 noise_cov += G_tau * Sigma_tau * G_tau.transpose();