192 lines
5.1 KiB
C++
192 lines
5.1 KiB
C++
/* ----------------------------------------------------------------------------
|
|
|
|
* 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
|
|
|
|
* -------------------------------------------------------------------------- */
|
|
|
|
/*
|
|
* timeSymbolMaps.cpp
|
|
*
|
|
* Created on: Jan 20, 2010
|
|
* Author: richard
|
|
*/
|
|
|
|
#include <boost/unordered_map.hpp>
|
|
#include <string>
|
|
#include <boost/timer.hpp>
|
|
#include <boost/lexical_cast.hpp>
|
|
#include <vector>
|
|
#include <map>
|
|
|
|
#include <gtsam/nonlinear/Key.h>
|
|
|
|
using namespace std;
|
|
using namespace boost;
|
|
using namespace gtsam;
|
|
|
|
template<class T>
|
|
class SymbolMapExp {
|
|
private:
|
|
typedef map<unsigned char, vector<T> > Map;
|
|
typedef vector<T> Vec;
|
|
|
|
Map values_;
|
|
|
|
public:
|
|
typedef pair<Symbol, T> value_type;
|
|
|
|
SymbolMapExp() {}
|
|
|
|
T& at(const Symbol& key) {
|
|
typename Map::iterator it = values_.find(key.chr());
|
|
if(it != values_.end())
|
|
return it->second.at(key.index());
|
|
else
|
|
throw invalid_argument("Key " + (string)key + " not present");
|
|
}
|
|
|
|
void set(const Symbol& key, const T& value) {
|
|
Vec& vec(values_[key.chr()]);
|
|
//vec.reserve(10000);
|
|
if(key.index() >= vec.size()) {
|
|
vec.reserve(key.index()+1);
|
|
vec.resize(key.index());
|
|
vec.push_back(value);
|
|
} else
|
|
vec[key.index()] = value;
|
|
}
|
|
};
|
|
|
|
template<class T>
|
|
class SymbolMapBinary : public std::map<Symbol, T> {
|
|
private:
|
|
typedef std::map<Symbol, T> Base;
|
|
public:
|
|
SymbolMapBinary() : std::map<Symbol, T>() {}
|
|
|
|
T& at(const Symbol& key) {
|
|
typename Base::iterator it = Base::find(key);
|
|
if (it == Base::end())
|
|
throw(std::invalid_argument("SymbolMap::[] invalid key: " + (std::string)key));
|
|
return it->second;
|
|
}
|
|
};
|
|
|
|
struct SymbolHash : public std::unary_function<Symbol, std::size_t> {
|
|
std::size_t operator()(Symbol const& x) const {
|
|
std::size_t seed = 0;
|
|
boost::hash_combine(seed, x.chr());
|
|
boost::hash_combine(seed, x.index());
|
|
return ((size_t(x.chr()) << 24) & x.index());
|
|
}
|
|
};
|
|
|
|
template<class T>
|
|
class SymbolMapHash : public boost::unordered_map<Symbol, T, SymbolHash> {
|
|
public:
|
|
SymbolMapHash() : boost::unordered_map<Symbol, T, SymbolHash>(60000) {}
|
|
};
|
|
|
|
struct Value {
|
|
double v;
|
|
Value() : v(0.0) {}
|
|
Value(double vi) : v(vi) {}
|
|
operator string() { return lexical_cast<string>(v); }
|
|
bool operator!=(const Value& vc) { return v != vc.v; }
|
|
};
|
|
|
|
#define ELEMS 3000
|
|
#define TIMEAT 300
|
|
|
|
int main(int argc, char *argv[]) {
|
|
timer tmr;
|
|
|
|
// pre-allocate
|
|
cout << "Generating test data ..." << endl;
|
|
vector<pair<Symbol, Value> > values;
|
|
for(size_t i=0; i<ELEMS; i++) {
|
|
values.push_back(make_pair(Symbol('a',i), (double)i));
|
|
values.push_back(make_pair(Symbol('b',i), (double)i));
|
|
values.push_back(make_pair(Symbol('c',i), (double)i));
|
|
}
|
|
|
|
// time binary map
|
|
cout << "Timing binary map ..." << endl;
|
|
{
|
|
SymbolMapBinary<Value> binary;
|
|
for(size_t i=0; i<ELEMS*3; ) {
|
|
size_t stop = i + TIMEAT;
|
|
tmr.restart();
|
|
for( ; i<stop; i++)
|
|
binary.insert(values[i]);
|
|
double time = tmr.elapsed();
|
|
cout << i << " values, avg " << (time/(double)TIMEAT)*1e6 << " mu-s per insert" << endl;
|
|
|
|
tmr.restart();
|
|
for(size_t j=0; j<i; j++)
|
|
if(values[j].second != binary[values[j].first]) {
|
|
cout << "Wrong value! At key " << (string)values[j].first <<
|
|
" expecting " << (string)values[j].second <<
|
|
" got " << (string)binary[values[j].first] << endl;
|
|
}
|
|
time = tmr.elapsed();
|
|
cout << i << " values, avg " << (time)*1e3 << " ms per lookup" << endl;
|
|
}
|
|
}
|
|
|
|
// time hash map
|
|
cout << "Timing hash map ..." << endl;
|
|
{
|
|
SymbolMapHash<Value> hash;
|
|
for(size_t i=0; i<ELEMS*3; ) {
|
|
size_t stop = i + TIMEAT;
|
|
tmr.restart();
|
|
for( ; i<stop; i++)
|
|
hash.insert(values[i]);
|
|
double time = tmr.elapsed();
|
|
cout << i << " values, avg " << (time/(double)TIMEAT)*1e6 << " mu-s per insert" << endl;
|
|
|
|
tmr.restart();
|
|
for(size_t j=0; j<i; j++)
|
|
if(values[j].second != hash[values[j].first]) {
|
|
cout << "Wrong value! At key " << (string)values[j].first <<
|
|
" expecting " << (string)values[j].second <<
|
|
" got " << (string)hash[values[j].first] << endl;
|
|
}
|
|
time = tmr.elapsed();
|
|
cout << i << " values, avg " << (time/(double)i)*1e6 << " mu-s per lookup" << endl;
|
|
}
|
|
}
|
|
|
|
// time experimental map
|
|
cout << "Timing experimental map ..." << endl;
|
|
{
|
|
SymbolMapExp<Value> experimental;
|
|
for(size_t i=0; i<ELEMS*3; ) {
|
|
size_t stop = i + TIMEAT;
|
|
tmr.restart();
|
|
for( ; i<stop; i++)
|
|
experimental.set(values[i].first, values[i].second);
|
|
double time = tmr.elapsed();
|
|
cout << i << " values, avg " << (time/(double)TIMEAT)*1e6 << " mu-s per insert" << endl;
|
|
|
|
tmr.restart();
|
|
for(size_t j=0; j<i; j++)
|
|
if(values[j].second != experimental.at(values[j].first)) {
|
|
cout << "Wrong value! At key " << (string)values[j].first <<
|
|
" expecting " << (string)values[j].second <<
|
|
" got " << (string)experimental.at(values[j].first) << endl;
|
|
}
|
|
time = tmr.elapsed();
|
|
cout << i << " values, avg " << (time/(double)i)*1e6 << " mu-s per lookup" << endl;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|