2013-03-22 47 views
1

我正在寻找一个智能的方式来使用增强图库Boost uBLAS。更确切地说,我需要通过使用图表邻接矩阵之间的标量产品的结果和包含每个顶点的一些其他顶点属性的向量来更新每个顶点的给定顶点属性。让我给你一个(可惜lenghty)小例子来说明这个问题:现在如何调整boost :: property_map以像使用ublas :: vector一样使用它?

#include <boost/graph/adjacency_list.hpp> 
#include <boost/graph/iteration_macros.hpp> 
#include <boost/numeric/ublas/matrix.hpp> 
#include <boost/numeric/ublas/io.hpp> 

using namespace boost; 
namespace ublas = boost::numeric::ublas; 


struct Vertex {    //Using bundled vertex properties 

     double old_potential; 
     double new_potential; 
}; 


typedef adjacency_list< listS, vecS, directedS, Vertex > Graph; 

int main(){ 

    //[Prepare a graph with two vertex property maps and initialize 
    Graph graph; 
    add_edge (0, 1, graph); 
    add_edge (0, 3, graph); 
    add_edge (1, 2, graph); 

    auto v_old_potential = boost::get(&Vertex::old_potential, graph); 
    auto v_new_potential = boost::get(&Vertex::new_potential, graph); 

    unsigned int source_strength = 0; 

    BGL_FORALL_VERTICES(v, graph, Graph) { 

    v_old_potential[v] = source_strength++; 
    v_new_potential[v] = 0; 
    } 
    //] 


    //[ Extracting the adjacency matrix by iteration through all edges --> uBLAS matrix 
    ublas::zero_matrix<int> zero_matrix(num_vertices(graph) , num_vertices(graph)); 
    ublas::matrix<int> adjacency_matrix(zero_matrix);  //initialize properly 

    BGL_FORALL_EDGES(e, graph, Graph) { 

    adjacency_matrix(source(e,graph), target(e,graph)) = 1; 
    adjacency_matrix(target(e,graph), source(e,graph)) = 1; 
    } 
    //] 


    //[ Extracting the old potentials by iteration through all vertices --> uBLAS vector 
    ublas::zero_vector<double> zero_vector(num_vertices(graph)); 
    ublas::vector<double> old_potential_vector(zero_vector); //initialize properly 
    ublas::vector<double> new_potential_vector(zero_vector); //initialize properly 

    BGL_FORALL_VERTICES(v, graph, Graph) { 

     old_potential_vector(vertex(v,graph)) = v_old_potential[v]; 
    } 
    //] 


    //[ Compute new potentials = A . old potentials ! 
    new_potential_vector = ublas::prod (adjacency_matrix, old_potential_vector);  //  new = A.old 
    //] 


    //[ Updating the property map for the new potentials with the newly computed values from above 
    BGL_FORALL_VERTICES(v, graph, Graph) { 

     v_new_potential[v] = old_potential_vector(vertex(v,graph)); 
    } 
    //] 

    std::cout << adjacency_matrix << std::endl;  //output = [4,4]((0,1,0,1),(1,0,1,0),(0,1,0,0),(1,0,0,0)) 
    std::cout << old_potential_vector << std::endl; //output = [4](0,1,2,3) 
    std::cout << new_potential_vector << std::endl; //output = [4](4,2,1,0) 

} 

,而我的建议是一个可行的解决方案,我不是很满意。问题是,(a)我复制整个old_potential属性映射到相关的ublas::vector为了计算标量乘积。并且(b)我需要遍历new_potential属性映射以及将新计算的值返回到图形中。 我怀疑这些操作会在我的应用程序中重复很多,这就是为什么我想从一开始就完成这个部分尽可能干净的原因。

理想情况下,我想用这些拷贝做来回,而是使用某种适配器的做出boost::property_map工作作为ublas::vectorprod()呼叫。这将是真棒使用这样的事情:

adapter(new_potential) = ublas::prod(adjacency_matrix, adapter(old_potential)); 

如果任何人有一个想法如何实现这样的功能或如何提高自己的解决方案,我将非常感激。

回答

