1 //=======================================================================
2 // Copyright 2007 Aaron Windsor
4 // Distributed under the Boost Software License, Version 1.0. (See
5 // accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt)
7 //=======================================================================
11 This test is almost identical to all_planar_input_files_test.cpp
12 except that parallel edges and loops are added to the graphs as
15 This test needs to be linked against Boost.Filesystem.
19 #define BOOST_FILESYSTEM_VERSION 3
28 #include <boost/property_map/property_map.hpp>
29 #include <boost/lexical_cast.hpp>
30 #include <boost/tuple/tuple.hpp>
31 #include <boost/filesystem.hpp>
32 #include <boost/algorithm/string.hpp>
33 #include <boost/test/minimal.hpp>
36 #include <boost/graph/adjacency_list.hpp>
37 #include <boost/graph/depth_first_search.hpp>
38 #include <boost/graph/properties.hpp>
39 #include <boost/graph/graph_traits.hpp>
40 #include <boost/graph/planar_canonical_ordering.hpp>
41 #include <boost/graph/make_connected.hpp>
42 #include <boost/graph/make_biconnected_planar.hpp>
43 #include <boost/graph/make_maximal_planar.hpp>
44 #include <boost/graph/is_straight_line_drawing.hpp>
45 #include <boost/graph/is_kuratowski_subgraph.hpp>
46 #include <boost/graph/chrobak_payne_drawing.hpp>
47 #include <boost/graph/boyer_myrvold_planar_test.hpp>
48 #include <boost/graph/planar_detail/add_edge_visitors.hpp>
55 using namespace boost
;
65 template <typename Graph
>
66 void read_dimacs(Graph
& g
, const std::string
& filename
)
69 // every <vertex_stride>th vertex has a self-loop
70 int vertex_stride
= 5;
72 // on vertices with self loops, there are between 1 and
73 // <max_loop_multiplicity> loops
74 int max_loop_multiplicity
= 6;
76 // every <edge_stride>th edge is a parallel edge
79 // parallel edges come in groups of 2 to <max_edge_multiplicity> + 1
80 int max_edge_multiplicity
= 5;
82 typedef typename graph_traits
<Graph
>::vertex_iterator vertex_iterator_t
;
83 typedef typename graph_traits
<Graph
>::vertex_descriptor vertex_t
;
84 std::vector
<vertex_t
> vertices_by_index
;
86 std::ifstream
in(filename
.c_str());
88 long num_edges_added
= 0;
89 long num_parallel_edges
= 0;
95 in
.getline(buffer
, 256);
96 std::string
s(buffer
);
101 std::vector
<std::string
> v
;
102 split(v
, buffer
, is_any_of(" \t\n"));
107 long num_vertices
= boost::lexical_cast
<long>(v
[2].c_str());
108 g
= Graph(num_vertices
);
111 vertex_iterator_t vi
, vi_end
;
114 for(boost::tie(vi
, vi_end
) = vertices(g
); vi
!= vi_end
; ++vi
)
116 if (count
% vertex_stride
== 0)
119 i
< (mult_count
% max_loop_multiplicity
) + 1;
123 add_edge(*vi
, *vi
, g
);
130 std::copy(vertices(g
).first
,
132 std::back_inserter(vertices_by_index
)
135 else if (v
[0] == "e")
137 add_edge(vertices_by_index
[boost::lexical_cast
<long>(v
[1].c_str())],
138 vertices_by_index
[boost::lexical_cast
<long>(v
[2].c_str())],
141 if (num_edges_added
% edge_stride
== 0)
144 i
< (num_parallel_edges
% max_edge_multiplicity
) + 1;
148 add_edge(vertices_by_index
149 [boost::lexical_cast
<long>(v
[1].c_str())],
151 [boost::lexical_cast
<long>(v
[2].c_str())],
154 ++num_parallel_edges
;
165 struct face_counter
: planar_face_traversal_visitor
168 face_counter() : m_num_faces(0) {}
170 void begin_face() { ++m_num_faces
; }
172 long num_faces() { return m_num_faces
; }
185 int test_graph(const std::string
& dimacs_filename
)
188 typedef adjacency_list
<listS
,
191 property
<vertex_index_t
, int>,
192 property
<edge_index_t
, int> > graph
;
194 typedef graph_traits
<graph
>::edge_descriptor edge_t
;
195 typedef graph_traits
<graph
>::edge_iterator edge_iterator_t
;
196 typedef graph_traits
<graph
>::vertex_iterator vertex_iterator_t
;
197 typedef graph_traits
<graph
>::edges_size_type e_size_t
;
198 typedef graph_traits
<graph
>::vertex_descriptor vertex_t
;
199 typedef edge_index_update_visitor
<property_map
<graph
, edge_index_t
>::type
>
202 vertex_iterator_t vi
, vi_end
;
203 edge_iterator_t ei
, ei_end
;
206 read_dimacs(g
, dimacs_filename
);
208 // Initialize the interior edge index
209 property_map
<graph
, edge_index_t
>::type e_index
= get(edge_index
, g
);
210 e_size_t edge_count
= 0;
211 for(boost::tie(ei
, ei_end
) = edges(g
); ei
!= ei_end
; ++ei
)
212 put(e_index
, *ei
, edge_count
++);
214 // Initialize the interior vertex index - not needed if the vertices
215 // are stored with a vecS
217 property_map<graph, vertex_index_t>::type v_index = get(vertex_index, g);
218 v_size_t vertex_count = 0;
219 for(boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi)
220 put(v_index, *vi, vertex_count++);
223 // This edge_updater will automatically update the interior edge
224 // index of the graph as edges are created.
225 edge_visitor_t
edge_updater(get(edge_index
, g
), num_edges(g
));
227 // The input graph may not be maximal planar, but the Chrobak-Payne straight
228 // line drawing needs a maximal planar graph as input. So, we make a copy of
229 // the original graph here, then add edges to the graph to make it maximal
230 // planar. When we're done creating a drawing of the maximal planar graph,
231 // we can use the same mapping of vertices to points on the grid to embed the
232 // original, non-maximal graph.
235 // Add edges to make g connected, if it isn't already
236 make_connected(g
, get(vertex_index
, g
), edge_updater
);
238 std::vector
<graph_traits
<graph
>::edge_descriptor
> kuratowski_edges
;
240 typedef std::vector
< std::vector
<edge_t
> > edge_permutation_storage_t
;
241 typedef boost::iterator_property_map
242 < edge_permutation_storage_t::iterator
,
243 property_map
<graph
, vertex_index_t
>::type
247 edge_permutation_storage_t
edge_permutation_storage(num_vertices(g
));
248 edge_permutation_t
perm(edge_permutation_storage
.begin(),
252 // Test for planarity, computing the planar embedding or the kuratowski
254 if (!boyer_myrvold_planarity_test(boyer_myrvold_params::graph
= g
,
255 boyer_myrvold_params::embedding
= perm
,
256 boyer_myrvold_params::kuratowski_subgraph
257 = std::back_inserter(kuratowski_edges
)
261 std::cerr
<< "Not planar. ";
262 BOOST_REQUIRE(is_kuratowski_subgraph
263 (g
, kuratowski_edges
.begin(), kuratowski_edges
.end())
269 // If we get this far, we have a connected planar graph.
270 make_biconnected_planar(g
, perm
, get(edge_index
, g
), edge_updater
);
272 // Compute the planar embedding of the (now) biconnected planar graph
273 BOOST_CHECK (boyer_myrvold_planarity_test(boyer_myrvold_params::graph
= g
,
274 boyer_myrvold_params::embedding
279 // If we get this far, we have a biconnected planar graph
280 make_maximal_planar(g
, perm
, get(vertex_index
,g
), get(edge_index
,g
),
283 // Now the graph is triangulated - we can compute the final planar embedding
284 BOOST_CHECK (boyer_myrvold_planarity_test(boyer_myrvold_params::graph
= g
,
285 boyer_myrvold_params::embedding
290 // Make sure Euler's formula holds
292 planar_face_traversal(g
, perm
, vis
, get(edge_index
, g
));
294 BOOST_CHECK(num_vertices(g
) - num_edges(g
) + vis
.num_faces() == 2);
296 // Compute a planar canonical ordering of the vertices
297 std::vector
<vertex_t
> ordering
;
298 planar_canonical_ordering(g
, perm
, std::back_inserter(ordering
));
300 BOOST_CHECK(ordering
.size() == num_vertices(g
));
302 typedef std::vector
< coord_t
> drawing_storage_t
;
303 typedef boost::iterator_property_map
304 < drawing_storage_t::iterator
, property_map
<graph
, vertex_index_t
>::type
>
307 drawing_storage_t
drawing_vector(num_vertices(g
));
308 drawing_map_t
drawing(drawing_vector
.begin(), get(vertex_index
,g
));
310 // Compute a straight line drawing
311 chrobak_payne_straight_line_drawing(g
,
318 std::cerr
<< "Planar. ";
319 BOOST_REQUIRE (is_straight_line_drawing(g
, drawing
));
330 int test_main(int argc
, char* argv
[])
333 std::string input_directory_str
= "planar_input_graphs";
336 input_directory_str
= std::string(argv
[1]);
339 std::cout
<< "Reading planar input files from " << input_directory_str
342 filesystem::path input_directory
=
343 filesystem::system_complete(filesystem::path(input_directory_str
));
344 const std::string dimacs_extension
= ".dimacs";
346 filesystem::directory_iterator dir_end
;
347 for( filesystem::directory_iterator
dir_itr(input_directory
);
348 dir_itr
!= dir_end
; ++dir_itr
)
351 if (dir_itr
->path().extension() != dimacs_extension
)
354 std::cerr
<< "Testing " << dir_itr
->path().leaf() << "... ";
355 BOOST_REQUIRE (test_graph(dir_itr
->path().string()) == 0);
357 std::cerr
<< std::endl
;