Fixed compile problem with gcc and bug fix in int key <-> Symbol encoding

release/4.3a0
Richard Roberts 2012-02-24 23:38:51 +00:00
parent eae3ee0ecd
commit 12775256c1
9 changed files with 183 additions and 74 deletions

View File

@ -26,7 +26,7 @@
namespace gtsam {
/**
* FastSet is a thin wrapper around std::set that uses the boost
* FastList is a thin wrapper around std::list that uses the boost
* fast_pool_allocator instead of the default STL allocator. This is just a
* convenience to avoid having lengthy types in the code. Through timing,
* we've seen that the fast_pool_allocator can lead to speedups of several

View File

@ -62,7 +62,7 @@ namespace gtsam {
Pose3(const Rot3& R, const Point3& t) : R_(R), t_(t) {}
/** Construct from Pose2 */
Pose3(const Pose2& pose2);
explicit Pose3(const Pose2& pose2);
/** Constructor from 4*4 matrix */
Pose3(const Matrix &T) :

View File

@ -144,8 +144,8 @@ void ISAM2<CONDITIONAL,GRAPH>::Impl::AddVariables(
Index nextVar = originalnVars;
BOOST_FOREACH(const Values::ConstKeyValuePair& key_value, newTheta) {
delta.permutation()[nextVar] = nextVar;
ordering.insert(key_value.first, nextVar);
if(debug) cout << "Adding variable " << keyFormatter(key_value.first) << " with order " << nextVar << endl;
ordering.insert(key_value.key, nextVar);
if(debug) cout << "Adding variable " << keyFormatter(key_value.key) << " with order " << nextVar << endl;
++ nextVar;
}
assert(delta.permutation().size() == delta.container().size());
@ -234,19 +234,19 @@ void ISAM2<CONDITIONAL, GRAPH>::Impl::ExpmapMasked(Values& values, const Permute
Ordering::const_iterator key_index;
for(key_value = values.begin(), key_index = ordering.begin();
key_value != values.end() && key_index != ordering.end(); ++key_value, ++key_index) {
assert(key_value->first == key_index->first);
assert(key_value->key == key_index->first);
const Index var = key_index->second;
if(ISDEBUG("ISAM2 update verbose")) {
if(mask[var])
cout << "expmap " << keyFormatter(key_value->first) << " (j = " << var << "), delta = " << delta[var].transpose() << endl;
cout << "expmap " << keyFormatter(key_value->key) << " (j = " << var << "), delta = " << delta[var].transpose() << endl;
else
cout << " " << keyFormatter(key_value->first) << " (j = " << var << "), delta = " << delta[var].transpose() << endl;
cout << " " << keyFormatter(key_value->key) << " (j = " << var << "), delta = " << delta[var].transpose() << endl;
}
assert(delta[var].size() == (int)key_value->second.dim());
assert(delta[var].size() == (int)key_value->value.dim());
assert(delta[var].unaryExpr(&isfinite<double>).all());
if(mask[var]) {
Value* retracted = key_value->second.retract_(delta[var]);
key_value->second = *retracted;
Value* retracted = key_value->value.retract_(delta[var]);
key_value->value = *retracted;
retracted->deallocate_();
if(invalidateIfDebug)
(*invalidateIfDebug)[var].operator=(Vector::Constant(delta[var].rows(), numeric_limits<double>::infinity())); // Strange syntax to work with clang++ (bug in clang?)

View File

@ -23,6 +23,10 @@
#include <boost/mpl/char.hpp>
#include <boost/format.hpp>
#include <boost/serialization/nvp.hpp>
#include <boost/function.hpp>
#include <boost/lambda/bind.hpp>
#include <boost/lambda/construct.hpp>
#include <boost/lambda/lambda.hpp>
#include <gtsam/nonlinear/Key.h>
@ -57,25 +61,25 @@ public:
/** Constructor that decodes an integer Key */
Symbol(Key key) {
const size_t keyBytes = sizeof(Key);
const size_t chrBytes = sizeof(unsigned char);
const size_t indexBytes = keyBytes - chrBytes;
const Key chrMask = std::numeric_limits<unsigned char>::max() << indexBytes;
const size_t keyBits = sizeof(Key) * 8;
const size_t chrBits = sizeof(unsigned char) * 8;
const size_t indexBits = keyBits - chrBits;
const Key chrMask = Key(std::numeric_limits<unsigned char>::max()) << indexBits;
const Key indexMask = ~chrMask;
c_ = (key & chrMask) >> indexBytes;
c_ = (unsigned char)((key & chrMask) >> indexBits);
j_ = key & indexMask;
}
/** Cast to integer */
operator Key() const {
const size_t keyBytes = sizeof(Key);
const size_t chrBytes = sizeof(unsigned char);
const size_t indexBytes = keyBytes - chrBytes;
const Key chrMask = std::numeric_limits<unsigned char>::max() << indexBytes;
const size_t keyBits = sizeof(Key) * 8;
const size_t chrBits = sizeof(unsigned char) * 8;
const size_t indexBits = keyBits - chrBits;
const Key chrMask = Key(std::numeric_limits<unsigned char>::max()) << indexBits;
const Key indexMask = ~chrMask;
if(j_ > indexMask)
throw std::invalid_argument("Symbol index is too large");
Key key = (c_ << indexBytes) | j_;
Key key = (Key(c_) << indexBits) | j_;
return key;
}
@ -113,6 +117,16 @@ public:
return comp.c_ != c_ || comp.j_ != j_;
}
/** Return a filter function that returns true when evaluated on a Key whose
* character (when converted to a Symbol) matches \c c. Use this with the
* Values::filter() function to retrieve all key-value pairs with the
* requested character.
*/
static boost::function<bool(Key)> ChrTest(unsigned char c) {
namespace bl = boost::lambda;
return bl::bind(&Symbol::chr, bl::bind(bl::constructor<Symbol>(), bl::_1)) == c;
}
private:
/** Serialization function */

View File

@ -43,8 +43,8 @@ namespace gtsam {
void Values::print(const string& str, const KeyFormatter& keyFormatter) const {
cout << str << "Values with " << size() << " values:\n" << endl;
for(const_iterator key_value = begin(); key_value != end(); ++key_value) {
cout << " " << keyFormatter(key_value->first) << ": ";
key_value->second.print("");
cout << " " << keyFormatter(key_value->key) << ": ";
key_value->value.print("");
}
}
@ -53,11 +53,11 @@ namespace gtsam {
if(this->size() != other.size())
return false;
for(const_iterator it1=this->begin(), it2=other.begin(); it1!=this->end(); ++it1, ++it2) {
if(typeid(it1->second) != typeid(it2->second))
if(typeid(it1->value) != typeid(it2->value))
return false;
if(it1->first != it2->first)
if(it1->key != it2->key)
return false;
if(!it1->second.equals_(it2->second, tol))
if(!it1->value.equals_(it2->value, tol))
return false;
}
return true; // We return false earlier if we find anything that does not match
@ -78,9 +78,9 @@ namespace gtsam {
Values result;
for(const_iterator key_value = begin(); key_value != end(); ++key_value) {
const SubVector& singleDelta = delta[ordering[key_value->first]]; // Delta for this value
Key key = key_value->first; // Non-const duplicate to deal with non-const insert argument
Value* retractedValue(key_value->second.retract_(singleDelta)); // Retract
const SubVector& singleDelta = delta[ordering[key_value->key]]; // Delta for this value
Key key = key_value->key; // Non-const duplicate to deal with non-const insert argument
Value* retractedValue(key_value->value.retract_(singleDelta)); // Retract
result.values_.insert(key, retractedValue); // Add retracted result directly to result values
}
@ -99,10 +99,10 @@ namespace gtsam {
if(this->size() != cp.size())
throw DynamicValuesMismatched();
for(const_iterator it1=this->begin(), it2=cp.begin(); it1!=this->end(); ++it1, ++it2) {
if(it1->first != it2->first)
if(it1->key != it2->key)
throw DynamicValuesMismatched(); // If keys do not match
// Will throw a dynamic_cast exception if types do not match
result.insert(ordering[it1->first], it1->second.localCoordinates_(it2->second));
result.insert(ordering[it1->key], it1->value.localCoordinates_(it2->value));
}
}
@ -117,8 +117,8 @@ namespace gtsam {
/* ************************************************************************* */
void Values::insert(const Values& values) {
for(const_iterator key_value = values.begin(); key_value != values.end(); ++key_value) {
Key key = key_value->first; // Non-const duplicate to deal with non-const insert argument
insert(key, key_value->second);
Key key = key_value->key; // Non-const duplicate to deal with non-const insert argument
insert(key, key_value->value);
}
}
@ -139,7 +139,7 @@ namespace gtsam {
/* ************************************************************************* */
void Values::update(const Values& values) {
for(const_iterator key_value = values.begin(); key_value != values.end(); ++key_value) {
this->update(key_value->first, key_value->second);
this->update(key_value->key, key_value->value);
}
}
@ -152,10 +152,12 @@ namespace gtsam {
}
/* ************************************************************************* */
FastList<Key> Values::keys() const {
FastList<Key> result;
for(const_iterator key_value = begin(); key_value != end(); ++key_value)
result.push_back(key_value->first);
std::list<Key> Values::keys() const {
std::list<Key> result;
for(const_iterator key_value = begin(); key_value != end(); ++key_value) {
result.push_back(key_value->key);
cout << result.back() << endl;
}
return result;
}
@ -170,7 +172,7 @@ namespace gtsam {
vector<size_t> Values::dims(const Ordering& ordering) const {
vector<size_t> result(values_.size());
BOOST_FOREACH(const ConstKeyValuePair& key_value, *this) {
result[ordering[key_value.first]] = key_value.second.dim();
result[ordering[key_value.key]] = key_value.value.dim();
}
return result;
}
@ -179,7 +181,7 @@ namespace gtsam {
size_t Values::dim() const {
size_t result = 0;
BOOST_FOREACH(const ConstKeyValuePair& key_value, *this) {
result += key_value.second.dim();
result += key_value.value.dim();
}
return result;
}
@ -188,7 +190,7 @@ namespace gtsam {
Ordering::shared_ptr Values::orderingArbitrary(Index firstVar) const {
Ordering::shared_ptr ordering(new Ordering);
for(const_iterator key_value = begin(); key_value != end(); ++key_value) {
ordering->insert(key_value->first, firstVar++);
ordering->insert(key_value->key, firstVar++);
}
return ordering;
}

View File

@ -87,10 +87,21 @@ namespace gtsam {
typedef boost::shared_ptr<Values> shared_ptr;
/// A key-value pair, which you get by dereferencing iterators
typedef std::pair<const Key, Value&> KeyValuePair;
struct KeyValuePair {
const Key key; ///< The key
Value& value; ///< The value
KeyValuePair(Key _key, Value& _value) : key(_key), value(_value) {}
};
/// A key-value pair, which you get by dereferencing iterators
typedef std::pair<const Key, const Value&> ConstKeyValuePair;
struct ConstKeyValuePair {
const Key key; ///< The key
const Value& value; ///< The value
ConstKeyValuePair(Key _key, const Value& _value) : key(_key), value(_value) {}
ConstKeyValuePair(const KeyValuePair& kv) : key(kv.key), value(kv.value) {}
};
/// Mutable forward iterator, with value type KeyValuePair
typedef boost::transform_iterator<
@ -108,17 +119,42 @@ namespace gtsam {
typedef boost::transform_iterator<
boost::function1<ConstKeyValuePair, const ConstKeyValuePtrPair&>, KeyValueMap::const_reverse_iterator> const_reverse_iterator;
private:
template<class ValueType>
struct _KeyValuePair {
const Key key; ///< The key
ValueType& value; ///< The value
const Key& first; ///< For std::pair compatibility, the key
ValueType& second; ///< For std::pair compatibility, the value
_KeyValuePair(Key _key, ValueType& _value) : key(_key), value(_value), first(key), second(value) {}
};
template<class ValueType>
struct _ConstKeyValuePair {
const Key key; ///< The key
const ValueType& value; ///< The value
const Key& first; ///< For std::pair compatibility, the key
const ValueType& second; ///< For std::pair compatibility, the value
_ConstKeyValuePair(Key _key, const Value& _value) : key(_key), value(_value), first(key), second(value) {}
};
public:
template<class ValueType = Value>
class Filtered : public boost::transformed_range<
std::pair<const Key, ValueType&>(*)(KeyValuePair key_value),
_KeyValuePair<ValueType>(*)(Values::KeyValuePair key_value),
const boost::filtered_range<
boost::function<bool(const ConstKeyValuePair&)>,
const boost::iterator_range<iterator> > > {
public:
typedef _KeyValuePair<ValueType> KeyValuePair;
private:
typedef boost::transformed_range<
std::pair<const Key, ValueType&>(*)(KeyValuePair key_value),
KeyValuePair(*)(Values::KeyValuePair key_value),
const boost::filtered_range<
boost::function<bool(const ConstKeyValuePair&)>,
boost::function<bool(const Values::ConstKeyValuePair&)>,
const boost::iterator_range<iterator> > > Base;
Filtered(const Base& base) : Base(base) {}
@ -126,17 +162,20 @@ namespace gtsam {
friend class Values;
};
template<class ValueType>
template<class ValueType = Value>
class ConstFiltered : public boost::transformed_range<
std::pair<const Key, const ValueType&>(*)(ConstKeyValuePair key_value),
_ConstKeyValuePair<ValueType>(*)(Values::ConstKeyValuePair key_value),
const boost::filtered_range<
boost::function<bool(const ConstKeyValuePair&)>,
const boost::iterator_range<const_iterator> > > {
public:
typedef _ConstKeyValuePair<ValueType> KeyValuePair;
private:
typedef boost::transformed_range<
std::pair<const Key, const ValueType&>(*)(ConstKeyValuePair key_value),
KeyValuePair(*)(Values::ConstKeyValuePair key_value),
const boost::filtered_range<
boost::function<bool(const ConstKeyValuePair&)>,
boost::function<bool(const Values::ConstKeyValuePair&)>,
const boost::iterator_range<const_iterator> > > Base;
ConstFiltered(const Base& base) : Base(base) {}
@ -257,7 +296,7 @@ namespace gtsam {
* Returns a set of keys in the config
* Note: by construction, the list is ordered
*/
FastList<Key> keys() const;
std::list<Key> keys() const;
/** Replace all keys and variables */
Values& operator=(const Values& rhs);
@ -324,7 +363,7 @@ namespace gtsam {
boost::make_iterator_range(begin(), end()),
boost::function<bool(const ConstKeyValuePair&)>(
boost::bind(&filterHelper<ValueType>, filterFcn, _1))),
&castHelper<ValueType, KeyValuePair>);
&castHelper<ValueType, _KeyValuePair<ValueType>, KeyValuePair>);
}
/**
@ -371,7 +410,7 @@ namespace gtsam {
boost::make_iterator_range(begin(), end()),
boost::function<bool(const ConstKeyValuePair&)>(
boost::bind(&filterHelper<ValueType>, filterFcn, _1))),
&castHelper<const ValueType, ConstKeyValuePair>);
&castHelper<const ValueType, _ConstKeyValuePair<ValueType>, ConstKeyValuePair>);
}
private:
@ -380,14 +419,14 @@ namespace gtsam {
template<class ValueType>
static bool filterHelper(const boost::function<bool(Key)> filter, const ConstKeyValuePair& key_value) {
// Filter and check the type
return filter(key_value.first) && (typeid(ValueType) == typeid(key_value.second) || typeid(ValueType) == typeid(Value));
return filter(key_value.key) && (typeid(ValueType) == typeid(key_value.value) || typeid(ValueType) == typeid(Value));
}
// Cast to the derived ValueType
template<class ValueType, class KeyValuePairType>
static std::pair<const Key, ValueType&> castHelper(KeyValuePairType key_value) {
template<class ValueType, class CastedKeyValuePairType, class KeyValuePairType>
static CastedKeyValuePairType castHelper(KeyValuePairType key_value) {
// Static cast because we already checked the type during filtering
return std::pair<const Key, ValueType&>(key_value.first, static_cast<ValueType&>(key_value.second));
return CastedKeyValuePairType(key_value.key, static_cast<ValueType&>(key_value.value));
}
/** Serialization function */

View File

@ -19,6 +19,7 @@ using namespace boost::assign;
#include <CppUnitLite/TestHarness.h>
#include <gtsam/base/Testable.h>
#include <gtsam/base/TestableAssertions.h>
#include <gtsam/nonlinear/Symbol.h>
using namespace std;
@ -33,6 +34,30 @@ TEST(Key, KeySymbolConversion) {
EXPECT(assert_equal(expected, actual))
}
/* ************************************************************************* */
TEST(Key, KeySymbolEncoding) {
// Test encoding of Symbol <-> size_t <-> string
if(sizeof(Key) == 8) {
Symbol symbol(0x61, 5);
Key key = 0x6100000000000005;
string str = "a5";
LONGS_EQUAL(key, (Key)symbol);
assert_equal(str, DefaultKeyFormatter(symbol));
assert_equal(symbol, Symbol(key));
} else if(sizeof(Key) == 4) {
Symbol symbol(0x61, 5);
Key key = 0x61000005;
string str = "a5";
LONGS_EQUAL(key, (Key)symbol);
assert_equal(str, DefaultKeyFormatter(symbol));
assert_equal(symbol, Symbol(key));
}
}
/* ************************************************************************* */
int main() { TestResult tr; return TestRegistry::runAllTests(tr); }
/* ************************************************************************* */

View File

@ -31,7 +31,7 @@ using namespace gtsam;
using namespace std;
static double inf = std::numeric_limits<double>::infinity();
Key key1(Symbol('v',1)), key2(Symbol('v',2)), key3(Symbol('v',3)), key4(Symbol('v',4));
const Key key1(Symbol('v',1)), key2(Symbol('v',2)), key3(Symbol('v',3)), key4(Symbol('v',4));
/* ************************************************************************* */
TEST( Values, equals1 )
@ -218,14 +218,14 @@ TEST(Values, extract_keys)
config.insert(key3, Pose2());
config.insert(key4, Pose2());
FastList<Key> expected, actual;
std::list<Key> expected, actual;
expected += key1, key2, key3, key4;
actual = config.keys();
CHECK(actual.size() == expected.size());
FastList<Key>::const_iterator itAct = actual.begin(), itExp = expected.begin();
std::list<Key>::const_iterator itAct = actual.begin(), itExp = expected.begin();
for (; itAct != actual.end() && itExp != expected.end(); ++itAct, ++itExp) {
LONGS_EQUAL(*itExp, *itAct);
EXPECT(*itExp == *itAct);
}
}
@ -274,15 +274,15 @@ TEST(Values, filter) {
// Filter by key
int i = 0;
Values::Filtered<Value> filtered = values.filter(boost::bind(std::greater_equal<Key>(), _1, 2));
BOOST_FOREACH(const Values::Filtered<Value>::value_type& key_value, filtered) {
BOOST_FOREACH(const Values::Filtered<>::KeyValuePair& key_value, filtered) {
if(i == 0) {
LONGS_EQUAL(2, key_value.first);
EXPECT(typeid(Pose2) == typeid(key_value.second));
EXPECT(assert_equal(pose2, dynamic_cast<const Pose2&>(key_value.second)));
LONGS_EQUAL(2, key_value.key);
EXPECT(typeid(Pose2) == typeid(key_value.value));
EXPECT(assert_equal(pose2, dynamic_cast<const Pose2&>(key_value.value)));
} else if(i == 1) {
LONGS_EQUAL(3, key_value.first);
EXPECT(typeid(Pose3) == typeid(key_value.second));
EXPECT(assert_equal(pose3, dynamic_cast<const Pose3&>(key_value.second)));
LONGS_EQUAL(3, key_value.key);
EXPECT(typeid(Pose3) == typeid(key_value.value));
EXPECT(assert_equal(pose3, dynamic_cast<const Pose3&>(key_value.value)));
} else {
EXPECT(false);
}
@ -292,13 +292,42 @@ TEST(Values, filter) {
// Filter by type
i = 0;
BOOST_FOREACH(const Values::Filtered<Pose3>::value_type& key_value, values.filter<Pose3>()) {
BOOST_FOREACH(const Values::Filtered<Pose3>::KeyValuePair& key_value, values.filter<Pose3>()) {
if(i == 0) {
LONGS_EQUAL(1, key_value.first);
EXPECT(assert_equal(pose1, key_value.second));
LONGS_EQUAL(1, key_value.key);
EXPECT(assert_equal(pose1, key_value.value));
} else if(i == 1) {
LONGS_EQUAL(3, key_value.first);
EXPECT(assert_equal(pose3, key_value.second));
LONGS_EQUAL(3, key_value.key);
EXPECT(assert_equal(pose3, key_value.value));
} else {
EXPECT(false);
}
++ i;
}
LONGS_EQUAL(2, i);
}
/* ************************************************************************* */
TEST(Values, Symbol_filter) {
Pose2 pose0(1.0, 2.0, 0.3);
Pose3 pose1(Pose2(0.1, 0.2, 0.3));
Pose2 pose2(4.0, 5.0, 0.6);
Pose3 pose3(Pose2(0.3, 0.7, 0.9));
Values values;
values.insert(Symbol('x',0), pose0);
values.insert(Symbol('y',1), pose1);
values.insert(Symbol('x',2), pose2);
values.insert(Symbol('y',3), pose3);
int i = 0;
BOOST_FOREACH(const Values::Filtered<Value>::KeyValuePair& key_value, values.filter(Symbol::ChrTest('y'))) {
if(i == 0) {
LONGS_EQUAL(Symbol('y',1), key_value.key);
EXPECT(assert_equal(pose1, dynamic_cast<const Pose3&>(key_value.value)));
} else if(i == 1) {
LONGS_EQUAL(Symbol('y',3), key_value.key);
EXPECT(assert_equal(pose3, dynamic_cast<const Pose3&>(key_value.value)));
} else {
EXPECT(false);
}

View File

@ -155,8 +155,8 @@ void save2D(const pose2SLAM::Graph& graph, const Values& config, const SharedDia
// save poses
BOOST_FOREACH(const Values::ConstKeyValuePair& key_value, config) {
const Pose2& pose = dynamic_cast<const Pose2&>(key_value.second);
stream << "VERTEX2 " << key_value.first << " " << pose.x() << " " << pose.y() << " " << pose.theta() << endl;
const Pose2& pose = dynamic_cast<const Pose2&>(key_value.value);
stream << "VERTEX2 " << key_value.key << " " << pose.x() << " " << pose.y() << " " << pose.theta() << endl;
}
// save edges