1
#include <iostream> 
#include <memory> 
#include <boost/graph/adjacency_list.hpp> 
#include <boost/graph/iteration_macros.hpp> 
#include <boost/numeric/ublas/matrix.hpp> 
#include <boost/numeric/ublas/io.hpp> 

using namespace boost; 
namespace ublas = boost::numeric::ublas; 

enum vertex_old_potential_t { vertex_old_potential }; 
enum vertex_new_potential_t { vertex_new_potential }; 

namespace boost 
{ 
    BOOST_INSTALL_PROPERTY(vertex, new_potential); 
    BOOST_INSTALL_PROPERTY(vertex, old_potential); 
} 

typedef property<vertex_new_potential_t, double, property<vertex_old_potential_t,double> > Vertex; 


typedef adjacency_list< listS, vecS, directedS, Vertex > Graph; 

struct ublas_vector_map; 

namespace boost { 
    template<> 
    struct property_map< Graph, vertex_new_potential_t > { 
    typedef ublas_vector_map type; 
    typedef ublas_vector_map const_type; 
    }; 

    template<> 
    struct property_map< Graph, vertex_old_potential_t > { 
    typedef ublas_vector_map type; 
    typedef ublas_vector_map const_type; 
    }; 
} 

struct ublas_vector_map : put_get_helper<double&,ublas_vector_map> { 
    typedef double value_type; 
    typedef value_type& reference; 
    typedef typename graph_traits<Graph>::vertex_descriptor key_type; 
    typedef boost::lvalue_property_map_tag category; 

    ublas_vector_map(Graph* g, vertex_old_potential_t&):vec(new ublas::vector<double>(num_vertices(*g),0.0)){} 
    ublas_vector_map(Graph* g, vertex_new_potential_t&):vec(new ublas::vector<double>(num_vertices(*g),0.0)){} 


    reference operator[](key_type v) const { 
    return (*vec)(v); 
    } 

    ublas::vector<double>& vector() { return *vec; } 

    private: 
    std::unique_ptr<ublas::vector<double> > vec; 
}; 

int main(){ 

    //[Prepare a graph with two vertex property maps and initialize 
    Graph graph; 
    add_edge (0, 1, graph); 
    add_edge (0, 3, graph); 
    add_edge (1, 2, graph); 

    auto v_old_potential = boost::get(vertex_old_potential, graph); 
    auto v_new_potential = boost::get(vertex_new_potential, graph); 

    unsigned int source_strength = 0; 

    BGL_FORALL_VERTICES(v, graph, Graph) { 

    v_old_potential[v] = source_strength++; 
    } 
    //] 


    //[ Extracting the adjacency matrix by iteration through all edges --> uBLAS matrix 
    ublas::zero_matrix<int> zero_matrix(num_vertices(graph) , num_vertices(graph)); 
    ublas::matrix<int> adjacency_matrix(zero_matrix);  //initialize properly 

    BGL_FORALL_EDGES(e, graph, Graph) { 

    adjacency_matrix(source(e,graph), target(e,graph)) = 1; 
    adjacency_matrix(target(e,graph), source(e,graph)) = 1; 
    } 
    //] 



    //[ Compute new potentials = A . old potentials ! 
    v_new_potential.vector() = ublas::prod (adjacency_matrix, v_old_potential.vector());  //  new = A.old 
    //] 




    std::cout << adjacency_matrix << std::endl;  //output = [4,4]((0,1,0,1),(1,0,1,0),(0,1,0,0),(1,0,0,0)) 
    std::cout << v_old_potential.vector() << std::endl; //output = [4](0,1,2,3) 
    std::cout << v_new_potential.vector() << std::endl; //output = [4](4,2,1,0) 

    //You must access the properties via v_new_potential and v_old_potential, if you use get... again it resets 
    std::cout << v_new_potential[0] << std::endl; 
    std::cout << get(vertex_new_potential, graph)[0] << std::endl; 

} 
+0

感谢您的解决方案,它编译和工作。但是,您是否可以想到一种使捆绑属性也可以使用的方法?在BGL文件中,它表示,财产清单的使用在某些时候已经或将要贬值。我试图调整你的代码以获得捆绑的属性,但是我不知道如何在没有可用'vertex_potential_t'标签的情况下达到目的。 – mtd 2013-03-25 09:12:30