/* ---------------------------------------------------------------------------- * GTSAM Copyright 2010, Georgia Tech Research Corporation, * Atlanta, Georgia 30332-0415 * All Rights Reserved * Authors: Frank Dellaert, et al. (see THANKS for the full author list) * See LICENSE for the license information * -------------------------------------------------------------------------- */ /** * @file NonlinearFactor.cpp * @brief Nonlinear Factor base classes * @author Frank Dellaert * @author Richard Roberts */ #include #include #include namespace gtsam { /* ************************************************************************* */ double NonlinearFactor::error(const Values& c) const { throw std::runtime_error("NonlinearFactor::error is not implemented"); } /* ************************************************************************* */ double NonlinearFactor::error(const HybridValues& c) const { return this->error(c.nonlinear()); } /* ************************************************************************* */ void NonlinearFactor::print(const std::string& s, const KeyFormatter& keyFormatter) const { std::cout << s << " keys = { "; for(Key key: keys()) { std::cout << keyFormatter(key) << " "; } std::cout << "}" << std::endl; } /* ************************************************************************* */ bool NonlinearFactor::equals(const NonlinearFactor& f, double tol) const { return Base::equals(f); } /* ************************************************************************* */ NonlinearFactor::shared_ptr NonlinearFactor::rekey( const std::map& rekey_mapping) const { shared_ptr new_factor = clone(); for (size_t i = 0; i < new_factor->size(); ++i) { Key& cur_key = new_factor->keys()[i]; std::map::const_iterator mapping = rekey_mapping.find(cur_key); if (mapping != rekey_mapping.end()) cur_key = mapping->second; } return new_factor; } /* ************************************************************************* */ NonlinearFactor::shared_ptr NonlinearFactor::rekey( const KeyVector& new_keys) const { assert(new_keys.size() == keys().size()); shared_ptr new_factor = clone(); new_factor->keys() = new_keys; return new_factor; } /* ************************************************************************* */ void NoiseModelFactor::print(const std::string& s, const KeyFormatter& keyFormatter) const { Base::print(s, keyFormatter); if (noiseModel_) noiseModel_->print(" noise model: "); } /* ************************************************************************* */ bool NoiseModelFactor::equals(const NonlinearFactor& f, double tol) const { const NoiseModelFactor* e = dynamic_cast(&f); return e && Base::equals(f, tol) && ((!noiseModel_ && !e->noiseModel_) || (noiseModel_ && e->noiseModel_ && noiseModel_->equals(*e->noiseModel_, tol))); } /* ************************************************************************* */ NoiseModelFactor::shared_ptr NoiseModelFactor::cloneWithNewNoiseModel( const SharedNoiseModel newNoise) const { NoiseModelFactor::shared_ptr new_factor = std::dynamic_pointer_cast(clone()); new_factor->noiseModel_ = newNoise; return new_factor; } /* ************************************************************************* */ static void check(const SharedNoiseModel& noiseModel, size_t m) { if (noiseModel && m != noiseModel->dim()) { throw std::invalid_argument( "NoiseModelFactor: NoiseModel has dimension " + std::to_string(noiseModel->dim()) + " instead of " + std::to_string(m) + "."); } } /* ************************************************************************* */ Vector NoiseModelFactor::whitenedError(const Values& c) const { const Vector b = unwhitenedError(c); check(noiseModel_, b.size()); return noiseModel_ ? noiseModel_->whiten(b) : b; } /* ************************************************************************* */ Vector NoiseModelFactor::unweightedWhitenedError(const Values& c) const { const Vector b = unwhitenedError(c); check(noiseModel_, b.size()); return noiseModel_ ? noiseModel_->unweightedWhiten(b) : b; } /* ************************************************************************* */ double NoiseModelFactor::weight(const Values& c) const { if (active(c)) { if (noiseModel_) { const Vector b = unwhitenedError(c); check(noiseModel_, b.size()); return noiseModel_->weight(b); } else return 1.0; } else { return 0.0; } } /* ************************************************************************* */ double NoiseModelFactor::error(const Values& c) const { if (active(c)) { const Vector b = unwhitenedError(c); check(noiseModel_, b.size()); if (noiseModel_) return noiseModel_->loss(noiseModel_->squaredMahalanobisDistance(b)); else return 0.5 * b.squaredNorm(); } else { return 0.0; } } /* ************************************************************************* */ std::shared_ptr NoiseModelFactor::linearize( const Values& x) const { // Only linearize if the factor is active if (!active(x)) return std::shared_ptr(); // Call evaluate error to get Jacobians and RHS vector b std::vector A(size()); Vector b = -unwhitenedError(x, A); check(noiseModel_, b.size()); // Whiten the corresponding system now if (noiseModel_) noiseModel_->WhitenSystem(A, b); // Fill in terms, needed to create JacobianFactor below std::vector > terms(size()); for (size_t j = 0; j < size(); ++j) { terms[j].first = keys()[j]; terms[j].second.swap(A[j]); } // TODO pass unwhitened + noise model to Gaussian factor using noiseModel::Constrained; if (noiseModel_ && noiseModel_->isConstrained()) return GaussianFactor::shared_ptr( new JacobianFactor(terms, b, std::static_pointer_cast(noiseModel_)->unit())); else { return GaussianFactor::shared_ptr(new JacobianFactor(terms, b)); } } /* ************************************************************************* */ } // \namespace gtsam