Deprecated boost iterators in Values

release/4.3a0
Frank Dellaert 2023-01-22 12:18:09 -08:00
parent 9bca36fd2c
commit ae63321d1b
33 changed files with 359 additions and 332 deletions

View File

@ -43,9 +43,9 @@ int main(const int argc, const char* argv[]) {
auto priorModel = noiseModel::Diagonal::Variances( auto priorModel = noiseModel::Diagonal::Variances(
(Vector(6) << 1e-6, 1e-6, 1e-6, 1e-4, 1e-4, 1e-4).finished()); (Vector(6) << 1e-6, 1e-6, 1e-6, 1e-4, 1e-4, 1e-4).finished());
Key firstKey = 0; Key firstKey = 0;
for (const auto key_value : *initial) { for (const auto key : initial->keys()) {
std::cout << "Adding prior to g2o file " << std::endl; std::cout << "Adding prior to g2o file " << std::endl;
firstKey = key_value.key; firstKey = key;
graph->addPrior(firstKey, Pose3(), priorModel); graph->addPrior(firstKey, Pose3(), priorModel);
break; break;
} }
@ -74,10 +74,8 @@ int main(const int argc, const char* argv[]) {
// Calculate and print marginal covariances for all variables // Calculate and print marginal covariances for all variables
Marginals marginals(*graph, result); Marginals marginals(*graph, result);
for (const auto key_value : result) { for (const auto& key_pose : result.extract<Pose3>()) {
auto p = dynamic_cast<const GenericValue<Pose3>*>(&key_value.value); std::cout << marginals.marginalCovariance(key_pose.first) << endl;
if (!p) continue;
std::cout << marginals.marginalCovariance(key_value.key) << endl;
} }
return 0; return 0;
} }

View File

