Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Extract the adjacency matrix from a BGL graph

Using the Boost Graph Library I am looking for a way to extract the adjacency matrix from an underlying graph represented by either boost::adjacency_list or boost::adjacency_matrix. I'd like to use this matrix in conjunction with boost::numeric::ublas to solve a system of simultaneous linear equations.

Here is a minimal example to get you going:

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/adjacency_matrix.hpp>

using namespace boost;

typedef boost::adjacency_list< listS, vecS, directedS > ListGraph;
typedef boost::adjacency_matrix< directedS > MatrixGraph;

int main(){ 

  ListGraph lg; 
  add_edge (0, 1, lg); 
  add_edge (0, 3, lg); 
  add_edge (1, 2, lg); 
  add_edge (2, 3, lg); 

  //How do I get the adjacency matrix underlying lg?

  MatrixGraph mg(3); 
  add_edge (0, 1, mg); 
  add_edge (0, 3, mg); 
  add_edge (1, 2, mg); 
  add_edge (2, 3, mg); 

  //How do I get the adjacency matrix underlying mg?

}

If anyone could come up with an efficient way to obtain the adjacency matrix I would be much obliged. Ideally the solution is compatible with uBLAS. I wonder if there is a way to avoid iteration through the entire graph.

like image 381
mtd Avatar asked Mar 21 '13 11:03

mtd


1 Answers

The easiest way to convert adjacency_list into adjacency_matrix is to use boost::copy_graph

Your code for MatrixGraph mg should be modified as follows

#include <boost/graph/copy.hpp>
#include <cassert>

using namespace boost;

typedef boost::adjacency_list< listS, vecS, directedS > ListGraph;
typedef boost::adjacency_matrix< directedS > MatrixGraph;

int main(){

    ListGraph lg;
    add_edge(0, 1, lg);
    add_edge(0, 3, lg);
    add_edge(1, 2, lg);
    add_edge(2, 3, lg);

    //How do I get the adjacency matrix underlying lg?

    //How do I get the adjacency matrix underlying mg?   
    MatrixGraph mg( num_vertices(lg));
    boost::copy_graph(lg, mg);
}

Now, to use adjacency matrix with ublas or similar, you can write a simple "access" class to make syntax more compliant with ublas. Continuing previous snippet we get:

template <class Graph>
class MatrixAccessor
{
public:
    typedef typename Graph::Matrix Matrix; //actually a vector<
    typedef typename Matrix::const_reference const_reference;


    MatrixAccessor(const Graph* g)
        : m_g(g)
    {
        static_assert(boost::is_same<size_t, typename Graph::vertex_descriptor>::value, "Vertex descriptor should be of integer type");
    }

    const_reference operator()(size_t u, size_t v) const
    {
        return m_g->get_edge(u, v);
    }

    const Graph* m_g;
};

void use_matrix(const MatrixGraph & mg)
{
    MatrixAccessor<MatrixGraph> matr(&mg);
    assert(matr(0, 1) == 1);
    assert(matr(0, 2) == 0);
}

In case your adjacency_matrix has some edge-bundled properties, you might need to modify the operator() in MatrixAccessor.

Depending on how much uBLAS you use, you can refine MatrixAccessor further. For example, out_edge_iterator for a given vertex of a MatrixGraph is actually an iterator over matrix column; vertex_iterator can be treated as iterator over matrix rows, etc.

Of course, graph matrix is immutable and as such should be used with care.

like image 55
Michael Simbirsky Avatar answered Oct 15 '22 20:10

Michael Simbirsky