using_property_maps.html 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480
  1. <HTML>
  2. <!--
  3. Copyright (c) Jeremy Siek 2000
  4. Distributed under the Boost Software License, Version 1.0.
  5. (See accompanying file LICENSE_1_0.txt or copy at
  6. http://www.boost.org/LICENSE_1_0.txt)
  7. -->
  8. <Head>
  9. <Title>Boost Graph Library: Using Property Maps</Title>
  10. <BODY BGCOLOR="#ffffff" LINK="#0000ee" TEXT="#000000" VLINK="#551a8b"
  11. ALINK="#ff0000">
  12. <IMG SRC="../../../boost.png"
  13. ALT="C++ Boost" width="277" height="86">
  14. <BR Clear>
  15. <H1><A NAME="sec:property-maps"></A>
  16. Property Maps
  17. </H1>
  18. <P>
  19. The main link between the abstract mathematical nature of graphs and
  20. the concrete problems they are used to solve is the properties that
  21. are attached to the vertices and edges of a graph, things like
  22. distance, capacity, weight, color, etc. There are many ways to attach
  23. properties to graph in terms of data-structure implementation, but
  24. graph algorithms should not have to deal with the implementation
  25. details of the properties. The <I>property map</I> interface
  26. defined in Section <A
  27. HREF="../../property_map/doc/property_map.html">Property
  28. Map Concepts</A> provides a generic method for accessing
  29. properties from graphs. This is the interface used in the BGL
  30. algorithms to access properties.
  31. <P>
  32. <H2>Property Map Interface</H2>
  33. <P>
  34. The property map interface specifies that each property is
  35. accessed using a separate property map object. In the following
  36. example we show an implementation of the <TT>relax()</TT> function used
  37. inside of Dijkstra's shortest paths algorithm. In this function, we
  38. need to access the weight property of an edge, and the distance
  39. property of a vertex. We write <TT>relax()</TT> as a template function
  40. so that it can be used in many difference situations. Two of the
  41. arguments to the function, <TT>weight</TT> and <TT>distance</TT>, are the
  42. property map objects. In general, BGL algorithms explicitly pass
  43. property map objects for every property that a function will
  44. need. The property map interface defines several functions, two
  45. of which we use here: <TT>get()</TT> and <TT>put()</TT>. The <TT>get()</TT>
  46. function takes a property map object, such as <TT>distance</TT> and
  47. a <I>key</I> object. In the case of the distance property we are using
  48. the vertex objects <TT>u</TT> and <TT>v</TT> as keys. The <TT>get()</TT>
  49. function then returns the property value for the vertex.
  50. <P>
  51. <PRE>
  52. template &lt;class Edge, class Graph,
  53. class WeightPropertyMap,
  54. class DistancePropertyMap&gt;
  55. bool relax(Edge e, const Graph&amp; g,
  56. WeightPropertyMap weight,
  57. DistancePropertyMap distance)
  58. {
  59. typedef typename graph_traits&lt;Graph&gt;::vertex_descriptor Vertex;
  60. Vertex u = source(e,g), v = target(e,g);
  61. if ( get(distance, u) + get(weight, e) &lt; get(distance, v)) {
  62. put(distance, v, get(distance, u) + get(weight, e));
  63. return true;
  64. } else
  65. return false;
  66. }
  67. </PRE>
  68. The function <TT>get()</TT> returns a copy of the property value. There
  69. is a third function in the property map interface, <TT>at()</TT>,
  70. that returns a reference to the property value (a const reference if
  71. the map is not mutable).
  72. <P>
  73. Similar to the <TT>iterator_traits</TT> class of the STL, there is a
  74. <TT>property_traits</TT> class that can be used to deduce the types
  75. associated with a property map type: the key and value types, and
  76. the property map category (which is used to tell whether the
  77. map is readable, writeable, or both). In the <TT>relax()</TT>
  78. function we could have used <TT>property_traits</TT> to declare local
  79. variables of the distance property type.
  80. <P>
  81. <PRE>
  82. {
  83. typedef typename graph_traits&lt;Graph&gt;::vertex_descriptor Vertex;
  84. Vertex u = source(e,g), v = target(e,g);
  85. typename property_traits&lt;DistancePropertyMap&gt;::value_type
  86. du, dv; // local variables of the distance property type
  87. du = get(distance, u);
  88. dv = get(distance, v);
  89. if (du + get(weight, e) &lt; dv) {
  90. put(distance, v, du + get(weight, e));
  91. return true;
  92. } else
  93. return false;
  94. }
  95. </PRE>
  96. <P>
  97. There are two kinds of graph properties: interior and exterior.
  98. <P>
  99. <DL>
  100. <DT><STRONG>Interior Properties</STRONG></DT>
  101. <DD>are stored ``inside'' the graph object
  102. in some way, and the lifetime of the property value objects is the
  103. same as that of the graph object.
  104. <P>
  105. </DD>
  106. <DT><STRONG>Exterior Properties</STRONG></DT>
  107. <DD>are stored ``outside'' of the graph
  108. object and the lifetime of the property value objects is independent
  109. of the graph. This is useful for properties that are only needed
  110. temporarily, perhaps for the duration of a particular algorithm such
  111. as the color property used in <TT>breadth_first_search()</TT>. When
  112. using exterior properties with a BGL algorithm a property map
  113. object for the exterior property must be passed as an argument to the
  114. algorithm.
  115. </DD>
  116. </DL>
  117. <P>
  118. <H2><A NAME="sec:interior-properties"></A>
  119. Interior Properties
  120. </H2>
  121. <P>
  122. A graph type that supports interior property storage (such as
  123. <TT>adjacency_list</TT>) provides access to its property map
  124. objects through the interface defined in <a
  125. href="./PropertyGraph.html">PropertyGraph</a>. There is a function
  126. <TT>get(Property, g)</TT> that get property map objects from a
  127. graph. The first argument is the property type to specify which
  128. property you want to access and the second argument is the graph
  129. object. A graph type must document which properties (and therefore
  130. tags) it provides access to. The type of the property map depends on
  131. the type of graph and the property being mapped. A trait class is
  132. defined that provides a generic way to deduce the property map type:
  133. <TT>property_map</TT>. The following code shows how one can obtain the
  134. property map for the distance and weight properties of some graph
  135. type.
  136. <P>
  137. <PRE>
  138. property_map&lt;Graph, vertex_distance_t&gt;::type d
  139. = get(vertex_distance, g);
  140. property_map&lt;Graph, edge_weight_t&gt;::type w
  141. = get(edge_weight, g);
  142. </PRE>
  143. <P>
  144. In general, the BGL algorithms require all property maps needed
  145. by the algorithm to be explicitly passed to the algorithm. For
  146. example, the BGL Dijkstra's shortest paths algorithm requires four
  147. property maps: distance, weight, color, and vertex ID.
  148. <P>
  149. Often times some or all of the properties will be interior to the
  150. graph, so one would call Dijkstra's algorithm in the following way
  151. (given some graph <TT>g</TT> and source vertex <TT>src</TT>).
  152. <P>
  153. <PRE>
  154. dijkstra_shortest_paths(g, src,
  155. distance_map(get(vertex_distance, g)).
  156. weight_map(get(edge_weight, g)).
  157. color_map(get(vertex_color, g)).
  158. vertex_index_map(get(vertex_index, g)));
  159. </PRE>
  160. <P>
  161. Since it is somewhat cumbersome to specify all of the property maps,
  162. BGL provides defaults that assume some of the properties are interior
  163. and can be accessed via <TT>get(Property, g)</TT> from the graph, or
  164. if the property map is only used internally, then the algorithm will
  165. create a property map for itself out of an array and using the graph's
  166. vertex index map as the offset into the array. Below we show a call to
  167. <TT>dijkstra_shortest_paths</TT> algorithm using all defaults for the
  168. named parameters. This call is equivalent to the previous call to
  169. Dijkstra's algorithm.
  170. <P>
  171. <PRE>
  172. dijkstra_shortest_paths(g, src);
  173. </PRE>
  174. <P>
  175. The next question is: how do interior properties become attached to a
  176. graph object in the first place? This depends on the graph class that
  177. you are using. The <TT>adjacency_list</TT> graph class of BGL uses a
  178. property mechanism (see Section <A
  179. HREF="using_adjacency_list.html#sec:adjacency-list-properties">Internal
  180. Properties</A>) to allow an arbitrary number of properties to be
  181. stored on the edges and vertices of the graph.
  182. <P>
  183. <H2><A NAME="sec:exterior-properties"></A>
  184. Exterior Properties
  185. </H2>
  186. <P>
  187. In this section we will describe two methods for constructing exterior
  188. property maps, however there is an unlimited number of ways that
  189. one could create exterior properties for a graph.
  190. <P>
  191. The first method uses the adaptor class
  192. <TT>iterator_property_map</TT>. This
  193. class wraps a random access iterator, creating a property map out
  194. of it. The random access iterator must point to the beginning of a
  195. range of property values, and the length of the range must be the
  196. number of vertices or edges in the graph (depending on whether it is a
  197. vertex or edge property map). The adaptor must also be supplied
  198. with an ID property map, which will be used to map the vertex or
  199. edge descriptor to the offset of the property value (offset from the
  200. random access iterator). The ID property map will typically be an
  201. interior property map of the graph. The following example shows
  202. how the <TT>iterator_property_map</TT>
  203. can be used to create exterior property maps for the capacity and flow properties, which are stored in arrays. The arrays are
  204. indexed by edge ID. The edge ID is added to the graph using a property,
  205. and the values of the ID's are given when each edge is added to the
  206. graph. The complete source code for this example is in
  207. <TT>example/exterior_edge_properties.cpp</TT>. The
  208. <TT>print_network()</TT> function prints out the graph with
  209. the flow and capacity values.
  210. <P>
  211. <PRE>
  212. typedef adjacency_list&lt;vecS, vecS, bidirectionalS,
  213. no_property, property&lt;edge_index_t, std::size_t&gt; &gt; Graph;
  214. const int num_vertices = 9;
  215. Graph G(num_vertices);
  216. int capacity_array[] = { 10, 20, 20, 20, 40, 40, 20, 20, 20, 10 };
  217. int flow_array[] = { 8, 12, 12, 12, 12, 12, 16, 16, 16, 8 };
  218. // Add edges to the graph, and assign each edge an ID number.
  219. add_edge(0, 1, 0, G);
  220. // ...
  221. typedef graph_traits&lt;Graph&gt;::edge_descriptor Edge;
  222. typedef property_map&lt;Graph, edge_index_t&gt;::type EdgeID_Map;
  223. EdgeID_Map edge_id = get(edge_index, G);
  224. iterator_property_map
  225. &lt;int*, int, int&amp;, EdgeID_Map&gt;
  226. capacity(capacity_array, edge_id),
  227. flow(flow_array, edge_id);
  228. print_network(G, capacity, flow);
  229. </PRE>
  230. <P>
  231. The second method uses a pointer type (a pointer to an array of
  232. property values) as a property map. This requires the key type to
  233. be an integer so that it can be used as an offset to the pointer. The
  234. <TT>adjacency_list</TT> class with template parameter
  235. <TT>VertexList=vecS</TT> uses integers for vertex descriptors (indexed
  236. from zero to the number of vertices in the graph), so they are
  237. suitable as the key type for a pointer property map. When the
  238. <TT>VertexList</TT> is not <TT>vecS</TT>, then the vertex descriptor is
  239. not an integer, and cannot be used with a pointer property map.
  240. Instead the method described above of using a
  241. <TT>iterator_property_map</TT> with an ID
  242. property must be used. The <TT>edge_list</TT> class may also use an
  243. integer type for the vertex descriptor, depending on how the adapted
  244. edge iterator is defined. The example in
  245. <TT>example/bellman_ford.cpp</TT> shows <TT>edge_list</TT> being used
  246. with pointers as vertex property maps.
  247. <P>
  248. The reason that pointers can be used as property maps is that
  249. there are several overloaded functions and a specialization of
  250. <TT>property_traits</TT> in the header <a
  251. href="../../../boost/property_map/property_map.hpp"><TT>boost/property_map/property_map.hpp</TT></a>
  252. that implement the property map interface in terms of
  253. pointers. The definition of those functions is listed here.
  254. <P>
  255. <PRE>
  256. namespace boost {
  257. template &lt;class T&gt;
  258. struct property_traits&lt;T*&gt; {
  259. typedef T value_type;
  260. typedef ptrdiff_t key_type;
  261. typedef lvalue_property_map_tag category;
  262. };
  263. template &lt;class T&gt;
  264. void put(T* pa, std::ptrdiff_t key, const T&amp; value) { pa[key] = value; }
  265. template &lt;class T&gt;
  266. const T&amp; get(const T* pa, std::ptrdiff_t key) { return pa[key]; }
  267. template &lt;class T&gt;
  268. const T&amp; at(const T* pa, std::ptrdiff_t key) { return pa[key]; }
  269. template &lt;class T&gt;
  270. T&amp; at(T* pa, std::ptrdiff_t key) { return pa[key]; }
  271. }
  272. </PRE>
  273. <P>
  274. In the following example, we use an array to store names of cities for
  275. each vertex in the graph, and a <TT>std::vector</TT> to store vertex
  276. colors which will be needed in a call to
  277. <TT>breadth_first_search()</TT>. Since the iterator of a
  278. <TT>std::vector</TT> (obtained with a call to <TT>begin()</TT>) is a
  279. pointer, the pointer property map method also works for
  280. <TT>std::vector::iterator</TT>. The complete source code for this
  281. example is in <a
  282. href="../example/city_visitor.cpp"><TT>example/city_visitor.cpp</TT></a>.
  283. <P>
  284. <PRE>
  285. // Definition of city_visitor omitted...
  286. int main(int,char*[])
  287. {
  288. enum { SanJose, SanFran, LA, SanDiego, Fresno, LosVegas, Reno,
  289. Sacramento, SaltLake, Pheonix, N };
  290. // An array of vertex name properties
  291. std::string names[] = { &quot;San Jose&quot;, &quot;San Francisco&quot;, &quot;San Jose&quot;,
  292. &quot;San Francisco&quot;, &quot;Los Angeles&quot;, &quot;San Diego&quot;,
  293. &quot;Fresno&quot;, &quot;Los Vegas&quot;, &quot;Reno&quot;, &quot;Sacramento&quot;,
  294. &quot;Salt Lake City&quot;, &quot;Pheonix&quot; };
  295. // Specify all the connecting roads between cities.
  296. typedef std::pair&lt;int,int&gt; E;
  297. E edge_array[] = { E(Sacramento, Reno), ... };
  298. // Specify the graph type.
  299. typedef adjacency_list&lt;vecS, vecS, undirectedS&gt; Graph;
  300. // Create the graph object, based on the edges in edge_array.
  301. Graph G(N, edge_array, edge_array + sizeof(edge_array)/sizeof(E));
  302. // DFS and BFS need to &quot;color&quot; the vertices.
  303. // Here we use std::vector as exterior property storage.
  304. std::vector&lt;default_color_type&gt; colors(N);
  305. cout &lt;&lt; &quot;*** Depth First ***&quot; &lt;&lt; endl;
  306. depth_first_search(G, city_visitor(names), colors.begin());
  307. cout &lt;&lt; endl;
  308. // Get the source vertex
  309. boost::graph_traits&lt;Graph&gt;::vertex_descriptor
  310. s = vertex(SanJose, G);
  311. cout &lt;&lt; &quot;*** Breadth First ***&quot; &lt;&lt; endl;
  312. breadth_first_search(G, s, city_visitor(names), colors.begin());
  313. return 0;
  314. }
  315. </PRE>
  316. <P>
  317. <H2><A NAME="sec:custom-exterior-property-maps"></A>
  318. Constructing an Exterior Property Map
  319. </H2>
  320. <P>
  321. Implementing your own exterior property maps is not very
  322. difficult. You simply need to overload the functions required by the
  323. <a href="property_map.html">property map concept</a>
  324. that you want your class to model. At most, this means overloading the
  325. <TT>put()</TT> and <TT>get()</TT> functions and implementing
  326. <TT>operator[]</TT>. Also, your property map class will need to have
  327. nested typedefs for all the types defined in <TT>property_traits</TT>,
  328. or you can create a specialization of <TT>property_traits</TT> for
  329. your new property map type.
  330. <P>
  331. The implementation of the
  332. <TT>iterator_property_map</TT> class
  333. serves as a good example for how to build and exterior property
  334. map. Here we present a simplified implementation of the
  335. <TT>iterator_property_map</TT> class
  336. which we will name <TT>iterator_pa</TT>.
  337. <P>
  338. We start with the definition of the <TT>iterator_map</TT> class
  339. itself. This adaptor class is templated on the adapted <TT>Iterator</TT>
  340. type and the ID property map. The job of the ID property map
  341. is to map the key object (which will typically be a vertex or edge
  342. descriptor) to an integer offset. The <TT>iterator_map</TT> class will
  343. need the three necessary typedefs for a property map:
  344. <TT>key_type</TT>, <TT>value_type</TT>, and <TT>category</TT>. We can use
  345. <TT>property_traits</TT> to find the key type of <TT>IDMap</TT>, and
  346. we can use <TT>iterator_traits</TT> to determine the value type of
  347. <TT>Iterator</TT>. We choose
  348. <TT>boost::lvalue_property_map_tag</TT> for the category
  349. since we plan on implementing the <TT>at()</TT> function.
  350. <P>
  351. <PRE>
  352. template &lt;class Iterator, class IDMap&gt;
  353. class iterator_map
  354. {
  355. public:
  356. typedef typename boost::property_traits&lt;IDMap&gt;::key_type key_type;
  357. typedef typename std::iterator_traits&lt;Iterator&gt;::value_type value_type;
  358. typedef boost::lvalue_property_map_tag category;
  359. iterator_map(Iterator i = Iterator(),
  360. const IDMap&amp; id = IDMap())
  361. : m_iter(i), m_id(id) { }
  362. Iterator m_iter;
  363. IDMap m_id;
  364. };
  365. </PRE>
  366. <P>
  367. Next we implement the three property map functions, <TT>get()</TT>,
  368. <TT>put()</TT>, and <TT>at()</TT>. In each of the functions, the
  369. <TT>key</TT> object is converted to an integer offset using the
  370. <TT>m_id</TT> property map, and then that is used as an offset
  371. to the random access iterator <TT>m_iter</TT>.
  372. <P>
  373. <PRE>
  374. template &lt;class Iter, class ID&gt;
  375. typename std::iterator_traits&lt;Iter&gt;::value_type
  376. get(const iterator_map&lt;Iter,ID&gt;&amp; i,
  377. typename boost::property_traits&lt;ID&gt;::key_type key)
  378. {
  379. return i.m_iter[i.m_id[key]];
  380. }
  381. template &lt;class Iter, class ID&gt;
  382. void
  383. put(const iterator_map&lt;Iter,ID&gt;&amp; i,
  384. typename boost::property_traits&lt;ID&gt;::key_type key,
  385. const typename std::iterator_traits&lt;Iter&gt;::value_type&amp; value)
  386. {
  387. i.m_iter[i.m_id[key]] = value;
  388. }
  389. template &lt;class Iter, class ID&gt;
  390. typename std::iterator_traits&lt;Iter&gt;::reference
  391. at(const iterator_map&lt;Iter,ID&gt;&amp; i,
  392. typename boost::property_traits&lt;ID&gt;::key_type key)
  393. {
  394. return i.m_iter[i.m_id[key]];
  395. }
  396. </PRE>
  397. <P>
  398. That is it. The <TT>iterator_map</TT> class is complete and could be
  399. used just like the
  400. <TT>iterator_property_map</TT> in the
  401. previous section.
  402. <P>
  403. <br>
  404. <HR>
  405. <TABLE>
  406. <TR valign=top>
  407. <TD nowrap>Copyright &copy; 2000-2001</TD><TD>
  408. <A HREF="http://www.boost.org/people/jeremy_siek.htm">Jeremy Siek</A>, Indiana University (<A HREF="mailto:jsiek@osl.iu.edu">jsiek@osl.iu.edu</A>)
  409. </TD></TR></TABLE>
  410. </BODY>
  411. </HTML>