@ -55,14 +55,14 @@ int main(const int argc, const char *argv[]) {
std::cout << "Rewriting input to file: " << inputFileRewritten << std::endl; std::cout << "Rewriting input to file: " << inputFileRewritten << std::endl;
// Additional: rewrite input with simplified keys 0,1,... // Additional: rewrite input with simplified keys 0,1,...
Values simpleInitial; Values simpleInitial;
for(const auto key_value: *initial) { for (const auto k : initial->keys()) {
Key key; Key key;
if(add) if (add)
key = key_value.key + firstKey; key = k + firstKey;
else else
key = key_value.key - firstKey; key = k - firstKey;
simpleInitial.insert(key, initial->at(key_value.key)); simpleInitial.insert(key, initial->at(k));
} }
NonlinearFactorGraph simpleGraph; NonlinearFactorGraph simpleGraph;
for(const boost::shared_ptr<NonlinearFactor>& factor: *graph) { for(const boost::shared_ptr<NonlinearFactor>& factor: *graph) {

View File

@ -42,9 +42,9 @@ int main(const int argc, const char* argv[]) {
auto priorModel = noiseModel::Diagonal::Variances( auto priorModel = noiseModel::Diagonal::Variances(
(Vector(6) << 1e-6, 1e-6, 1e-6, 1e-4, 1e-4, 1e-4).finished()); (Vector(6) << 1e-6, 1e-6, 1e-6, 1e-4, 1e-4, 1e-4).finished());
Key firstKey = 0; Key firstKey = 0;
for (const auto key_value : *initial) { for (const auto key : initial->keys()) {
std::cout << "Adding prior to g2o file " << std::endl; std::cout << "Adding prior to g2o file " << std::endl;
firstKey = key_value.key; firstKey = key;
graph->addPrior(firstKey, Pose3(), priorModel); graph->addPrior(firstKey, Pose3(), priorModel);
break; break;
} }

View File

@ -42,9 +42,9 @@ int main(const int argc, const char* argv[]) {
auto priorModel = noiseModel::Diagonal::Variances( auto priorModel = noiseModel::Diagonal::Variances(
(Vector(6) << 1e-6, 1e-6, 1e-6, 1e-4, 1e-4, 1e-4).finished()); (Vector(6) << 1e-6, 1e-6, 1e-6, 1e-4, 1e-4, 1e-4).finished());
Key firstKey = 0; Key firstKey = 0;
for (const auto key_value : *initial) { for (const auto key : initial->keys()) {
std::cout << "Adding prior to g2o file " << std::endl; std::cout << "Adding prior to g2o file " << std::endl;
firstKey = key_value.key; firstKey = key;
graph->addPrior(firstKey, Pose3(), priorModel); graph->addPrior(firstKey, Pose3(), priorModel);
break; break;
} }

View File

@ -42,9 +42,9 @@ int main(const int argc, const char* argv[]) {
auto priorModel = noiseModel::Diagonal::Variances( auto priorModel = noiseModel::Diagonal::Variances(
(Vector(6) << 1e-6, 1e-6, 1e-6, 1e-4, 1e-4, 1e-4).finished()); (Vector(6) << 1e-6, 1e-6, 1e-6, 1e-4, 1e-4, 1e-4).finished());
Key firstKey = 0; Key firstKey = 0;
for (const auto key_value : *initial) { for (const auto key : initial->keys()) {
std::cout << "Adding prior to g2o file " << std::endl; std::cout << "Adding prior to g2o file " << std::endl;
firstKey = key_value.key; firstKey = key;
graph->addPrior(firstKey, Pose3(), priorModel); graph->addPrior(firstKey, Pose3(), priorModel);
break; break;
} }

View File

@ -559,12 +559,12 @@ void runPerturb()
// Perturb values // Perturb values
VectorValues noise; VectorValues noise;
for(const Values::KeyValuePair key_val: initial) for(const auto& key_dim: initial.dims())
{ {
Vector noisev(key_val.value.dim()); Vector noisev(key_dim.second);
for(Vector::Index i = 0; i < noisev.size(); ++i) for(Vector::Index i = 0; i < noisev.size(); ++i)
noisev(i) = normal(rng); noisev(i) = normal(rng);
noise.insert(key_val.key, noisev); noise.insert(key_dim.first, noisev);
} }
Values perturbed = initial.retract(noise); Values perturbed = initial.retract(noise);

View File

@ -102,7 +102,7 @@ class GTSAM_EXPORT HybridValues {
/// Check whether a variable with key \c j exists in values. /// Check whether a variable with key \c j exists in values.
bool existsNonlinear(Key j) { bool existsNonlinear(Key j) {
return (nonlinear_.find(j) != nonlinear_.end()); return nonlinear_.exists(j);
}; };
/// Check whether a variable with key \c j exists. /// Check whether a variable with key \c j exists.

View File

@ -129,10 +129,7 @@ TEST(HybridBayesNet, evaluateHybrid) {
TEST(HybridBayesNet, Choose) { TEST(HybridBayesNet, Choose) {
Switching s(4); Switching s(4);
Ordering ordering; const Ordering ordering(s.linearizationPoint.keys());
for (auto&& kvp : s.linearizationPoint) {
ordering += kvp.key;
}
HybridBayesNet::shared_ptr hybridBayesNet; HybridBayesNet::shared_ptr hybridBayesNet;
HybridGaussianFactorGraph::shared_ptr remainingFactorGraph; HybridGaussianFactorGraph::shared_ptr remainingFactorGraph;
@ -163,10 +160,7 @@ TEST(HybridBayesNet, Choose) {
TEST(HybridBayesNet, OptimizeAssignment) { TEST(HybridBayesNet, OptimizeAssignment) {
Switching s(4); Switching s(4);
Ordering ordering; const Ordering ordering(s.linearizationPoint.keys());
for (auto&& kvp : s.linearizationPoint) {
ordering += kvp.key;
}
HybridBayesNet::shared_ptr hybridBayesNet; HybridBayesNet::shared_ptr hybridBayesNet;
HybridGaussianFactorGraph::shared_ptr remainingFactorGraph; HybridGaussianFactorGraph::shared_ptr remainingFactorGraph;

View File

@ -436,36 +436,6 @@ struct GTSAM_EXPORT UpdateImpl {
} }
} }
/**
* Apply expmap to the given values, but only for indices appearing in
* \c mask. Values are expmapped in-place.
* \param mask Mask on linear indices, only \c true entries are expmapped
*/
static void ExpmapMasked(const VectorValues& delta, const KeySet& mask,
Values* theta) {
gttic(ExpmapMasked);
assert(theta->size() == delta.size());
Values::iterator key_value;
VectorValues::const_iterator key_delta;
#ifdef GTSAM_USE_TBB
for (key_value = theta->begin(); key_value != theta->end(); ++key_value) {
key_delta = delta.find(key_value->key);
#else
for (key_value = theta->begin(), key_delta = delta.begin();
key_value != theta->end(); ++key_value, ++key_delta) {
assert(key_value->key == key_delta->first);
#endif
Key var = key_value->key;
assert(static_cast<size_t>(delta[var].size()) == key_value->value.dim());
assert(delta[var].allFinite());
if (mask.exists(var)) {
Value* retracted = key_value->value.retract_(delta[var]);
key_value->value = *retracted;
retracted->deallocate_();
}
}
}
// Linearize new factors // Linearize new factors
void linearizeNewFactors(const NonlinearFactorGraph& newFactors, void linearizeNewFactors(const NonlinearFactorGraph& newFactors,
const Values& theta, size_t numNonlinearFactors, const Values& theta, size_t numNonlinearFactors,

View File

@ -454,7 +454,7 @@ ISAM2Result ISAM2::update(const NonlinearFactorGraph& newFactors,
update.findFluid(roots_, relinKeys, &result.markedKeys, result.details()); update.findFluid(roots_, relinKeys, &result.markedKeys, result.details());
// 6. Update linearization point for marked variables: // 6. Update linearization point for marked variables:
// \Theta_{J}:=\Theta_{J}+\Delta_{J}. // \Theta_{J}:=\Theta_{J}+\Delta_{J}.
UpdateImpl::ExpmapMasked(delta_, relinKeys, &theta_); theta_.retractMasked(delta_, relinKeys);
} }
result.variablesRelinearized = result.markedKeys.size(); result.variablesRelinearized = result.markedKeys.size();
} }

View File

@ -285,8 +285,8 @@ static Scatter scatterFromValues(const Values& values) {
scatter.reserve(values.size()); scatter.reserve(values.size());
// use "natural" ordering with keys taken from the initial values // use "natural" ordering with keys taken from the initial values
for (const auto key_value : values) { for (const auto& key_dim : values.dims()) {
scatter.add(key_value.key, key_value.value.dim()); scatter.add(key_dim.first, key_dim.second);
} }
return scatter; return scatter;

View File

@ -24,12 +24,10 @@
#pragma once #pragma once
#include <gtsam/nonlinear/Values.h>
#include <utility> #include <utility>
#include <boost/bind/bind.hpp>
#include <gtsam/nonlinear/Values.h> // Only so Eclipse finds class definition
namespace gtsam { namespace gtsam {
@ -95,13 +93,13 @@ namespace gtsam {
std::map<Key, ValueType> std::map<Key, ValueType>
Values::extract(const std::function<bool(Key)>& filterFcn) const { Values::extract(const std::function<bool(Key)>& filterFcn) const {
std::map<Key, ValueType> result; std::map<Key, ValueType> result;
for (const auto& key_value : *this) { for (const auto& key_value : values_) {
// Check if key matches // Check if key matches
if (filterFcn(key_value.key)) { if (filterFcn(key_value.first)) {
// Check if type matches (typically does as symbols matched with types) // Check if type matches (typically does as symbols matched with types)
if (auto t = if (auto t =
dynamic_cast<const GenericValue<ValueType>*>(&key_value.value)) dynamic_cast<const GenericValue<ValueType>*>(key_value.second))
result[key_value.key] = t->value(); result[key_value.first] = t->value();
} }
} }
return result; return result;
@ -109,6 +107,8 @@ namespace gtsam {
/* ************************************************************************* */ /* ************************************************************************* */
#ifdef GTSAM_ALLOW_DEPRECATED_SINCE_V42 #ifdef GTSAM_ALLOW_DEPRECATED_SINCE_V42
#include <boost/bind/bind.hpp>
template<class ValueType> template<class ValueType>
class Values::Filtered { class Values::Filtered {
public: public:

View File

@ -25,8 +25,6 @@
#include <gtsam/nonlinear/Values.h> #include <gtsam/nonlinear/Values.h>
#include <gtsam/linear/VectorValues.h> #include <gtsam/linear/VectorValues.h>
#include <boost/iterator/transform_iterator.hpp>
#include <list> #include <list>
#include <memory> #include <memory>
#include <sstream> #include <sstream>
@ -52,15 +50,15 @@ namespace gtsam {
/* ************************************************************************* */ /* ************************************************************************* */
Values::Values(const Values& other, const VectorValues& delta) { Values::Values(const Values& other, const VectorValues& delta) {
for (const_iterator key_value = other.begin(); key_value != other.end(); ++key_value) { for (const auto& key_value : other.values_) {
VectorValues::const_iterator it = delta.find(key_value->key); VectorValues::const_iterator it = delta.find(key_value.first);
Key key = key_value->key; // Non-const duplicate to deal with non-const insert argument Key key = key_value.first; // Non-const duplicate to deal with non-const insert argument
if (it != delta.end()) { if (it != delta.end()) {
const Vector& v = it->second; const Vector& v = it->second;
Value* retractedValue(key_value->value.retract_(v)); // Retract Value* retractedValue(key_value.second->retract_(v)); // Retract
values_.insert(key, retractedValue); // Add retracted result directly to result values values_.insert(key, retractedValue); // Add retracted result directly to result values
} else { } else {
values_.insert(key, key_value->value.clone_()); // Add original version to result values values_.insert(key, key_value.second->clone_()); // Add original version to result values
} }
} }
} }
@ -69,9 +67,9 @@ namespace gtsam {
void Values::print(const string& str, const KeyFormatter& keyFormatter) const { void Values::print(const string& str, const KeyFormatter& keyFormatter) const {
cout << str << (str.empty() ? "" : "\n"); cout << str << (str.empty() ? "" : "\n");
cout << "Values with " << size() << " values:\n"; cout << "Values with " << size() << " values:\n";
for(const_iterator key_value = begin(); key_value != end(); ++key_value) { for (const auto& key_value : values_) {
cout << "Value " << keyFormatter(key_value->key) << ": "; cout << "Value " << keyFormatter(key_value.first) << ": ";
key_value->value.print(""); key_value.second->print("");
cout << "\n"; cout << "\n";
} }
} }
@ -80,12 +78,12 @@ namespace gtsam {
bool Values::equals(const Values& other, double tol) const { bool Values::equals(const Values& other, double tol) const {
if (this->size() != other.size()) if (this->size() != other.size())
return false; return false;
for (const_iterator it1 = this->begin(), it2 = other.begin(); for (auto it1 = values_.begin(), it2 = other.values_.begin();
it1 != this->end(); ++it1, ++it2) { it1 != values_.end(); ++it1, ++it2) {
const Value& value1 = it1->value; const Value* value1 = it1->second;
const Value& value2 = it2->value; const Value* value2 = it2->second;
if (typeid(value1) != typeid(value2) || it1->key != it2->key if (typeid(*value1) != typeid(*value2) || it1->first != it2->first
|| !value1.equals_(value2, tol)) { || !value1->equals_(*value2, tol)) {
return false; return false;
} }
} }
@ -102,17 +100,44 @@ namespace gtsam {
return Values(*this, delta); return Values(*this, delta);
} }
/* ************************************************************************* */
void Values::retractMasked(const VectorValues& delta, const KeySet& mask) {
gttic(retractMasked);
assert(theta->size() == delta.size());
auto key_value = values_.begin();
VectorValues::const_iterator key_delta;
#ifdef GTSAM_USE_TBB
for (; key_value != values_.end(); ++key_value) {
key_delta = delta.find(key_value.first);
#else
for (key_delta = delta.begin(); key_value != values_.end();
++key_value, ++key_delta) {
assert(key_value.first == key_delta->first);
#endif
Key var = key_value->first;
assert(static_cast<size_t>(delta[var].size()) == key_value->second->dim());
assert(delta[var].allFinite());
if (mask.exists(var)) {
Value* retracted = key_value->second->retract_(delta[var]);
// TODO(dellaert): can we use std::move here?
*(key_value->second) = *retracted;
retracted->deallocate_();
}
}
}
/* ************************************************************************* */ /* ************************************************************************* */
VectorValues Values::localCoordinates(const Values& cp) const { VectorValues Values::localCoordinates(const Values& cp) const {
if(this->size() != cp.size()) if(this->size() != cp.size())
throw DynamicValuesMismatched(); throw DynamicValuesMismatched();
VectorValues result; VectorValues result;
for(const_iterator it1=this->begin(), it2=cp.begin(); it1!=this->end(); ++it1, ++it2) { for (auto it1 = values_.begin(), it2 = cp.values_.begin();
if(it1->key != it2->key) it1 != values_.end(); ++it1, ++it2) {
if(it1->first != it2->first)
throw DynamicValuesMismatched(); // If keys do not match throw DynamicValuesMismatched(); // If keys do not match
// Will throw a dynamic_cast exception if types do not match // Will throw a dynamic_cast exception if types do not match
// NOTE: this is separate from localCoordinates(cp, ordering, result) due to at() vs. insert // NOTE: this is separate from localCoordinates(cp, ordering, result) due to at() vs. insert
result.insert(it1->key, it1->value.localCoordinates_(it2->value)); result.insert(it1->first, it1->second->localCoordinates_(*it2->second));
} }
return result; return result;
} }
@ -130,24 +155,26 @@ namespace gtsam {
/* ************************************************************************* */ /* ************************************************************************* */
void Values::insert(Key j, const Value& val) { void Values::insert(Key j, const Value& val) {
std::pair<iterator,bool> insertResult = tryInsert(j, val); auto insertResult = values_.insert(j, val.clone_());
if(!insertResult.second) if(!insertResult.second)
throw ValuesKeyAlreadyExists(j); throw ValuesKeyAlreadyExists(j);
} }
/* ************************************************************************* */ /* ************************************************************************* */
void Values::insert(const Values& values) { void Values::insert(const Values& other) {
for(const_iterator key_value = values.begin(); key_value != values.end(); ++key_value) { for (auto key_value = other.values_.begin();
Key key = key_value->key; // Non-const duplicate to deal with non-const insert argument key_value != other.values_.end(); ++key_value) {
insert(key, key_value->value); insert(key_value->first, *(key_value->second));
} }
} }
/* ************************************************************************* */ /* ************************************************************************* */
#ifdef GTSAM_ALLOW_DEPRECATED_SINCE_V42
std::pair<Values::iterator, bool> Values::tryInsert(Key j, const Value& value) { std::pair<Values::iterator, bool> Values::tryInsert(Key j, const Value& value) {
std::pair<KeyValueMap::iterator, bool> result = values_.insert(j, value.clone_()); std::pair<KeyValueMap::iterator, bool> result = values_.insert(j, value.clone_());
return std::make_pair(boost::make_transform_iterator(result.first, &make_deref_pair), result.second); return std::make_pair(boost::make_transform_iterator(result.first, &make_deref_pair), result.second);
} }
#endif
/* ************************************************************************* */ /* ************************************************************************* */
void Values::update(Key j, const Value& val) { void Values::update(Key j, const Value& val) {
@ -165,9 +192,10 @@ namespace gtsam {
} }
/* ************************************************************************* */ /* ************************************************************************* */
void Values::update(const Values& values) { void Values::update(const Values& other) {
for(const_iterator key_value = values.begin(); key_value != values.end(); ++key_value) { for (auto key_value = other.values_.begin();
this->update(key_value->key, key_value->value); key_value != other.values_.end(); ++key_value) {
this->update(key_value->first, *(key_value->second));
} }
} }
@ -183,10 +211,10 @@ namespace gtsam {
} }
/* ************************************************************************ */ /* ************************************************************************ */
void Values::insert_or_assign(const Values& values) { void Values::insert_or_assign(const Values& other) {
for (const_iterator key_value = values.begin(); key_value != values.end(); for (auto key_value = other.values_.begin();
++key_value) { key_value != other.values_.end(); ++key_value) {
this->insert_or_assign(key_value->key, key_value->value); this->insert_or_assign(key_value->first, *(key_value->second));
} }
} }
@ -202,8 +230,16 @@ namespace gtsam {
KeyVector Values::keys() const { KeyVector Values::keys() const {
KeyVector result; KeyVector result;
result.reserve(size()); result.reserve(size());
for(const_iterator key_value = begin(); key_value != end(); ++key_value) for(const auto& key_value: values_)
result.push_back(key_value->key); result.push_back(key_value.first);
return result;
}
/* ************************************************************************* */
KeySet Values::keySet() const {
KeySet result;
for(const auto& key_value: values_)
result.insert(key_value.first);
return result; return result;
} }
@ -217,8 +253,17 @@ namespace gtsam {
/* ************************************************************************* */ /* ************************************************************************* */
size_t Values::dim() const { size_t Values::dim() const {
size_t result = 0; size_t result = 0;
for(const auto key_value: *this) { for (const auto key_value : values_) {
result += key_value.value.dim(); result += key_value->second->dim();
}
return result;
}
/* ************************************************************************* */
std::map<Key,size_t> Values::dims() const {
std::map<Key,size_t> result;
for (const auto key_value : values_) {
result.emplace(key_value->first, key_value->second->dim());
} }
return result; return result;
} }
@ -226,8 +271,8 @@ namespace gtsam {
/* ************************************************************************* */ /* ************************************************************************* */
VectorValues Values::zeroVectors() const { VectorValues Values::zeroVectors() const {
VectorValues result; VectorValues result;
for(const auto key_value: *this) for (const auto key_value : values_)
result.insert(key_value.key, Vector::Zero(key_value.value.dim())); result.insert(key_value->first, Vector::Zero(key_value->second->dim()));
return result; return result;
} }

View File

@ -28,10 +28,10 @@
#include <gtsam/base/GenericValue.h> #include <gtsam/base/GenericValue.h>
#include <gtsam/base/VectorSpace.h> #include <gtsam/base/VectorSpace.h>
#include <gtsam/inference/Key.h> #include <gtsam/inference/Key.h>
#include <boost/iterator/transform_iterator.hpp>
#include <boost/ptr_container/serialize_ptr_map.hpp> #include <boost/ptr_container/serialize_ptr_map.hpp>
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
#ifdef GTSAM_ALLOW_DEPRECATED_SINCE_V42 #ifdef GTSAM_ALLOW_DEPRECATED_SINCE_V42
#include <boost/iterator/transform_iterator.hpp>
#include <boost/iterator/filter_iterator.hpp> #include <boost/iterator/filter_iterator.hpp>
#endif #endif
@ -81,10 +81,6 @@ namespace gtsam {
// The member to store the values, see just above // The member to store the values, see just above
KeyValueMap values_; KeyValueMap values_;
// Types obtained by iterating
typedef KeyValueMap::const_iterator::value_type ConstKeyValuePtrPair;
typedef KeyValueMap::iterator::value_type KeyValuePtrPair;
public: public:
/// A shared_ptr to this class /// A shared_ptr to this class
@ -110,22 +106,6 @@ namespace gtsam {
ConstKeyValuePair(const KeyValuePair& kv) : key(kv.key), value(kv.value) {} ConstKeyValuePair(const KeyValuePair& kv) : key(kv.key), value(kv.value) {}
}; };
/// Mutable forward iterator, with value type KeyValuePair
typedef boost::transform_iterator<
std::function<KeyValuePair(const KeyValuePtrPair&)>, KeyValueMap::iterator> iterator;
/// Const forward iterator, with value type ConstKeyValuePair
typedef boost::transform_iterator<
std::function<ConstKeyValuePair(const ConstKeyValuePtrPair&)>, KeyValueMap::const_iterator> const_iterator;
/// Mutable reverse iterator, with value type KeyValuePair
typedef boost::transform_iterator<
std::function<KeyValuePair(const KeyValuePtrPair&)>, KeyValueMap::reverse_iterator> reverse_iterator;
/// Const reverse iterator, with value type ConstKeyValuePair
typedef boost::transform_iterator<
std::function<ConstKeyValuePair(const ConstKeyValuePtrPair&)>, KeyValueMap::const_reverse_iterator> const_reverse_iterator;
typedef KeyValuePair value_type; typedef KeyValuePair value_type;
/** Default constructor creates an empty Values class */ /** Default constructor creates an empty Values class */
@ -191,47 +171,24 @@ namespace gtsam {
template<typename ValueType> template<typename ValueType>
boost::optional<const ValueType&> exists(Key j) const; boost::optional<const ValueType&> exists(Key j) const;
/** Find an element by key, returning an iterator, or end() if the key was
* not found. */
iterator find(Key j) { return boost::make_transform_iterator(values_.find(j), &make_deref_pair); }
/** Find an element by key, returning an iterator, or end() if the key was
* not found. */
const_iterator find(Key j) const { return boost::make_transform_iterator(values_.find(j), &make_const_deref_pair); }
/** Find the element greater than or equal to the specified key. */
iterator lower_bound(Key j) { return boost::make_transform_iterator(values_.lower_bound(j), &make_deref_pair); }
/** Find the element greater than or equal to the specified key. */
const_iterator lower_bound(Key j) const { return boost::make_transform_iterator(values_.lower_bound(j), &make_const_deref_pair); }
/** Find the lowest-ordered element greater than the specified key. */
iterator upper_bound(Key j) { return boost::make_transform_iterator(values_.upper_bound(j), &make_deref_pair); }
/** Find the lowest-ordered element greater than the specified key. */
const_iterator upper_bound(Key j) const { return boost::make_transform_iterator(values_.upper_bound(j), &make_const_deref_pair); }
/** The number of variables in this config */ /** The number of variables in this config */
size_t size() const { return values_.size(); } size_t size() const { return values_.size(); }
/** whether the config is empty */ /** whether the config is empty */
bool empty() const { return values_.empty(); } bool empty() const { return values_.empty(); }
const_iterator begin() const { return boost::make_transform_iterator(values_.begin(), &make_const_deref_pair); }
const_iterator end() const { return boost::make_transform_iterator(values_.end(), &make_const_deref_pair); }
iterator begin() { return boost::make_transform_iterator(values_.begin(), &make_deref_pair); }
iterator end() { return boost::make_transform_iterator(values_.end(), &make_deref_pair); }
const_reverse_iterator rbegin() const { return boost::make_transform_iterator(values_.rbegin(), &make_const_deref_pair); }
const_reverse_iterator rend() const { return boost::make_transform_iterator(values_.rend(), &make_const_deref_pair); }
reverse_iterator rbegin() { return boost::make_transform_iterator(values_.rbegin(), &make_deref_pair); }
reverse_iterator rend() { return boost::make_transform_iterator(values_.rend(), &make_deref_pair); }
/// @name Manifold Operations /// @name Manifold Operations
/// @{ /// @{
/** Add a delta config to current config and returns a new config */ /** Add a delta config to current config and returns a new config */
Values retract(const VectorValues& delta) const; Values retract(const VectorValues& delta) const;
/**
* Retract, but only for Keys appearing in \c mask. In-place.
* \param mask Mask on Keys where to apply retract.
*/
void retractMasked(const VectorValues& delta, const KeySet& mask);
/** Get a delta config about a linearization point c0 (*this) */ /** Get a delta config about a linearization point c0 (*this) */
VectorValues localCoordinates(const Values& cp) const; VectorValues localCoordinates(const Values& cp) const;
@ -252,12 +209,6 @@ namespace gtsam {
/// version for double /// version for double
void insertDouble(Key j, double c) { insert<double>(j,c); } void insertDouble(Key j, double c) { insert<double>(j,c); }
/** insert that mimics the STL map insert - if the value already exists, the map is not modified
* and an iterator to the existing value is returned, along with 'false'. If the value did not
* exist, it is inserted and an iterator pointing to the new element, along with 'true', is
* returned. */
std::pair<iterator, bool> tryInsert(Key j, const Value& value);
/** single element change of existing element */ /** single element change of existing element */
void update(Key j, const Value& val); void update(Key j, const Value& val);
@ -288,11 +239,16 @@ namespace gtsam {
void erase(Key j); void erase(Key j);
/** /**
* Returns a set of keys in the config * Returns a vector of keys in the config.
* Note: by construction, the list is ordered * Note: by construction, the list is ordered
*/ */
KeyVector keys() const; KeyVector keys() const;
/**
* Returns a set of keys in the config.
*/
KeySet keySet() const;
/** Replace all keys and variables */ /** Replace all keys and variables */
Values& operator=(const Values& rhs); Values& operator=(const Values& rhs);
@ -305,6 +261,9 @@ namespace gtsam {
/** Compute the total dimensionality of all values (\f$ O(n) \f$) */ /** Compute the total dimensionality of all values (\f$ O(n) \f$) */
size_t dim() const; size_t dim() const;
/** Return all dimensions in a map (\f$ O(n log n) \f$) */
std::map<Key,size_t> dims() const;
/** Return a VectorValues of zero vectors for each variable in this Values */ /** Return a VectorValues of zero vectors for each variable in this Values */
VectorValues zeroVectors() const; VectorValues zeroVectors() const;
@ -312,8 +271,8 @@ namespace gtsam {
template<class ValueType> template<class ValueType>
size_t count() const { size_t count() const {
size_t i = 0; size_t i = 0;
for (const auto key_value : *this) { for (const auto key_value : values_) {
if (dynamic_cast<const GenericValue<ValueType>*>(&key_value.value)) if (dynamic_cast<const GenericValue<ValueType>*>(key_value.second))
++i; ++i;
} }
return i; return i;
@ -343,6 +302,67 @@ namespace gtsam {
extract(const std::function<bool(Key)>& filterFcn = &_truePredicate<Key>) const; extract(const std::function<bool(Key)>& filterFcn = &_truePredicate<Key>) const;
#ifdef GTSAM_ALLOW_DEPRECATED_SINCE_V42 #ifdef GTSAM_ALLOW_DEPRECATED_SINCE_V42
// Types obtained by iterating
typedef KeyValueMap::const_iterator::value_type ConstKeyValuePtrPair;
typedef KeyValueMap::iterator::value_type KeyValuePtrPair;
/** insert that mimics the STL map insert - if the value already exists, the map is not modified
* and an iterator to the existing value is returned, along with 'false'. If the value did not
* exist, it is inserted and an iterator pointing to the new element, along with 'true', is
* returned. */
std::pair<iterator, bool> tryInsert(Key j, const Value& value);
/// Mutable forward iterator, with value type KeyValuePair
typedef boost::transform_iterator<
std::function<KeyValuePair(const KeyValuePtrPair&)>, KeyValueMap::iterator> iterator;
/// Const forward iterator, with value type ConstKeyValuePair
typedef boost::transform_iterator<
std::function<ConstKeyValuePair(const ConstKeyValuePtrPair&)>, KeyValueMap::const_iterator> const_iterator;
/// Mutable reverse iterator, with value type KeyValuePair
typedef boost::transform_iterator<
std::function<KeyValuePair(const KeyValuePtrPair&)>, KeyValueMap::reverse_iterator> reverse_iterator;
/// Const reverse iterator, with value type ConstKeyValuePair
typedef boost::transform_iterator<
std::function<ConstKeyValuePair(const ConstKeyValuePtrPair&)>, KeyValueMap::const_reverse_iterator> const_reverse_iterator;
static ConstKeyValuePair make_const_deref_pair(const KeyValueMap::const_iterator::value_type& key_value) {
return ConstKeyValuePair(key_value.first, *key_value.second); }
static KeyValuePair make_deref_pair(const KeyValueMap::iterator::value_type& key_value) {
return KeyValuePair(key_value.first, *key_value.second); }
const_iterator begin() const { return boost::make_transform_iterator(values_.begin(), &make_const_deref_pair); }
const_iterator end() const { return boost::make_transform_iterator(values_.end(), &make_const_deref_pair); }
iterator begin() { return boost::make_transform_iterator(values_.begin(), &make_deref_pair); }
iterator end() { return boost::make_transform_iterator(values_.end(), &make_deref_pair); }
const_reverse_iterator rbegin() const { return boost::make_transform_iterator(values_.rbegin(), &make_const_deref_pair); }
const_reverse_iterator rend() const { return boost::make_transform_iterator(values_.rend(), &make_const_deref_pair); }
reverse_iterator rbegin() { return boost::make_transform_iterator(values_.rbegin(), &make_deref_pair); }
reverse_iterator rend() { return boost::make_transform_iterator(values_.rend(), &make_deref_pair); }
/** Find an element by key, returning an iterator, or end() if the key was
* not found. */
iterator find(Key j) { return boost::make_transform_iterator(values_.find(j), &make_deref_pair); }
/** Find an element by key, returning an iterator, or end() if the key was
* not found. */
const_iterator find(Key j) const { return boost::make_transform_iterator(values_.find(j), &make_const_deref_pair); }
/** Find the element greater than or equal to the specified key. */
iterator lower_bound(Key j) { return boost::make_transform_iterator(values_.lower_bound(j), &make_deref_pair); }
/** Find the element greater than or equal to the specified key. */
const_iterator lower_bound(Key j) const { return boost::make_transform_iterator(values_.lower_bound(j), &make_const_deref_pair); }
/** Find the lowest-ordered element greater than the specified key. */
iterator upper_bound(Key j) { return boost::make_transform_iterator(values_.upper_bound(j), &make_deref_pair); }
/** Find the lowest-ordered element greater than the specified key. */
const_iterator upper_bound(Key j) const { return boost::make_transform_iterator(values_.upper_bound(j), &make_const_deref_pair); }
/** A filtered view of a Values, returned from Values::filter. */ /** A filtered view of a Values, returned from Values::filter. */
template <class ValueType = Value> template <class ValueType = Value>
class Filtered; class Filtered;
@ -395,12 +415,6 @@ namespace gtsam {
ar & BOOST_SERIALIZATION_NVP(values_); ar & BOOST_SERIALIZATION_NVP(values_);
} }
static ConstKeyValuePair make_const_deref_pair(const KeyValueMap::const_iterator::value_type& key_value) {
return ConstKeyValuePair(key_value.first, *key_value.second); }
static KeyValuePair make_deref_pair(const KeyValueMap::iterator::value_type& key_value) {
return KeyValuePair(key_value.first, *key_value.second); }
}; };
/* ************************************************************************* */ /* ************************************************************************* */

View File

@ -128,9 +128,10 @@ struct LevenbergMarquardtState : public NonlinearOptimizerState {
noiseModelCache.resize(0); noiseModelCache.resize(0);
// for each of the variables, add a prior // for each of the variables, add a prior
damped.reserve(damped.size() + values.size()); damped.reserve(damped.size() + values.size());
for (const auto key_value : values) { std::map<Key,size_t> dims = values.dims();
const Key key = key_value.key; for (const auto& key_dim : dims) {
const size_t dim = key_value.value.dim(); const Key& key = key_dim.first;
const size_t& dim = key_dim.second;
const CachedModel* item = getCachedModel(dim); const CachedModel* item = getCachedModel(dim);
damped += boost::make_shared<JacobianFactor>(key, item->A, item->b, item->model); damped += boost::make_shared<JacobianFactor>(key, item->A, item->b, item->model);
} }

View File

@ -350,8 +350,8 @@ TEST(TestLinearContainerFactor, Rekey) {
// For extra fun lets try linearizing this LCF // For extra fun lets try linearizing this LCF
gtsam::Values linearization_pt_rekeyed; gtsam::Values linearization_pt_rekeyed;
for (auto key_val : linearization_pt) { for (auto key : linearization_pt.keys()) {
linearization_pt_rekeyed.insert(key_map.at(key_val.key), key_val.value); linearization_pt_rekeyed.insert(key_map.at(key), linearization_pt.at(key));
} }
// Check independent values since we don't want to unnecessarily sort // Check independent values since we don't want to unnecessarily sort

View File

@ -195,6 +195,7 @@ TEST(Values, basic_functions)
values.insert(6, M1); values.insert(6, M1);
values.insert(8, M2); values.insert(8, M2);
#ifdef GTSAM_ALLOW_DEPRECATED_SINCE_V42
// find // find
EXPECT_LONGS_EQUAL(4, values.find(4)->key); EXPECT_LONGS_EQUAL(4, values.find(4)->key);
EXPECT_LONGS_EQUAL(4, values_c.find(4)->key); EXPECT_LONGS_EQUAL(4, values_c.find(4)->key);
@ -210,7 +211,7 @@ TEST(Values, basic_functions)
EXPECT_LONGS_EQUAL(6, values_c.upper_bound(4)->key); EXPECT_LONGS_EQUAL(6, values_c.upper_bound(4)->key);
EXPECT_LONGS_EQUAL(4, values.upper_bound(3)->key); EXPECT_LONGS_EQUAL(4, values.upper_bound(3)->key);
EXPECT_LONGS_EQUAL(4, values_c.upper_bound(3)->key); EXPECT_LONGS_EQUAL(4, values_c.upper_bound(3)->key);
#endif
} }
/* ************************************************************************* */ /* ************************************************************************* */
@ -220,8 +221,8 @@ TEST(Values, retract_full)
config0.insert(key1, Vector3(1.0, 2.0, 3.0)); config0.insert(key1, Vector3(1.0, 2.0, 3.0));
config0.insert(key2, Vector3(5.0, 6.0, 7.0)); config0.insert(key2, Vector3(5.0, 6.0, 7.0));
VectorValues delta {{key1, Vector3(1.0, 1.1, 1.2)}, const VectorValues delta{{key1, Vector3(1.0, 1.1, 1.2)},
{key2, Vector3(1.3, 1.4, 1.5)}}; {key2, Vector3(1.3, 1.4, 1.5)}};
Values expected; Values expected;
expected.insert(key1, Vector3(2.0, 3.1, 4.2)); expected.insert(key1, Vector3(2.0, 3.1, 4.2));
@ -238,7 +239,7 @@ TEST(Values, retract_partial)
config0.insert(key1, Vector3(1.0, 2.0, 3.0)); config0.insert(key1, Vector3(1.0, 2.0, 3.0));
config0.insert(key2, Vector3(5.0, 6.0, 7.0)); config0.insert(key2, Vector3(5.0, 6.0, 7.0));
VectorValues delta {{key2, Vector3(1.3, 1.4, 1.5)}}; const VectorValues delta{{key2, Vector3(1.3, 1.4, 1.5)}};
Values expected; Values expected;
expected.insert(key1, Vector3(1.0, 2.0, 3.0)); expected.insert(key1, Vector3(1.0, 2.0, 3.0));
@ -248,6 +249,24 @@ TEST(Values, retract_partial)
CHECK(assert_equal(expected, Values(config0, delta))); CHECK(assert_equal(expected, Values(config0, delta)));
} }
/* ************************************************************************* */
TEST(Values, retract_masked)
{
Values config0;
config0.insert(key1, Vector3(1.0, 2.0, 3.0));
config0.insert(key2, Vector3(5.0, 6.0, 7.0));
const VectorValues delta{{key1, Vector3(1.0, 1.1, 1.2)},
{key2, Vector3(1.3, 1.4, 1.5)}};
Values expected;
expected.insert(key1, Vector3(1.0, 2.0, 3.0));
expected.insert(key2, Vector3(6.3, 7.4, 8.5));
config0.retractMasked(delta, {key2});
CHECK(assert_equal(expected, config0));
}
/* ************************************************************************* */ /* ************************************************************************* */
TEST(Values, equals) TEST(Values, equals)
{ {

View File

@ -62,10 +62,10 @@ static Values computePoses(const Values& initialRot,
// Upgrade rotations to full poses // Upgrade rotations to full poses
Values initialPose; Values initialPose;
for (const auto key_value : initialRot) { for (const auto& key_rot : initialRot.extract<typename Pose::Rotation>()) {
Key key = key_value.key; const Key& key = key_rot.first;
const auto& rot = initialRot.at<typename Pose::Rotation>(key); const auto& rot = key_rot.second;
Pose initializedPose = Pose(rot, origin); const Pose initializedPose(rot, origin);
initialPose.insert(key, initializedPose); initialPose.insert(key, initializedPose);
} }
@ -82,14 +82,14 @@ static Values computePoses(const Values& initialRot,
params.setVerbosity("TERMINATION"); params.setVerbosity("TERMINATION");
} }
GaussNewtonOptimizer optimizer(*posegraph, initialPose, params); GaussNewtonOptimizer optimizer(*posegraph, initialPose, params);
Values GNresult = optimizer.optimize(); const Values GNresult = optimizer.optimize();
// put into Values structure // put into Values structure
Values estimate; Values estimate;
for (const auto key_value : GNresult) { for (const auto& key_pose : GNresult.extract<Pose>()) {
Key key = key_value.key; const Key& key = key_pose.first;
if (key != kAnchorKey) { if (key != kAnchorKey) {
const Pose& pose = GNresult.at<Pose>(key); const Pose& pose = key_pose.second;
estimate.insert(key, pose); estimate.insert(key, pose);
} }
} }

View File

@ -122,12 +122,12 @@ Values InitializePose3::computeOrientationsGradient(
gttic(InitializePose3_computeOrientationsGradient); gttic(InitializePose3_computeOrientationsGradient);
// this works on the inverse rotations, according to Tron&Vidal,2011 // this works on the inverse rotations, according to Tron&Vidal,2011
Values inverseRot; std::map<Key,Rot3> inverseRot;
inverseRot.insert(initialize::kAnchorKey, Rot3()); inverseRot.emplace(initialize::kAnchorKey, Rot3());
for(const auto key_value: givenGuess) { for(const auto& key_pose: givenGuess.extract<Pose3>()) {
Key key = key_value.key; const Key& key = key_pose.first;
const Pose3& pose = givenGuess.at<Pose3>(key); const Pose3& pose = key_pose.second;
inverseRot.insert(key, pose.rotation().inverse()); inverseRot.emplace(key, pose.rotation().inverse());
} }
// Create the map of edges incident on each node // Create the map of edges incident on each node
@ -138,10 +138,8 @@ Values InitializePose3::computeOrientationsGradient(
// calculate max node degree & allocate gradient // calculate max node degree & allocate gradient
size_t maxNodeDeg = 0; size_t maxNodeDeg = 0;
VectorValues grad; for (const auto& key_R : inverseRot) {
for(const auto key_value: inverseRot) { const Key& key = key_R.first;
Key key = key_value.key;
grad.insert(key,Z_3x1);
size_t currNodeDeg = (adjEdgesMap.at(key)).size(); size_t currNodeDeg = (adjEdgesMap.at(key)).size();
if(currNodeDeg > maxNodeDeg) if(currNodeDeg > maxNodeDeg)
maxNodeDeg = currNodeDeg; maxNodeDeg = currNodeDeg;
@ -162,28 +160,29 @@ Values InitializePose3::computeOrientationsGradient(
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
// compute the gradient at each node // compute the gradient at each node
maxGrad = 0; maxGrad = 0;
for (const auto key_value : inverseRot) { VectorValues grad;
Key key = key_value.key; for (const auto& key_R : inverseRot) {
const Key& key = key_R.first;
const Rot3& Ri = key_R.second;
Vector gradKey = Z_3x1; Vector gradKey = Z_3x1;
// collect the gradient for each edge incident on key // collect the gradient for each edge incident on key
for (const size_t& factorId : adjEdgesMap.at(key)) { for (const size_t& factorId : adjEdgesMap.at(key)) {
Rot3 Rij = factorId2RotMap.at(factorId); const Rot3& Rij = factorId2RotMap.at(factorId);
Rot3 Ri = inverseRot.at<Rot3>(key);
auto factor = pose3Graph.at(factorId); auto factor = pose3Graph.at(factorId);
const auto& keys = factor->keys(); const auto& keys = factor->keys();
if (key == keys[0]) { if (key == keys[0]) {
Key key1 = keys[1]; Key key1 = keys[1];
Rot3 Rj = inverseRot.at<Rot3>(key1); const Rot3& Rj = inverseRot.at(key1);
gradKey = gradKey + gradientTron(Ri, Rij * Rj, a, b); gradKey = gradKey + gradientTron(Ri, Rij * Rj, a, b);
} else if (key == keys[1]) { } else if (key == keys[1]) {
Key key0 = keys[0]; Key key0 = keys[0];
Rot3 Rj = inverseRot.at<Rot3>(key0); const Rot3& Rj = inverseRot.at(key0);
gradKey = gradKey + gradientTron(Ri, Rij.between(Rj), a, b); gradKey = gradKey + gradientTron(Ri, Rij.between(Rj), a, b);
} else { } else {
cout << "Error in gradient computation" << endl; cout << "Error in gradient computation" << endl;
} }
} // end of i-th gradient computation } // end of i-th gradient computation
grad.at(key) = stepsize * gradKey; grad.insert(key, stepsize * gradKey);
double normGradKey = (gradKey).norm(); double normGradKey = (gradKey).norm();
if(normGradKey>maxGrad) if(normGradKey>maxGrad)
@ -192,8 +191,12 @@ Values InitializePose3::computeOrientationsGradient(
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
// update estimates // update estimates
inverseRot = inverseRot.retract(grad); for (auto& key_R : inverseRot) {
const Key& key = key_R.first;
Rot3& Ri = key_R.second;
Ri = Ri.retract(grad.at(key));
}
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
// check stopping condition // check stopping condition
if (it>20 && maxGrad < 5e-3) if (it>20 && maxGrad < 5e-3)
@ -201,12 +204,13 @@ Values InitializePose3::computeOrientationsGradient(
} // enf of gradient iterations } // enf of gradient iterations
// Return correct rotations // Return correct rotations
const Rot3& Rref = inverseRot.at<Rot3>(initialize::kAnchorKey); // This will be set to the identity as so far we included no prior const Rot3& Rref = inverseRot.at(initialize::kAnchorKey); // This will be set to the identity as so far we included no prior
Values estimateRot; Values estimateRot;
for(const auto key_value: inverseRot) { for (const auto key_R : inverseRot) {
Key key = key_value.key; const Key& key = key_R.first;
const Rot3& Ri = key_R.second;
if (key != initialize::kAnchorKey) { if (key != initialize::kAnchorKey) {
const Rot3& R = inverseRot.at<Rot3>(key); const Rot3& R = inverseRot.at(key);
if(setRefFrame) if(setRefFrame)
estimateRot.insert(key, Rref.compose(R.inverse())); estimateRot.insert(key, Rref.compose(R.inverse()));
else else

View File

@ -586,9 +586,9 @@ void save2D(const NonlinearFactorGraph &graph, const Values &config,
fstream stream(filename.c_str(), fstream::out); fstream stream(filename.c_str(), fstream::out);
// save poses // save poses
for (const auto key_value : config) { for (const auto &key_pose : config.extract<Pose2>()) {
const Pose2 &pose = key_value.value.cast<Pose2>(); const Pose2 &pose = key_pose.second;
stream << "VERTEX2 " << key_value.key << " " << pose.x() << " " << pose.y() stream << "VERTEX2 " << key_pose.first << " " << pose.x() << " " << pose.y()
<< " " << pose.theta() << endl; << " " << pose.theta() << endl;
} }
@ -635,45 +635,33 @@ void writeG2o(const NonlinearFactorGraph &graph, const Values &estimate,
auto index = [](gtsam::Key key) { return Symbol(key).index(); }; auto index = [](gtsam::Key key) { return Symbol(key).index(); };
// save 2D poses // save 2D poses
for (const auto key_value : estimate) { for (const auto &pair : estimate.extract<Pose2>()) {
auto p = dynamic_cast<const GenericValue<Pose2> *>(&key_value.value); const Pose2 &pose = pair.second;
if (!p) stream << "VERTEX_SE2 " << index(pair.first) << " " << pose.x() << " "
continue;
const Pose2 &pose = p->value();
stream << "VERTEX_SE2 " << index(key_value.key) << " " << pose.x() << " "
<< pose.y() << " " << pose.theta() << endl; << pose.y() << " " << pose.theta() << endl;
} }
// save 3D poses // save 3D poses
for (const auto key_value : estimate) { for (const auto &pair : estimate.extract<Pose3>()) {
auto p = dynamic_cast<const GenericValue<Pose3> *>(&key_value.value); const Pose3 &pose = pair.second;
if (!p)
continue;
const Pose3 &pose = p->value();
const Point3 t = pose.translation(); const Point3 t = pose.translation();
const auto q = pose.rotation().toQuaternion(); const auto q = pose.rotation().toQuaternion();
stream << "VERTEX_SE3:QUAT " << index(key_value.key) << " " << t.x() << " " stream << "VERTEX_SE3:QUAT " << index(pair.first) << " " << t.x() << " "
<< t.y() << " " << t.z() << " " << q.x() << " " << q.y() << " " << t.y() << " " << t.z() << " " << q.x() << " " << q.y() << " "
<< q.z() << " " << q.w() << endl; << q.z() << " " << q.w() << endl;
} }
// save 2D landmarks // save 2D landmarks
for (const auto key_value : estimate) { for (const auto &pair : estimate.extract<Point2>()) {
auto p = dynamic_cast<const GenericValue<Point2> *>(&key_value.value); const Point2 &point = pair.second;
if (!p) stream << "VERTEX_XY " << index(pair.first) << " " << point.x() << " "
continue;
const Point2 &point = p->value();
stream << "VERTEX_XY " << index(key_value.key) << " " << point.x() << " "
<< point.y() << endl; << point.y() << endl;
} }
// save 3D landmarks // save 3D landmarks
for (const auto key_value : estimate) { for (const auto &pair : estimate.extract<Point3>()) {
auto p = dynamic_cast<const GenericValue<Point3> *>(&key_value.value); const Point3 &point = pair.second;
if (!p) stream << "VERTEX_TRACKXYZ " << index(pair.first) << " " << point.x()
continue;
const Point3 &point = p->value();
stream << "VERTEX_TRACKXYZ " << index(key_value.key) << " " << point.x()
<< " " << point.y() << " " << point.z() << endl; << " " << point.y() << " " << point.z() << endl;
} }

View File

@ -283,9 +283,10 @@ TEST( Lago, largeGraphNoisy_orientations ) {
Values::shared_ptr expected; Values::shared_ptr expected;
boost::tie(gmatlab, expected) = readG2o(matlabFile); boost::tie(gmatlab, expected) = readG2o(matlabFile);
for(const auto key_val: *expected){ for(const auto key_pose: expected->extract<Pose2>()){
Key k = key_val.key; const Key& k = key_pose.first;
EXPECT(assert_equal(expected->at<Pose2>(k), actual.at<Pose2>(k), 1e-5)); const Pose2& pose = key_pose.second;
EXPECT(assert_equal(pose, actual.at<Pose2>(k), 1e-5));
} }
} }
@ -309,9 +310,10 @@ TEST( Lago, largeGraphNoisy ) {
Values::shared_ptr expected; Values::shared_ptr expected;
boost::tie(gmatlab, expected) = readG2o(matlabFile); boost::tie(gmatlab, expected) = readG2o(matlabFile);
for(const auto key_val: *expected){ for(const auto key_pose: expected->extract<Pose2>()){
Key k = key_val.key; const Key& k = key_pose.first;
EXPECT(assert_equal(expected->at<Pose2>(k), actual.at<Pose2>(k), 1e-2)); const Pose2& pose = key_pose.second;
EXPECT(assert_equal(pose, actual.at<Pose2>(k), 1e-2));
} }
} }

View File

@ -308,12 +308,12 @@ int main(int argc, char** argv) {
// And to demonstrate the fixed-lag aspect, print the keys contained in each smoother after 3.0 seconds // And to demonstrate the fixed-lag aspect, print the keys contained in each smoother after 3.0 seconds
cout << "After 15.0 seconds, each version contains to the following keys:" << endl; cout << "After 15.0 seconds, each version contains to the following keys:" << endl;
cout << " Concurrent Filter Keys: " << endl; cout << " Concurrent Filter Keys: " << endl;
for(const auto key_value: concurrentFilter.getLinearizationPoint()) { for(const auto key: concurrentFilter.getLinearizationPoint().keys()) {
cout << setprecision(5) << " Key: " << key_value.key << endl; cout << setprecision(5) << " Key: " << key << endl;
} }
cout << " Concurrent Smoother Keys: " << endl; cout << " Concurrent Smoother Keys: " << endl;
for(const auto key_value: concurrentSmoother.getLinearizationPoint()) { for(const auto key: concurrentSmoother.getLinearizationPoint().keys()) {
cout << setprecision(5) << " Key: " << key_value.key << endl; cout << setprecision(5) << " Key: " << key << endl;
} }
cout << " Fixed-Lag Smoother Keys: " << endl; cout << " Fixed-Lag Smoother Keys: " << endl;
for(const auto& key_timestamp: fixedlagSmoother.timestamps()) { for(const auto& key_timestamp: fixedlagSmoother.timestamps()) {

View File

@ -59,8 +59,8 @@ FixedLagSmoother::Result BatchFixedLagSmoother::update(
// Add the new variables to theta // Add the new variables to theta
theta_.insert(newTheta); theta_.insert(newTheta);
// Add new variables to the end of the ordering // Add new variables to the end of the ordering
for (const auto key_value : newTheta) { for (const auto key : newTheta.keys()) {
ordering_.push_back(key_value.key); ordering_.push_back(key);
} }
// Augment Delta // Augment Delta
delta_.insert(newTheta.zeroVectors()); delta_.insert(newTheta.zeroVectors());
@ -161,8 +161,8 @@ void BatchFixedLagSmoother::eraseKeys(const KeyVector& keys) {
factorIndex_.erase(key); factorIndex_.erase(key);
// Erase the key from the set of linearized keys // Erase the key from the set of linearized keys
if (linearKeys_.exists(key)) { if (linearValues_.exists(key)) {
linearKeys_.erase(key); linearValues_.erase(key);
} }
} }
@ -186,8 +186,8 @@ FixedLagSmoother::Result BatchFixedLagSmoother::optimize() {
// Create output result structure // Create output result structure
Result result; Result result;
result.nonlinearVariables = theta_.size() - linearKeys_.size(); result.nonlinearVariables = theta_.size() - linearValues_.size();
result.linearVariables = linearKeys_.size(); result.linearVariables = linearValues_.size();
// Set optimization parameters // Set optimization parameters
double lambda = parameters_.lambdaInitial; double lambda = parameters_.lambdaInitial;
@ -265,10 +265,10 @@ FixedLagSmoother::Result BatchFixedLagSmoother::optimize() {
// Reset the deltas to zeros // Reset the deltas to zeros
delta_.setZero(); delta_.setZero();
// Put the linearization points and deltas back for specific variables // Put the linearization points and deltas back for specific variables
if (enforceConsistency_ && (linearKeys_.size() > 0)) { if (enforceConsistency_ && (linearValues_.size() > 0)) {
theta_.update(linearKeys_); theta_.update(linearValues_);
for(const auto key_value: linearKeys_) { for(const auto key: linearValues_.keys()) {
delta_.at(key_value.key) = newDelta.at(key_value.key); delta_.at(key) = newDelta.at(key);
} }
} }
// Decrease lambda for next time // Decrease lambda for next time

View File

@ -136,8 +136,8 @@ protected:
/** The current linearization point **/ /** The current linearization point **/
Values theta_; Values theta_;
/** The set of keys involved in current linear factors. These keys should not be relinearized. **/ /** The set of values involved in current linear factors. **/
Values linearKeys_; Values linearValues_;
/** The current ordering */ /** The current ordering */
Ordering ordering_; Ordering ordering_;

View File

@ -139,8 +139,8 @@ ConcurrentBatchFilter::Result ConcurrentBatchFilter::update(const NonlinearFacto
// Add the new variables to theta // Add the new variables to theta
theta_.insert(newTheta); theta_.insert(newTheta);
// Add new variables to the end of the ordering // Add new variables to the end of the ordering
for(const auto key_value: newTheta) { for (const auto key : newTheta.keys()) {
ordering_.push_back(key_value.key); ordering_.push_back(key);
} }
// Augment Delta // Augment Delta
delta_.insert(newTheta.zeroVectors()); delta_.insert(newTheta.zeroVectors());
@ -221,10 +221,7 @@ void ConcurrentBatchFilter::synchronize(const NonlinearFactorGraph& smootherSumm
if(debug) { PrintNonlinearFactorGraph(smootherSummarization_, "ConcurrentBatchFilter::synchronize ", "Updated Smoother Summarization:", DefaultKeyFormatter); } if(debug) { PrintNonlinearFactorGraph(smootherSummarization_, "ConcurrentBatchFilter::synchronize ", "Updated Smoother Summarization:", DefaultKeyFormatter); }
// Find the set of new separator keys // Find the set of new separator keys
KeySet newSeparatorKeys; const KeySet newSeparatorKeys = separatorValues_.keySet();
for(const auto key_value: separatorValues_) {
newSeparatorKeys.insert(key_value.key);
}
if(debug) { PrintKeys(newSeparatorKeys, "ConcurrentBatchFilter::synchronize ", "Current Separator Keys:"); } if(debug) { PrintKeys(newSeparatorKeys, "ConcurrentBatchFilter::synchronize ", "Current Separator Keys:"); }
@ -236,9 +233,9 @@ void ConcurrentBatchFilter::synchronize(const NonlinearFactorGraph& smootherSumm
graph.push_back(smootherShortcut_); graph.push_back(smootherShortcut_);
Values values; Values values;
values.insert(smootherSummarizationValues); values.insert(smootherSummarizationValues);
for(const auto key_value: separatorValues_) { for(const auto key: newSeparatorKeys) {
if(!values.exists(key_value.key)) { if(!values.exists(key)) {
values.insert(key_value.key, key_value.value); values.insert(key, separatorValues_.at(key));
} }
} }
// Calculate the summarized factor on just the new separator keys // Calculate the summarized factor on just the new separator keys
@ -471,8 +468,8 @@ void ConcurrentBatchFilter::optimize(const NonlinearFactorGraph& factors, Values
// Put the linearization points and deltas back for specific variables // Put the linearization points and deltas back for specific variables
if(linearValues.size() > 0) { if(linearValues.size() > 0) {
theta.update(linearValues); theta.update(linearValues);
for(const auto key_value: linearValues) { for(const auto key: linearValues.keys()) {
delta.at(key_value.key) = newDelta.at(key_value.key); delta.at(key) = newDelta.at(key);
} }
} }
@ -574,9 +571,7 @@ void ConcurrentBatchFilter::moveSeparator(const FastList<Key>& keysToMove) {
// Calculate the set of new separator keys: AffectedKeys + PreviousSeparatorKeys - KeysToMove // Calculate the set of new separator keys: AffectedKeys + PreviousSeparatorKeys - KeysToMove
KeySet newSeparatorKeys = removedFactors.keys(); KeySet newSeparatorKeys = removedFactors.keys();
for(const auto key_value: separatorValues_) { newSeparatorKeys.merge(separatorValues_.keySet());
newSeparatorKeys.insert(key_value.key);
}
for(Key key: keysToMove) { for(Key key: keysToMove) {
newSeparatorKeys.erase(key); newSeparatorKeys.erase(key);
} }

View File

@ -61,8 +61,8 @@ ConcurrentBatchSmoother::Result ConcurrentBatchSmoother::update(const NonlinearF
theta_.insert(newTheta); theta_.insert(newTheta);
// Add new variables to the end of the ordering // Add new variables to the end of the ordering
for(const auto key_value: newTheta) { for(const auto key: newTheta.keys()) {
ordering_.push_back(key_value.key); ordering_.push_back(key);
} }
// Augment Delta // Augment Delta
@ -135,26 +135,30 @@ void ConcurrentBatchSmoother::synchronize(const NonlinearFactorGraph& smootherFa
removeFactors(filterSummarizationSlots_); removeFactors(filterSummarizationSlots_);
// Insert new linpoints into the values, augment the ordering, and store new dims to augment delta // Insert new linpoints into the values, augment the ordering, and store new dims to augment delta
for(const auto key_value: smootherValues) { for(const auto key: smootherValues.keys()) {
std::pair<Values::iterator, bool> iter_inserted = theta_.tryInsert(key_value.key, key_value.value); if(!theta_.exists(key)) {
if(iter_inserted.second) { // If this a new key for theta_, also add to ordering and delta.
// If the insert succeeded const auto& value = smootherValues.at(key);
ordering_.push_back(key_value.key); delta_.insert(key, Vector::Zero(value.dim()));
delta_.insert(key_value.key, Vector::Zero(key_value.value.dim())); theta_.insert(key, value);
ordering_.push_back(key);
} else { } else {
// If the element already existed in theta_ // If the key already existed in theta_, just update.
iter_inserted.first->value = key_value.value; const auto& value = smootherValues.at(key);
theta_.update(key, value);
} }
} }
for(const auto key_value: separatorValues) { for(const auto key: separatorValues.keys()) {
std::pair<Values::iterator, bool> iter_inserted = theta_.tryInsert(key_value.key, key_value.value); if(!theta_.exists(key)) {
if(iter_inserted.second) { // If this a new key for theta_, also add to ordering and delta.
// If the insert succeeded const auto& value = separatorValues.at(key);
ordering_.push_back(key_value.key); delta_.insert(key, Vector::Zero(value.dim()));
delta_.insert(key_value.key, Vector::Zero(key_value.value.dim())); theta_.insert(key, value);
ordering_.push_back(key);
} else { } else {
// If the element already existed in theta_ // If the key already existed in theta_, just update.
iter_inserted.first->value = key_value.value; const auto& value = separatorValues.at(key);
theta_.update(key, value);
} }
} }
@ -322,8 +326,8 @@ ConcurrentBatchSmoother::Result ConcurrentBatchSmoother::optimize() {
// Put the linearization points and deltas back for specific variables // Put the linearization points and deltas back for specific variables
if(separatorValues_.size() > 0) { if(separatorValues_.size() > 0) {
theta_.update(separatorValues_); theta_.update(separatorValues_);
for(const auto key_value: separatorValues_) { for(const auto key: separatorValues_.keys()) {
delta_.at(key_value.key) = newDelta.at(key_value.key); delta_.at(key) = newDelta.at(key);
} }
} }
@ -371,10 +375,7 @@ void ConcurrentBatchSmoother::updateSmootherSummarization() {
} }
// Get the set of separator keys // Get the set of separator keys
gtsam::KeySet separatorKeys; const KeySet separatorKeys = separatorValues_.keySet();
for(const auto key_value: separatorValues_) {
separatorKeys.insert(key_value.key);
}
// Calculate the marginal factors on the separator // Calculate the marginal factors on the separator
smootherSummarization_ = internal::calculateMarginalFactors(graph, theta_, separatorKeys, parameters_.getEliminationFunction()); smootherSummarization_ = internal::calculateMarginalFactors(graph, theta_, separatorKeys, parameters_.getEliminationFunction());

View File

@ -69,14 +69,14 @@ ConcurrentIncrementalFilter::Result ConcurrentIncrementalFilter::update(const No
int group = 1; int group = 1;
// Set all existing variables to Group1 // Set all existing variables to Group1
if(isam2_.getLinearizationPoint().size() > 0) { if(isam2_.getLinearizationPoint().size() > 0) {
for(const auto key_value: isam2_.getLinearizationPoint()) { for(const auto key: isam2_.getLinearizationPoint().keys()) {
orderingConstraints->operator[](key_value.key) = group; orderingConstraints->operator[](key) = group;
} }
++group; ++group;
} }
// Assign new variables to the root // Assign new variables to the root
for(const auto key_value: newTheta) { for(const auto key: newTheta.keys()) {
orderingConstraints->operator[](key_value.key) = group; orderingConstraints->operator[](key) = group;
} }
// Set marginalizable variables to Group0 // Set marginalizable variables to Group0
for(Key key: *keysToMove){ for(Key key: *keysToMove){
@ -201,8 +201,8 @@ void ConcurrentIncrementalFilter::synchronize(const NonlinearFactorGraph& smooth
// Force iSAM2 not to relinearize anything during this iteration // Force iSAM2 not to relinearize anything during this iteration
FastList<Key> noRelinKeys; FastList<Key> noRelinKeys;
for(const auto key_value: isam2_.getLinearizationPoint()) { for(const auto key: isam2_.getLinearizationPoint().keys()) {
noRelinKeys.push_back(key_value.key); noRelinKeys.push_back(key);
} }
// Calculate the summarized factor on just the new separator keys // Calculate the summarized factor on just the new separator keys

View File

@ -66,9 +66,9 @@ ConcurrentIncrementalSmoother::Result ConcurrentIncrementalSmoother::update(cons
// Also, mark the separator keys as fixed linearization points // Also, mark the separator keys as fixed linearization points
FastMap<Key,int> constrainedKeys; FastMap<Key,int> constrainedKeys;
FastList<Key> noRelinKeys; FastList<Key> noRelinKeys;
for(const auto key_value: separatorValues_) { for (const auto key : separatorValues_.keys()) {
constrainedKeys[key_value.key] = 1; constrainedKeys[key] = 1;
noRelinKeys.push_back(key_value.key); noRelinKeys.push_back(key);
} }
// Use iSAM2 to perform an update // Use iSAM2 to perform an update
@ -82,14 +82,14 @@ ConcurrentIncrementalSmoother::Result ConcurrentIncrementalSmoother::update(cons
Values values(newTheta); Values values(newTheta);
// Unfortunately, we must be careful here, as some of the smoother values // Unfortunately, we must be careful here, as some of the smoother values
// and/or separator values may have been added previously // and/or separator values may have been added previously
for(const auto key_value: smootherValues_) { for(const auto key: smootherValues_.keys()) {
if(!isam2_.getLinearizationPoint().exists(key_value.key)) { if(!isam2_.getLinearizationPoint().exists(key)) {
values.insert(key_value.key, smootherValues_.at(key_value.key)); values.insert(key, smootherValues_.at(key));
} }
} }
for(const auto key_value: separatorValues_) { for(const auto key: separatorValues_.keys()) {
if(!isam2_.getLinearizationPoint().exists(key_value.key)) { if(!isam2_.getLinearizationPoint().exists(key)) {
values.insert(key_value.key, separatorValues_.at(key_value.key)); values.insert(key, separatorValues_.at(key));
} }
} }
@ -245,10 +245,7 @@ void ConcurrentIncrementalSmoother::updateSmootherSummarization() {
} }
// Get the set of separator keys // Get the set of separator keys
KeySet separatorKeys; const KeySet separatorKeys = separatorValues_.keySet();
for(const auto key_value: separatorValues_) {
separatorKeys.insert(key_value.key);
}
// Calculate the marginal factors on the separator // Calculate the marginal factors on the separator
smootherSummarization_ = internal::calculateMarginalFactors(graph, isam2_.getLinearizationPoint(), separatorKeys, smootherSummarization_ = internal::calculateMarginalFactors(graph, isam2_.getLinearizationPoint(), separatorKeys,

View File

@ -64,8 +64,8 @@ NonlinearFactorGraph CalculateMarginals(const NonlinearFactorGraph& factorGraph,
std::set<Key> KeysToKeep; std::set<Key> KeysToKeep;
for(const auto key_value: linPoint) { // we cycle over all the keys of factorGraph for(const auto key: linPoint.keys()) { // we cycle over all the keys of factorGraph
KeysToKeep.insert(key_value.key); KeysToKeep.insert(key);
} // so far we are keeping all keys, but we want to delete the ones that we are going to marginalize } // so far we are keeping all keys, but we want to delete the ones that we are going to marginalize
for(Key key: keysToMarginalize) { for(Key key: keysToMarginalize) {
KeysToKeep.erase(key); KeysToKeep.erase(key);

View File

@ -560,8 +560,8 @@ TEST( ConcurrentBatchSmoother, synchronize_3 )
GaussianFactorGraph::shared_ptr linearFactors = allFactors.linearize(allValues); GaussianFactorGraph::shared_ptr linearFactors = allFactors.linearize(allValues);
KeySet eliminateKeys = linearFactors->keys(); KeySet eliminateKeys = linearFactors->keys();
for(const auto key_value: filterSeparatorValues) { for(const auto key: filterSeparatorValues.keys()) {
eliminateKeys.erase(key_value.key); eliminateKeys.erase(key);
} }
KeyVector variables(eliminateKeys.begin(), eliminateKeys.end()); KeyVector variables(eliminateKeys.begin(), eliminateKeys.end());
GaussianFactorGraph result = *linearFactors->eliminatePartialMultifrontal(variables, EliminateCholesky).second; GaussianFactorGraph result = *linearFactors->eliminatePartialMultifrontal(variables, EliminateCholesky).second;

View File

@ -80,8 +80,8 @@ NonlinearFactorGraph CalculateMarginals(const NonlinearFactorGraph& factorGraph,
std::set<Key> KeysToKeep; std::set<Key> KeysToKeep;
for(const auto key_value: linPoint) { // we cycle over all the keys of factorGraph for(const auto key: linPoint.keys()) { // we cycle over all the keys of factorGraph
KeysToKeep.insert(key_value.key); KeysToKeep.insert(key);
} // so far we are keeping all keys, but we want to delete the ones that we are going to marginalize } // so far we are keeping all keys, but we want to delete the ones that we are going to marginalize
for(Key key: keysToMarginalize) { for(Key key: keysToMarginalize) {
KeysToKeep.erase(key); KeysToKeep.erase(key);

View File

@ -512,8 +512,8 @@ TEST( ConcurrentIncrementalSmootherDL, synchronize_2 )
// Values expectedLinearizationPoint = BatchOptimize(allFactors, allValues, 1); // Values expectedLinearizationPoint = BatchOptimize(allFactors, allValues, 1);
Values expectedLinearizationPoint = filterSeparatorValues; Values expectedLinearizationPoint = filterSeparatorValues;
Values actualLinearizationPoint; Values actualLinearizationPoint;
for(const auto key_value: filterSeparatorValues) { for(const auto key: filterSeparatorValues.keys()) {
actualLinearizationPoint.insert(key_value.key, smoother.getLinearizationPoint().at(key_value.key)); actualLinearizationPoint.insert(key, smoother.getLinearizationPoint().at(key));
} }
CHECK(assert_equal(expectedLinearizationPoint, actualLinearizationPoint, 1e-6)); CHECK(assert_equal(expectedLinearizationPoint, actualLinearizationPoint, 1e-6));
} }
@ -580,8 +580,8 @@ TEST( ConcurrentIncrementalSmootherDL, synchronize_3 )
// GaussianBayesNet::shared_ptr GBNsptr = GSS.eliminate(); // GaussianBayesNet::shared_ptr GBNsptr = GSS.eliminate();
KeySet allkeys = LinFactorGraph->keys(); KeySet allkeys = LinFactorGraph->keys();
for(const auto key_value: filterSeparatorValues) { for(const auto key: filterSeparatorValues.keys()) {
allkeys.erase(key_value.key); allkeys.erase(key);
} }
KeyVector variables(allkeys.begin(), allkeys.end()); KeyVector variables(allkeys.begin(), allkeys.end());
std::pair<GaussianBayesNet::shared_ptr, GaussianFactorGraph::shared_ptr> result = LinFactorGraph->eliminatePartialSequential(variables, EliminateCholesky); std::pair<GaussianBayesNet::shared_ptr, GaussianFactorGraph::shared_ptr> result = LinFactorGraph->eliminatePartialSequential(variables, EliminateCholesky);

View File

@ -513,8 +513,8 @@ TEST( ConcurrentIncrementalSmootherGN, synchronize_2 )
// Values expectedLinearizationPoint = BatchOptimize(allFactors, allValues, 1); // Values expectedLinearizationPoint = BatchOptimize(allFactors, allValues, 1);
Values expectedLinearizationPoint = filterSeparatorValues; Values expectedLinearizationPoint = filterSeparatorValues;
Values actualLinearizationPoint; Values actualLinearizationPoint;
for(const auto key_value: filterSeparatorValues) { for(const auto key: filterSeparatorValues.keys()) {
actualLinearizationPoint.insert(key_value.key, smoother.getLinearizationPoint().at(key_value.key)); actualLinearizationPoint.insert(key, smoother.getLinearizationPoint().at(key));
} }
CHECK(assert_equal(expectedLinearizationPoint, actualLinearizationPoint, 1e-6)); CHECK(assert_equal(expectedLinearizationPoint, actualLinearizationPoint, 1e-6));
} }
@ -582,8 +582,7 @@ TEST( ConcurrentIncrementalSmootherGN, synchronize_3 )
// GaussianBayesNet::shared_ptr GBNsptr = GSS.eliminate(); // GaussianBayesNet::shared_ptr GBNsptr = GSS.eliminate();
KeySet allkeys = LinFactorGraph->keys(); KeySet allkeys = LinFactorGraph->keys();
for(const auto key_value: filterSeparatorValues) for (const auto key : filterSeparatorValues.keys()) allkeys.erase(key);
allkeys.erase(key_value.key);
KeyVector variables(allkeys.begin(), allkeys.end()); KeyVector variables(allkeys.begin(), allkeys.end());
std::pair<GaussianBayesNet::shared_ptr, GaussianFactorGraph::shared_ptr> result = LinFactorGraph->eliminatePartialSequential(variables, EliminateCholesky); std::pair<GaussianBayesNet::shared_ptr, GaussianFactorGraph::shared_ptr> result = LinFactorGraph->eliminatePartialSequential(variables, EliminateCholesky);