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
parent
c92b7cca8c
commit
7aa07a9e16
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
/// @}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
|
|
|
|||
Loading…
Reference in New Issue