Reworked ordering to work with symbols, large keys, and non-zero indexed keys. No longer subtract min key to send to metis, but now creates bimap between keys and int values used in metis

release/4.3a0
Andrew Melim 2014-11-24 02:06:40 -05:00
parent c92b7cca8c
commit 7aa07a9e16
4 changed files with 64 additions and 81 deletions

View File

@ -27,8 +27,8 @@ namespace gtsam {
template<class FACTOR>
void MetisIndex::augment(const FactorGraph<FACTOR>& factors)
{
std::map<Key, FastSet<Key> > adjMap;
std::map<Key, FastSet<Key> >::iterator adjMapIt;
std::map<idx_t, FastSet<idx_t> > iAdjMap; // Stores a set of keys that are adjacent to key x, with adjMap.first
std::map<idx_t, FastSet<idx_t> >::iterator iAdjMapIt;
std::set<Key> keySet;
/* ********** Convert to CSR format ********** */
@ -37,31 +37,43 @@ void MetisIndex::augment(const FactorGraph<FACTOR>& factors)
// starting at index xadj[i] and ending at(but not including)
// index xadj[i + 1](i.e., adjncy[xadj[i]] through
// and including adjncy[xadj[i + 1] - 1]).
idx_t keyCounter = 0;
// First: Record a copy of each key inside the factorgraph and create a
// key to integer mapping. This is referenced during the adjaceny step
for (size_t i = 0; i < factors.size(); i++){
if (factors[i])
BOOST_FOREACH(const Key& key, *factors[i]){
keySet.insert(keySet.end(), key); // Keep a track of all unique keys
if (intKeyBMap_.left.find(key) == intKeyBMap_.left.end()){
intKeyBMap_.insert(bm_type::value_type(key, keyCounter));
keyCounter++;
}
}
}
// Create an adjacency mapping that stores the set of all adjacent keys for every key
for (size_t i = 0; i < factors.size(); i++){
if (factors[i]){
BOOST_FOREACH(const Key& k1, *factors[i]){
BOOST_FOREACH(const Key& k2, *factors[i]){
if (k1 != k2)
adjMap[k1].insert(adjMap[k1].end(), k2); // Insert at the end
}
keySet.insert(keySet.end(), k1); // Keep a track of all unique keySet
}
BOOST_FOREACH(const Key& k1, *factors[i])
BOOST_FOREACH(const Key& k2, *factors[i])
if (k1 != k2){
// Store both in Key and idx_t format
int i = intKeyBMap_.left.at(k1);
int j = intKeyBMap_.left.at(k2);
iAdjMap[i].insert(iAdjMap[i].end(), j);
}
}
}
// Number of keys referenced in this factor graph
nKeys_ = keySet.size();
// Starting with a nonzero key crashes METIS
// Find the smallest key in the graph
minKey_ = *keySet.begin(); // set is ordered
xadj_.push_back(0);// Always set the first index to zero
for (adjMapIt = adjMap.begin(); adjMapIt != adjMap.end(); ++adjMapIt) {
std::vector<Key> temp;
for (iAdjMapIt = iAdjMap.begin(); iAdjMapIt != iAdjMap.end(); ++iAdjMapIt) {
std::vector<idx_t> temp;
// Copy from the FastSet into a temporary vector
std::copy(adjMapIt->second.begin(), adjMapIt->second.end(), std::back_inserter(temp));
std::copy(iAdjMapIt->second.begin(), iAdjMapIt->second.end(), std::back_inserter(temp));
// Insert each index's set in order by appending them to the end of adj_
adj_.insert(adj_.end(), temp.begin(), temp.end());
//adj_.push_back(temp);

View File

@ -25,12 +25,14 @@
#include <gtsam/base/timing.h>
#include <gtsam/inference/Key.h>
#include <gtsam/inference/FactorGraph.h>
#include <metis.h>
#include <boost/bimap.hpp>
namespace gtsam {
/**
* The MetisIndex class converts a factor graph into the Compressed Sparse Row format for use in
* METIS algorithms. Specifically, two vectors store the adjacency structure of the graph. It is built
* fromt a factor graph prior to elimination, and stores the list of factors
* from a factor graph prior to elimination, and stores the list of factors
* that involve each variable.
* \nosubgrouping
*/
@ -38,13 +40,15 @@ class GTSAM_EXPORT MetisIndex
{
public:
typedef boost::shared_ptr<MetisIndex> shared_ptr;
typedef boost::bimap<Key, idx_t> bm_type;
private:
FastVector<Key> xadj_; // Index of node's adjacency list in adj
FastVector<Key> adj_; // Stores ajacency lists of all nodes, appended into a single vector
size_t nFactors_; // Number of factors in the original factor graph
size_t nKeys_; //
size_t minKey_;
FastVector<idx_t> xadj_; // Index of node's adjacency list in adj
FastVector<idx_t> adj_; // Stores ajacency lists of all nodes, appended into a single vector
FastVector<idx_t> iadj_; // Integer keys for passing into metis. One to one mapping with adj_;
boost::bimap<Key, idx_t> intKeyBMap_; // Stores Key <-> integer value relationship
size_t nFactors_; // Number of factors in the original factor graph
size_t nKeys_;
public:
/// @name Standard Constructors
@ -69,10 +73,13 @@ public:
template<class FACTOR>
void augment(const FactorGraph<FACTOR>& factors);
std::vector<Key> xadj() const { return xadj_; }
std::vector<Key> adj() const { return adj_; }
size_t nValues() const { return nKeys_; }
size_t minKey() const { return minKey_; }
std::vector<idx_t> xadj() const { return xadj_; }
std::vector<idx_t> adj() const { return adj_; }
size_t nValues() const { return nKeys_; }
Key intToKey(idx_t value) const {
assert(value >= 0);
return intKeyBMap_.right.find(value)->second;
}
/// @}
};

View File

@ -204,56 +204,20 @@ namespace gtsam {
{
gttic(Ordering_METIS);
vector<Key> xadj = met.xadj();
vector<Key> adj = met.adj();
Key minKey = met.minKey();
// TODO(Andrew): Debug
Key min = std::numeric_limits<Key>::max();
for (int i = 0; i < adj.size(); i++)
{
if (adj[i] < min)
min = adj[i];
}
std::cout << "Min: " << min << " minkey: " << minKey << std::endl;
// Normalize, subtract the smallest key
//std::transform(adj.begin(), adj.end(), adj.begin(), std::bind2nd(std::minus<Key>(), minKey));
for (vector<Key>::iterator it = adj.begin(); it != adj.end(); ++it)
*it = *it - minKey;
// Cast the adjacency formats into idx_t (int32)
// NOTE: Keys can store quite large values and hence may overflow during conversion to int
// It's important that the normalization is performed first.
vector<idx_t> adj_idx;
for (vector<Key>::iterator it = adj.begin(); it != adj.end(); ++it)
adj_idx.push_back(static_cast<int>(*it));
vector<idx_t> xadj_idx;
for (vector<Key>::iterator it = xadj.begin(); it != xadj.end(); ++it)
xadj_idx.push_back(static_cast<int>(*it));
// TODO(Andrew): Debug
for (int i = 0; i < adj.size(); i++)
{
assert(adj[i] >= 0);
if (adj[i] < 0)
std::cout << adj[i] << std::endl;
}
vector<idx_t> xadj = met.xadj();
vector<idx_t> adj = met.adj();
vector<idx_t> perm, iperm;
idx_t size = met.nValues();
for (idx_t i = 0; i < size; i++)
{
perm.push_back(0);
iperm.push_back(0);
}
idx_t size = met.nValues();
for (idx_t i = 0; i < size; i++)
{
perm.push_back(0);
iperm.push_back(0);
}
int outputError;
outputError = METIS_NodeND(&size, &xadj_idx[0], &adj_idx[0], NULL, NULL, &perm[0], &iperm[0]);
outputError = METIS_NodeND(&size, &xadj[0], &adj[0], NULL, NULL, &perm[0], &iperm[0]);
Ordering result;
if (outputError != METIS_OK)
@ -262,11 +226,11 @@ namespace gtsam {
return result;
}
result.resize(size);
for (size_t j = 0; j < size; ++j){
// We have to add the minKey value back to obtain the original key in the Values
result[j] = (Key)perm[j] + minKey;
}
result.resize(size);
for (size_t j = 0; j < size; ++j){
// We have to add the minKey value back to obtain the original key in the Values
result[j] = met.intToKey(perm[j]);
}
return result;
}

View File

@ -159,18 +159,18 @@ TEST(Ordering, csr_format_3) {
vector<int> xadjExpected, adjExpected;
xadjExpected += 0, 1, 4, 6, 8, 10;
adjExpected += 1, 0, 2, 4, 1, 3, 2, 4, 1, 3;
size_t minKey = mi.minKey();
//size_t minKey = mi.minKey();
vector<int> adjAcutal = mi.adj();
// Normalize, subtract the smallest key
std::transform(adjAcutal.begin(), adjAcutal.end(), adjAcutal.begin(),
std::bind2nd(std::minus<size_t>(), minKey));
//std::transform(adjAcutal.begin(), adjAcutal.end(), adjAcutal.begin(),
// std::bind2nd(std::minus<size_t>(), minKey));
EXPECT(xadjExpected == mi.xadj());
EXPECT(adjExpected.size() == mi.adj().size());
EXPECT(adjExpected == adjAcutal);
}
/* ************************************************************************* */