Moved LabeledSymbol from MastSLAM with some key-related utilities

release/4.3a0
Alex Cunningham 2013-04-30 18:41:06 +00:00
parent 62f6089119
commit 9e2b11800a
4 changed files with 433 additions and 0 deletions

26
gtsam.h
View File

@ -1450,6 +1450,32 @@ size_t symbol(char chr, size_t index);
char symbolChr(size_t key);
size_t symbolIndex(size_t key);
// Key utilities
gtsam::KeySet keyIntersection(const gtsam::KeySet& keysA, const gtsam::KeySet& keysB);
gtsam::KeySet keyDifference(const gtsam::KeySet& keysA, const gtsam::KeySet& keysB);
bool hasKeyIntersection(const gtsam::KeySet& keysA, const gtsam::KeySet& keysB);
// Default keyformatter
void printKeySet(const gtsam::KeySet& keys);
void printKeySet(const gtsam::KeySet& keys, string s);
#include <gtsam/nonlinear/LabeledSymbol.h>
class LabeledSymbol {
LabeledSymbol(size_t full_key);
LabeledSymbol(const gtsam::LabeledSymbol& key);
LabeledSymbol(unsigned char valType, unsigned char label, size_t j);
size_t key() const;
unsigned char label() const;
unsigned char chr() const;
size_t index() const;
gtsam::LabeledSymbol upper() const;
gtsam::LabeledSymbol lower() const;
void print(string s) const;
};
#include <gtsam/nonlinear/Ordering.h>
class Ordering {
// Standard Constructors and Named Constructors

View File

@ -0,0 +1,191 @@
/* ----------------------------------------------------------------------------
* GTSAM Copyright 2010, Georgia Tech Research Corporation,
* Atlanta, Georgia 30332-0415
* All Rights Reserved
* Authors: Frank Dellaert, et al. (see THANKS for the full author list)
* See LICENSE for the license information
* -------------------------------------------------------------------------- */
/**
* @file LabeledSymbol.h
* @date Jan 12, 2010
* @author: Alex Cunningham
*/
#include <iostream>
#include <boost/mpl/char.hpp>
#include <boost/format.hpp>
#include <boost/function.hpp>
#include <boost/lambda/bind.hpp>
#include <boost/lambda/construct.hpp>
#include <boost/lambda/lambda.hpp>
#include <boost/lexical_cast.hpp>
#include <gtsam/nonlinear/LabeledSymbol.h>
namespace gtsam {
using namespace std;
/* ************************************************************************* */
LabeledSymbol::LabeledSymbol()
: c_(0), label_(0), j_(0) {}
/* ************************************************************************* */
LabeledSymbol::LabeledSymbol(const LabeledSymbol& key)
: c_(key.c_), label_(key.label_), j_(key.j_) {}
/* ************************************************************************* */
LabeledSymbol::LabeledSymbol(unsigned char c, unsigned char label, size_t j)
: c_(c), label_(label), j_(j) {}
/* ************************************************************************* */
LabeledSymbol::LabeledSymbol(gtsam::Key key) {
const size_t keyBits = sizeof(gtsam::Key) * 8;
const size_t chrBits = sizeof(unsigned char) * 8;
const size_t lblBits = sizeof(unsigned char) * 8;
const size_t indexBits = keyBits - chrBits - lblBits;
const gtsam::Key chrMask = gtsam::Key(std::numeric_limits<unsigned char>::max()) << (indexBits + lblBits);
const gtsam::Key lblMask = gtsam::Key(std::numeric_limits<unsigned char>::max()) << indexBits;
const gtsam::Key indexMask = ~(chrMask | lblMask);
c_ = (unsigned char)((key & chrMask) >> (indexBits + lblBits));
label_ = (unsigned char)((key & lblMask) >> indexBits);
j_ = key & indexMask;
}
/* ************************************************************************* */
LabeledSymbol::operator gtsam::Key() const {
const size_t keyBits = sizeof(gtsam::Key) * 8;
const size_t chrBits = sizeof(unsigned char) * 8;
const size_t lblBits = sizeof(unsigned char) * 8;
const size_t indexBits = keyBits - chrBits - lblBits;
const gtsam::Key chrMask = gtsam::Key(std::numeric_limits<unsigned char>::max()) << (indexBits + lblBits);
const gtsam::Key lblMask = gtsam::Key(std::numeric_limits<unsigned char>::max()) << indexBits;
const gtsam::Key indexMask = ~(chrMask | lblMask);
if(j_ > indexMask)
throw std::invalid_argument("Symbol index is too large");
gtsam::Key key = (gtsam::Key(c_) << (indexBits + lblBits)) | (gtsam::Key(label_) << indexBits) | j_;
return key;
}
/* ************************************************************************* */
void LabeledSymbol::print(const std::string& s) const {
std::cout << s << ": " << (std::string) (*this) << std::endl;
}
/* ************************************************************************* */
LabeledSymbol::operator std::string() const {
return str(boost::format("%c%c%d") % c_ % label_ % j_);
}
/* ************************************************************************* */
bool LabeledSymbol::operator<(const LabeledSymbol& comp) const {
return c_ < comp.c_
|| (comp.c_ == c_ && label_ < comp.label_)
|| (comp.c_ == c_ && comp.label_ == label_ && j_ < comp.j_);
}
/* ************************************************************************* */
bool LabeledSymbol::operator==(const LabeledSymbol& comp) const {
return comp.c_ == c_ && comp.label_ == label_ && comp.j_ == j_;
}
/* ************************************************************************* */
bool LabeledSymbol::operator!=(const LabeledSymbol& comp) const {
return comp.c_ != c_ || comp.label_ != label_ || comp.j_ != j_;
}
/* ************************************************************************* */
bool LabeledSymbol::operator==(gtsam::Key comp) const {
return comp == (gtsam::Key)(*this);
}
/* ************************************************************************* */
bool LabeledSymbol::operator!=(gtsam::Key comp) const {
return comp != (gtsam::Key)(*this);
}
/* ************************************************************************* */
boost::function<bool(gtsam::Key)> LabeledSymbol::TypeTest(unsigned char c) {
namespace bl = boost::lambda;
return bl::bind(&LabeledSymbol::chr, bl::bind(bl::constructor<LabeledSymbol>(), bl::_1)) == c;
}
/* ************************************************************************* */
boost::function<bool(gtsam::Key)> LabeledSymbol::LabelTest(unsigned char label) {
namespace bl = boost::lambda;
return bl::bind(&LabeledSymbol::label, bl::bind(bl::constructor<LabeledSymbol>(), bl::_1)) == label;
}
/* ************************************************************************* */
boost::function<bool(gtsam::Key)> LabeledSymbol::TypeLabelTest(unsigned char c, unsigned char label) {
namespace bl = boost::lambda;
return bl::bind(&LabeledSymbol::chr, bl::bind(bl::constructor<LabeledSymbol>(), bl::_1)) == c &&
bl::bind(&LabeledSymbol::label, bl::bind(bl::constructor<LabeledSymbol>(), bl::_1)) == label;
}
/* ************************************************************************* */
std::string _multirobotKeyFormatter(gtsam::Key key) {
const LabeledSymbol asLabeledSymbol(key);
if(asLabeledSymbol.chr() > 0 && asLabeledSymbol.label() > 0)
return (std::string)asLabeledSymbol;
const gtsam::Symbol asSymbol(key);
if (asLabeledSymbol.chr() > 0)
return (std::string)asSymbol;
else
return boost::lexical_cast<std::string>(key);
}
/* ************************************************************************* */
void printKeySet(const gtsam::KeySet& keys, const std::string& s, const KeyFormatter& keyFormatter) {
cout << s << " ";
if (keys.empty())
cout << "(none)" << endl;
else {
BOOST_FOREACH(const gtsam::Key& key, keys)
cout << keyFormatter(key) << " ";
cout << endl;
}
}
/* ************************************************************************* */
gtsam::KeySet keyIntersection(const gtsam::KeySet& keysA, const gtsam::KeySet& keysB) {
gtsam::KeySet intersection;
if (keysA.empty() || keysB.empty())
return intersection;
BOOST_FOREACH(const gtsam::Key& key, keysA)
if (keysB.count(key))
intersection.insert(key);
return intersection;
}
/* ************************************************************************* */
bool hasKeyIntersection(const gtsam::KeySet& keysA, const gtsam::KeySet& keysB) {
if (keysA.empty() || keysB.empty())
return false;
BOOST_FOREACH(const gtsam::Key& key, keysA)
if (keysB.count(key))
return true;
return false;
}
/* ************************************************************************* */
gtsam::KeySet keyDifference(const gtsam::KeySet& keysA, const gtsam::KeySet& keysB) {
if (keysA.empty() || keysB.empty())
return keysA;
gtsam::KeySet difference;
BOOST_FOREACH(const gtsam::Key& key, keysA)
if (!keysB.count(key))
difference.insert(key);
return difference;
}
} // \namespace gtsam

View File

@ -0,0 +1,147 @@
/* ----------------------------------------------------------------------------
* GTSAM Copyright 2010, Georgia Tech Research Corporation,
* Atlanta, Georgia 30332-0415
* All Rights Reserved
* Authors: Frank Dellaert, et al. (see THANKS for the full author list)
* See LICENSE for the license information
* -------------------------------------------------------------------------- */
/**
* @file LabeledSymbol.h
* @date Jan 12, 2010
* @author: Alex Cunningham
* @author: Frank Dellaert
* @author: Richard Roberts
*/
#pragma once
#include <gtsam/nonlinear/Symbol.h>
#include <gtsam/nonlinear/Ordering.h>
namespace gtsam {
/**
* Customized version of gtsam::Symbol for multi-robot use
*/
class LabeledSymbol {
protected:
unsigned char c_, label_;
size_t j_;
public:
/** Default constructor */
LabeledSymbol();
/** Copy constructor */
LabeledSymbol(const LabeledSymbol& key);
/** Constructor */
LabeledSymbol(unsigned char c, unsigned char label, size_t j);
/** Constructor that decodes an integer gtsam::Key */
LabeledSymbol(gtsam::Key key);
/** Cast to integer */
operator gtsam::Key() const;
// Testable Requirements
void print(const std::string& s = "") const;
bool equals(const LabeledSymbol& expected, double tol = 0.0) const {
return (*this) == expected;
}
/** return the integer version */
gtsam::Key key() const { return (gtsam::Key) *this; }
/** Retrieve label character */
inline unsigned char label() const { return label_; }
/** Retrieve key character */
inline unsigned char chr() const { return c_; }
/** Retrieve key index */
inline size_t index() const { return j_; }
/** Create a string from the key */
operator std::string() const;
/** Comparison for use in maps */
bool operator<(const LabeledSymbol& comp) const;
bool operator==(const LabeledSymbol& comp) const;
bool operator==(gtsam::Key comp) const;
bool operator!=(const LabeledSymbol& comp) const;
bool operator!=(gtsam::Key comp) const;
/** Return a filter function that returns true when evaluated on a gtsam::Key whose
* character (when converted to a LabeledSymbol) matches \c c. Use this with the
* Values::filter() function to retrieve all key-value pairs with the
* requested character.
*/
// Checks only the type
static boost::function<bool(gtsam::Key)> TypeTest(unsigned char c);
// Checks only the robot ID (label_)
static boost::function<bool(gtsam::Key)> LabelTest(unsigned char label);
// Checks both type and the robot ID
static boost::function<bool(gtsam::Key)> TypeLabelTest(unsigned char c, unsigned char label);
// Converts to upper/lower versions of labels
LabeledSymbol upper() const { return LabeledSymbol(c_, toupper(label_), j_); }
LabeledSymbol lower() const { return LabeledSymbol(c_, tolower(label_), j_); }
// Create a new symbol with a different value
LabeledSymbol newChr(unsigned char c) const { return LabeledSymbol(c, label_, j_); }
LabeledSymbol newLabel(unsigned char label) const { return LabeledSymbol(c_, label, j_); }
private:
/** Serialization function */
friend class boost::serialization::access;
template<class ARCHIVE>
void serialize(ARCHIVE & ar, const unsigned int version) {
ar & BOOST_SERIALIZATION_NVP(c_);
ar & BOOST_SERIALIZATION_NVP(label_);
ar & BOOST_SERIALIZATION_NVP(j_);
}
}; // \class LabeledSymbol
// Helper function for Multi-robot Key Formatter
std::string _multirobotKeyFormatter(gtsam::Key key);
/**
* A KeyFormatter that will check for LabeledSymbol keys, as well as Symbol and plain
* integer keys. This keyformatter will need to be passed in to override the default
* formatter in print functions.
*
* Checks for LabeledSymbol, Symbol and then plain keys, in order.
*/
static const gtsam::KeyFormatter MultiRobotKeyFormatter = &_multirobotKeyFormatter;
/// Version of orderingIndexFormatter using multi-robot formatter
struct MultiRobotLinearFormatter : gtsam::OrderingIndexFormatter {
MultiRobotLinearFormatter(const gtsam::Ordering& ordering)
: gtsam::OrderingIndexFormatter(ordering, MultiRobotKeyFormatter) {}
};
/// Utility function to print sets of keys with optional prefix
void printKeySet(const KeySet& keys, const std::string& s = "",
const KeyFormatter& keyFormatter = DefaultKeyFormatter);
/// Computes the intersection between two sets
gtsam::KeySet keyIntersection(const gtsam::KeySet& keysA, const gtsam::KeySet& keysB);
/// Checks if an intersection exists - faster checking size of above
bool hasKeyIntersection(const gtsam::KeySet& keysA, const gtsam::KeySet& keysB);
/// Computes a difference between sets, so result is those that are in A, but not B
gtsam::KeySet keyDifference(const gtsam::KeySet& keysA, const gtsam::KeySet& keysB);
} // \namespace gtsam

View File

@ -0,0 +1,69 @@
/* ----------------------------------------------------------------------------
* GTSAM Copyright 2010, Georgia Tech Research Corporation,
* Atlanta, Georgia 30332-0415
* All Rights Reserved
* Authors: Frank Dellaert, et al. (see THANKS for the full author list)
* See LICENSE for the license information
* -------------------------------------------------------------------------- */
/*
* @file testLabeledSymbol.cpp
* @author Alex Cunningham
*/
#include <boost/assign/std/list.hpp> // for operator +=
using namespace boost::assign;
#include <CppUnitLite/TestHarness.h>
#include <gtsam/base/Testable.h>
#include <gtsam/base/TestableAssertions.h>
#include <gtsam/nonlinear/LabeledSymbol.h>
using namespace std;
using namespace gtsam;
/* ************************************************************************* */
TEST( testLabeledSymbol, KeyLabeledSymbolConversion ) {
LabeledSymbol expected('x', 'A', 4);
Key key(expected);
LabeledSymbol actual(key);
EXPECT(assert_equal(expected, actual))
}
/* ************************************************************************* */
TEST( testLabeledSymbol, KeyLabeledSymbolEncoding ) {
// Test encoding of LabeledSymbol <-> size_t <-> string
// Encoding scheme:
// Top 8 bits: variable type (255 possible values) - zero will not process
// Next 8 high bits: variable type (255 possible values)
// TODO: use fewer bits for type - only 4 or 5 should be necessary - will need more decoding
if(sizeof(Key) == 8) {
LabeledSymbol symbol(0x78, 0x41, 5);
Key key = 0x7841000000000005;
string str = "xA5";
EXPECT_LONGS_EQUAL(key, (Key)symbol);
EXPECT(assert_equal(str, MultiRobotKeyFormatter(symbol)));
EXPECT(assert_equal(symbol, LabeledSymbol(key)));
} else if(sizeof(Key) == 4) {
LabeledSymbol symbol(0x78, 0x41, 5);
Key key = 0x78410005;
string str = "xA5";
EXPECT_LONGS_EQUAL(key, (Key)symbol);
EXPECT(assert_equal(str, DefaultKeyFormatter(symbol)));
EXPECT(assert_equal(symbol, LabeledSymbol(key)));
}
}
/* ************************************************************************* */
int main() { TestResult tr; return TestRegistry::runAllTests(tr); }
/* ************************************************************************* */