/** * @file TupleConfig.h * @author Richard Roberts * @author Manohar Paluri * @author Alex Cunningham */ #include "LieConfig.h" #include "VectorConfig.h" #pragma once namespace gtsam { /** * TupleConfigs are a structure to manage heterogenous LieConfigs, so as to * enable different types of variables/keys to be used simultaneously. The * interface is designed to mimic that of a single LieConfig. * * This uses a recursive structure of config pairs to form a lisp-like * list, with a special case (TupleConfigEnd) that contains only one config * at the end. Because this recursion is done at compile time, there is no * runtime performance hit to using this structure. * * For an easier to use approach, there are TupleConfigN classes, which wrap * the recursive TupleConfigs together as a single class, so you can have * mixed-type classes from 2-6 types. Note that a TupleConfig2 is equivalent * to the previously used PairConfig. * * Design and extension note: * To implement a recursively templated data structure, note that most operations * have two versions: one with templates and one without. The templated one allows * for the arguments to be passed to the next config, while the specialized one * operates on the "first" config. TupleConfigEnd contains only the specialized version. */ template class TupleConfig : public Testable > { protected: // Data for internal configs Config1 first_; /// Arbitrary config Config2 second_; /// A TupleConfig or TupleConfigEnd, which wraps an arbitrary config public: // typedefs for config subtypes typedef class Config1::Key Key1; typedef class Config1::Value Value1; /** default constructor */ TupleConfig() {} /** Copy constructor */ TupleConfig(const TupleConfig& config) : first_(config.first_), second_(config.second_) {} /** Construct from configs */ TupleConfig(const Config1& cfg1, const Config2& cfg2) : first_(cfg1), second_(cfg2) {} virtual ~TupleConfig() {} /** Print */ void print(const std::string& s = "") const { first_.print(s); second_.print(); } /** Equality with tolerance for keys and values */ bool equals(const TupleConfig& c, double tol=1e-9) const { return first_.equals(c.first_, tol) && second_.equals(c.second_, tol); } /** * Insert a key/value pair to the config. * Note: if the key is already in the config, the config will not be changed. * Use update() to allow for changing existing values. * @param key is the key - can be an int (second version) if the can can be initialized from an int * @param value is the value to insert */ template void insert(const Key& key, const Value& value) {second_.insert(key, value);} void insert(const int& key, const Value1& value) {first_.insert(Key1(key), value);} void insert(const Key1& key, const Value1& value) {first_.insert(key, value);} /** * Insert a complete config at a time. * Note: if the key is already in the config, the config will not be changed. * Use update() to allow for changing existing values. * @param config is a full config to add */ template void insert(const TupleConfig& config) { second_.insert(config); } void insert(const TupleConfig& config) { first_.insert(config.first_); second_.insert(config.second_); } /** * Update function for whole configs - this will change existing values * @param config is a config to add */ template void update(const TupleConfig& config) { second_.update(config); } void update(const TupleConfig& config) { first_.update(config.first_); second_.update(config.second_); } /** * Update function for single key/value pairs - will change existing values * @param key is the variable identifier * @param value is the variable value to update */ template void update(const Key& key, const Value& value) { second_.update(key, value); } void update(const Key1& key, const Value1& value) { first_.update(key, value); } /** * Insert a subconfig * @param config is the config to insert */ template void insertSub(const Cfg& config) { second_.insertSub(config); } void insertSub(const Config1& config) { first_.insert(config); } /** erase an element by key */ template void erase(const Key& j) { second_.erase(j); } void erase(const Key1& j) { first_.erase(j); } /** clears the config */ void clear() { first_.clear(); second_.clear(); } /** determine whether an element exists */ template bool exists(const Key& j) const { return second_.exists(j); } bool exists(const Key1& j) const { return first_.exists(j); } /** a variant of exists */ template boost::optional exists_(const Key& j) const { return second_.exists_(j); } boost::optional exists_(const Key1& j) const { return first_.exists_(j); } /** access operator */ template const typename Key::Value_t & operator[](const Key& j) const { return second_[j]; } const Value1& operator[](const Key1& j) const { return first_[j]; } /** at access function */ template const typename Key::Value_t & at(const Key& j) const { return second_.at(j); } const Value1& at(const Key1& j) const { return first_.at(j); } /** direct config access */ const Config1& config() const { return first_; } const Config2& rest() const { return second_; } /** zero: create VectorConfig of appropriate structure */ VectorConfig zero() const { VectorConfig z1 = first_.zero(), z2 = second_.zero(); z2.insert(z1); return z2; } /** @return number of key/value pairs stored */ size_t size() const { return first_.size() + second_.size(); } /** @return true if config is empty */ bool empty() const { return first_.empty() && second_.empty(); } /** @return The dimensionality of the tangent space */ size_t dim() const { return first_.dim() + second_.dim(); } /** Expmap */ TupleConfig expmap(const VectorConfig& delta) const { return TupleConfig(gtsam::expmap(first_, delta), second_.expmap(delta)); } /** logmap each element */ VectorConfig logmap(const TupleConfig& cp) const { VectorConfig ret(gtsam::logmap(first_, cp.first_)); ret.insert(second_.logmap(cp.second_)); return ret; } private: /** Serialization function */ friend class boost::serialization::access; template void serialize(Archive & ar, const unsigned int version) { ar & BOOST_SERIALIZATION_NVP(first_); ar & BOOST_SERIALIZATION_NVP(second_); } }; /** * End of a recursive TupleConfig - contains only one config * * Do not use this class directly - it should only be used as a part * of a recursive structure */ template class TupleConfigEnd : public Testable > { protected: // Data for internal configs Config first_; public: // typedefs typedef class Config::Key Key1; typedef class Config::Value Value1; TupleConfigEnd() {} TupleConfigEnd(const TupleConfigEnd& config) : first_(config.first_) {} TupleConfigEnd(const Config& cfg) : first_(cfg) {} virtual ~TupleConfigEnd() {} void print(const std::string& s = "") const { first_.print(); } bool equals(const TupleConfigEnd& c, double tol=1e-9) const { return first_.equals(c.first_, tol); } void insert(const Key1& key, const Value1& value) {first_.insert(key, value); } void insert(const int& key, const Value1& value) {first_.insert(Key1(key), value);} void insert(const TupleConfigEnd& config) {first_.insert(config.first_); } void update(const TupleConfigEnd& config) {first_.update(config.first_); } void update(const Key1& key, const Value1& value) { first_.update(key, value); } void insertSub(const Config& config) {first_.insert(config); } const Value1& operator[](const Key1& j) const { return first_[j]; } const Config& config() const { return first_; } void erase(const Key1& j) { first_.erase(j); } void clear() { first_.clear(); } bool empty() const { return first_.empty(); } bool exists(const Key1& j) const { return first_.exists(j); } boost::optional exists_(const Key1& j) const { return first_.exists_(j); } const Value1& at(const Key1& j) const { return first_.at(j); } VectorConfig zero() const { VectorConfig z = first_.zero(); return z; } size_t size() const { return first_.size(); } size_t dim() const { return first_.dim(); } TupleConfigEnd expmap(const VectorConfig& delta) const { return TupleConfigEnd(gtsam::expmap(first_, delta)); } VectorConfig logmap(const TupleConfigEnd& cp) const { VectorConfig ret(gtsam::logmap(first_, cp.first_)); return ret; } private: friend class boost::serialization::access; template void serialize(Archive & ar, const unsigned int version) { ar & BOOST_SERIALIZATION_NVP(first_); } }; /** Exmap static functions */ template inline TupleConfig expmap(const TupleConfig& c, const VectorConfig& delta) { return c.expmap(delta); } /** logmap static functions */ template inline VectorConfig logmap(const TupleConfig& c0, const TupleConfig& cp) { return c0.logmap(cp); } /** * Wrapper classes to act as containers for configs. Note that these can be cascaded * recursively, as they are TupleConfigs, and are primarily a short form of the config * structure to make use of the TupleConfigs easier. * * The interface is designed to mimic PairConfig, but for 2-6 config types. */ template class TupleConfig1 : public TupleConfigEnd { public: // typedefs typedef C1 Config1; typedef TupleConfigEnd Base; typedef TupleConfig1 This; TupleConfig1() {} TupleConfig1(const This& config); TupleConfig1(const Base& config); TupleConfig1(const Config1& cfg1); // access functions inline const Config1& first() const { return this->config(); } }; template TupleConfig1 expmap(const TupleConfig1& c, const VectorConfig& delta) { return c.expmap(delta); } template VectorConfig logmap(const TupleConfig1& c1, const TupleConfig1& c2) { return c1.logmap(c2); } template class TupleConfig2 : public TupleConfig > { public: // typedefs typedef C1 Config1; typedef C2 Config2; typedef TupleConfig > Base; typedef TupleConfig2 This; TupleConfig2() {} TupleConfig2(const This& config); TupleConfig2(const Base& config); TupleConfig2(const Config1& cfg1, const Config2& cfg2); // access functions inline const Config1& first() const { return this->config(); } inline const Config2& second() const { return this->rest().config(); } }; template TupleConfig2 expmap(const TupleConfig2& c, const VectorConfig& delta) { return c.expmap(delta); } template VectorConfig logmap(const TupleConfig2& c1, const TupleConfig2& c2) { return c1.logmap(c2); } template class TupleConfig3 : public TupleConfig > > { public: // typedefs typedef C1 Config1; typedef C2 Config2; typedef C3 Config3; TupleConfig3() {} TupleConfig3(const TupleConfig > >& config); TupleConfig3(const TupleConfig3& config); TupleConfig3(const Config1& cfg1, const Config2& cfg2, const Config3& cfg3); // access functions inline const Config1& first() const { return this->config(); } inline const Config2& second() const { return this->rest().config(); } inline const Config3& third() const { return this->rest().rest().config(); } }; template TupleConfig3 expmap(const TupleConfig3& c, const VectorConfig& delta) { return c.expmap(delta); } template class TupleConfig4 : public TupleConfig > > > { public: // typedefs typedef C1 Config1; typedef C2 Config2; typedef C3 Config3; typedef C4 Config4; typedef TupleConfig > > > Base; typedef TupleConfig4 This; TupleConfig4() {} TupleConfig4(const This& config); TupleConfig4(const Base& config); TupleConfig4(const Config1& cfg1, const Config2& cfg2, const Config3& cfg3,const Config4& cfg4); // access functions inline const Config1& first() const { return this->config(); } inline const Config2& second() const { return this->rest().config(); } inline const Config3& third() const { return this->rest().rest().config(); } inline const Config4& fourth() const { return this->rest().rest().rest().config(); } }; template TupleConfig4 expmap(const TupleConfig4& c, const VectorConfig& delta) { return c.expmap(delta); } template class TupleConfig5 : public TupleConfig > > > > { public: // typedefs typedef C1 Config1; typedef C2 Config2; typedef C3 Config3; typedef C4 Config4; typedef C5 Config5; TupleConfig5() {} TupleConfig5(const TupleConfig5& config); TupleConfig5(const TupleConfig > > > >& config); TupleConfig5(const Config1& cfg1, const Config2& cfg2, const Config3& cfg3, const Config4& cfg4, const Config5& cfg5); // access functions inline const Config1& first() const { return this->config(); } inline const Config2& second() const { return this->rest().config(); } inline const Config3& third() const { return this->rest().rest().config(); } inline const Config4& fourth() const { return this->rest().rest().rest().config(); } inline const Config5& fifth() const { return this->rest().rest().rest().rest().config(); } }; template TupleConfig5 expmap(const TupleConfig5& c, const VectorConfig& delta) { return c.expmap(delta); } template class TupleConfig6 : public TupleConfig > > > > > { public: // typedefs typedef C1 Config1; typedef C2 Config2; typedef C3 Config3; typedef C4 Config4; typedef C5 Config5; typedef C6 Config6; TupleConfig6() {} TupleConfig6(const TupleConfig6& config); TupleConfig6(const TupleConfig > > > > >& config); TupleConfig6(const Config1& cfg1, const Config2& cfg2, const Config3& cfg3, const Config4& cfg4, const Config5& cfg5, const Config6& cfg6); // access functions inline const Config1& first() const { return this->config(); } inline const Config2& second() const { return this->rest().config(); } inline const Config3& third() const { return this->rest().rest().config(); } inline const Config4& fourth() const { return this->rest().rest().rest().config(); } inline const Config5& fifth() const { return this->rest().rest().rest().rest().config(); } inline const Config6& sixth() const { return this->rest().rest().rest().rest().rest().config(); } }; template TupleConfig6 expmap(const TupleConfig6& c, const VectorConfig& delta) { return c.expmap(delta); } }