boost :: property_map是如何在boost中实现的,以及如何更改它

时间:2014-04-23 14:19:27

标签: c++ algorithm boost graph boost-graph

我想知道如何在boost图中实现属性映射。例如,

我的顶点和边缘属性定义如下:

 //vertex property:-->
 struct NodeInfo {  int a , b , c; };   //actual bundled property

 struct NodeInfoPropertyTag {               // tag and kind  (as in boost documentation)
      typedef boost::vertex_property_tag kind;
      static  std::size_t const num;
 };

 std::size_t const NodeInfoPropertyTag::num = (std::size_t) &NodeInfoPropertyTag::num;

 //typedef the Vertex Property
 typedef boost::property <NodeInfoPropertyTag, NodeInfo>  NodeProperty;


 //Similar fashion for Edge Property --> some property for each edge of graph.
 typedef boost::property <EdgeInfoPropertyTag, EdgeInfo>  EdgeProperty;

我的图表是typedef&#39; d如下:

 typedef boost::adjacency_list <vecS, vecS, undirectedS, NodeProperty, EdgeProperty, no_property, listS>   Graph_t;

现在,在使用上面的typedef初始化图G时,我可以使用属性为顶点和边指定属性

例如:

  Graph_t  G;
  typedef graph_traits<Graph_t>::vertex_descriptor   vd_t;
  // edge_descriptor   ed_t;

  NodeInfo   ninfo1, ninfo2;   //put some values in ninfo  
  vd_t  v = add_vertex (ninfo1, G)   //add a vertex in G with property ninfo1 
  vd_t  u = add_vertex (ninfo2, G)   //add a vertex in G with property ninfo2


  EdgeInfo  einfo;   //initialize edgeinfo  for edge property
  add_edge (u, v, einfo, G )   edge (u, v) with property einfo is added in G

要访问任何顶点的节点属性,我可以使用以下两种方法中的任何一种:

 //method 1: direct method: using Tags

 // for a vertex "v" -->  get()
 NodInfo   info  =  boost::get (NodeInfoPropertyTag(), G, v)   //get v's property

 //modify  info  

 //put the modified property
  put (NodeInfoPropertyTag(), G, v, info)    // (put in G, key = v, value = info )


 //method 2 : using property maps.

 //Edge Map and Node Map  
 typedef typename boost::property_map <Graph_t, EdgeInfoPropertyTag>::type  EdgeMap;
 typedef typename boost::property_map <Graph_t, NodeInfoPropertyTag>::type  NodeMap;


 //edge e --> get
 EdgeInfo  einfo = boost::get (EdgeMap, e)

 //modify einfo

 //put 
 put (EdgeMap, e, einfo)   //put in the EdgeMap  key = e, value = einfo

现在,两个操作基本相同:即使用

  //former is translated to the latter --> 
  get(NodeInfoPropertyTag(), G, "key")   is equivalent to  get (NodeMap, "key")

我的问题是:

  1. 这些属性如何存储在Graph对象中。
  2. 是否存储在地图中,例如std :: map&lt;&gt; ?还是一些清单?或者一些有效的类似地图的数据结构。
  3. 如果是这样,我如何将基础数据结构修改为std :: unordered_map甚至 concurrent_hashmap或boost :: vector_property_map?
  4. 注意: 我不确定我可以使用vector_prop_map(这里),但我真的想使用它 顶点id成为矢量索引并且更有效 - &gt;它可能会导致边缘问题

    我的图形将包含一百万个顶点和许多边缘,以这种方式搜索 std :: map&lt;&gt;仍然是log(n),但我希望可移植性改变 底层数据结构,以便我可以使用unordered_map / concurrent_hashmap

    我需要concurrent_hashmap(来自英特尔TBB)因为我将并行化我的算法 因此希望并行访问将要的属性映射 由线程修改。

    请建议是否可以在boost图中控制和修改这些底层数据结构,以存储边缘和顶点属性。

1 个答案:

答案 0 :(得分:3)

  

这些属性如何存储在Graph对象中。

不会单独存储属性或类似地存储属性。

顶点和边缘属性存储在图形的顶点和边缘内。没有使用std::map或其他一些关联容器。无论您为adjacency_list提供什么,因为VertexProperties和EdgeProperties模板参数将存储在顶点和边缘中,即,它与使用std::list<T>时相同,其中T将存储在链表的节点中(以及必要的next-prev指针)。换句话说,adjacency_list将存储包含VertexProperties类型的对象的顶点,以及所需的任何边缘列表(in和out)。

当你使用property_map(通过get / put函数)时,它只是做了一些模板元编程魔术来创建一个瘦包装器,它只是读取/写入顶点的正确单个属性或边缘。从概念上讲,这是等价的:

NodeInfo info = boost::get (NodeInfoPropertyTag(), G, v);

// is conceptual equivalent to:

NodeInfo info = G[v].NodeInfoProperty;

这是属性映射的全部内容,它查找顶点属性(通过给定图形对象中的顶点描述符),并获取对应的顶点属性的数据成员(或子对象)到给定的标签类型。弄清楚如何为正确的属性标记获取正确的数据成员(或子对象)是一个模板元编程魔术,它在编译时计算出来(没有运行时开销)。并且,通常,从顶点描述符中查找顶点属性是一个常量时间操作(例如,取消引用指针,按索引查找等)。

总的来说,为特定顶点提取(读取或写入)特定属性是一个恒定时间操作。对于您使用adjacency_list的模板参数做出的任何选择都是如此。据我所知。

  

如果是这样,我如何将底层数据结构修改为std :: unordered_map甚至concurrent_hashmap或boost :: vector_property_map?

您可以通过OutEdgeList,VertexList和EdgeList指定要存储顶点和边的方式。属性本身没有其他存储方法。在这些环境中使用地图或哈希图并没有多大意义。

  

我真的想使用它,以便顶点id成为矢量索引

当您为vecS参数指定VertexList时,adjacency_list就是这种情况。

  

我需要concurrent_hashmap(来自英特尔TBB),因为我将并行化我的算法,因此希望并行访问将由线程修改的属性映射。

您应该考虑使用Parallel Graph库。

  

请建议是否可以在boost图中控制和修改这些底层数据结构,以存储边缘和顶点属性。

您可以指定用于存储顶点和边列表的数据结构。您也可以(理论上)为这些容器添加新类型的容器。但是,根据我的经验,这真的很难,因为adjacency_list的实现非常难以理解,并且交换其底层容器并不像Boost网站上宣传的那么简单。