/* ---------------------------------------------------------------------------- * 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 FunctorizedFactor.h * @date May 31, 2020 * @author Varun Agrawal **/ #pragma once #include #include #include namespace gtsam { /** * Factor which evaluates functor and uses the result to compute * error on provided measurement. * The provided FUNCTOR should provide two type aliases: `argument_type` which * corresponds to the type of input it accepts and `return_type` which indicates * the type of the return value. This factor uses those type values to construct * the functor. * * Template parameters are * @param FUNCTOR: A class which operates as a functor. * * Example: * Key key = Symbol('X', 0); * * auto model = noiseModel::Isotropic::Sigma(9, 1); * /// Functor that takes a matrix and multiplies every element by m * class MultiplyFunctor { * double m_; ///< simple multiplier * public: * using argument_type = Matrix; * using return_type = Matrix; * MultiplyFunctor(double m) : m_(m) {} * Matrix operator()(const Matrix &X, * OptionalJacobian<-1, -1> H = boost::none) const { * if (H) *H = m_ * Matrix::Identity(X.rows()*X.cols(), X.rows()*X.cols()); * return m_ * X; * } * }; * * Matrix measurement = Matrix::Identity(3, 3); * double multiplier = 2.0; * FunctorizedFactor factor(keyX, measurement, model, multiplier); */ template class GTSAM_EXPORT FunctorizedFactor : public NoiseModelFactor1 { private: using T = typename FUNCTOR::argument_type; using Base = NoiseModelFactor1; typename FUNCTOR::return_type measured_; ///< value that is compared with functor return value SharedNoiseModel noiseModel_; ///< noise model FUNCTOR func_; ///< functor instance public: /** default constructor - only use for serialization */ FunctorizedFactor() {} /** Construct with given x and the parameters of the basis * * @param Args: Variadic template parameter for functor arguments. * * @param key: Factor key * @param z: Measurement object of type FUNCTOR::return_type * @param model: Noise model * @param args: Variable number of arguments used to instantiate functor */ template FunctorizedFactor(Key key, const typename FUNCTOR::return_type &z, const SharedNoiseModel &model, Args &&... args) : Base(model, key), measured_(z), noiseModel_(model), func_(std::forward(args)...) {} virtual ~FunctorizedFactor() {} /// @return a deep copy of this factor virtual NonlinearFactor::shared_ptr clone() const { return boost::static_pointer_cast( NonlinearFactor::shared_ptr(new FunctorizedFactor(*this))); } Vector evaluateError(const T ¶ms, boost::optional H = boost::none) const { typename FUNCTOR::return_type x = func_(params, H); Vector error = traits::Local(measured_, x); return error; } /// @name Testable /// @{ void print(const std::string &s = "", const KeyFormatter &keyFormatter = DefaultKeyFormatter) const { Base::print(s, keyFormatter); std::cout << s << (s != "" ? " " : "") << "FunctorizedFactor(" << keyFormatter(this->key()) << ")" << std::endl; traits::Print(measured_, " measurement: "); std::cout << " noise model sigmas: " << noiseModel_->sigmas().transpose() << std::endl; } virtual bool equals(const NonlinearFactor &other, double tol = 1e-9) const { const FunctorizedFactor *e = dynamic_cast *>(&other); const bool base = Base::equals(*e, tol); return e && Base::equals(other, tol) && traits::Equals(this->measured_, e->measured_, tol); } /// @} private: /** Serialization function */ friend class boost::serialization::access; template void serialize(ARCHIVE &ar, const unsigned int /*version*/) { ar &boost::serialization::make_nvp( "NoiseModelFactor1", boost::serialization::base_object(*this)); ar &BOOST_SERIALIZATION_NVP(measured_); ar &BOOST_SERIALIZATION_NVP(func_); } }; /// traits template struct traits> : public Testable> {}; } // namespace gtsam