Last active
October 6, 2024 11:19
-
-
Save Hermann-SW/99d151a273d290ee0d843c79b2da26a8 to your computer and use it in GitHub Desktop.
Boost make_"connected / biconnected_planar / maximal_planar"+straight_line_drawing demos made create graphviz graph with fixed coordinates
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//======================================================================= | |
// Distributed under the Boost Software License, Version 1.0. (See | |
// accompanying file LICENSE_1_0.txt or copy at | |
// http://www.boost.org/LICENSE_1_0.txt) | |
/* | |
f=straight_line_graphviz | |
g++ -O3 -Wall -pedantic -Wextra $f.cpp -o $f | |
cpplint --filter=-legal/copyright,-build/namespaces,-runtime/references $f.cpp | |
cppcheck --enable=all --suppress=missingIncludeSystem $f.cpp --check-config | |
*/ | |
//======================================================================= | |
#include <cassert> | |
#include <cstring> | |
#include <iostream> | |
#include <fstream> | |
#include <vector> | |
#include <boost/graph/adjacency_list.hpp> | |
#include <boost/graph/properties.hpp> | |
#include <boost/graph/graph_traits.hpp> | |
#include <boost/property_map/property_map.hpp> | |
#include <boost/ref.hpp> | |
#include <boost/graph/make_connected.hpp> | |
#include <boost/graph/make_biconnected_planar.hpp> | |
#include <boost/graph/make_maximal_planar.hpp> | |
#include <boost/graph/planar_face_traversal.hpp> | |
#include <boost/graph/boyer_myrvold_planar_test.hpp> | |
#include <boost/graph/planar_canonical_ordering.hpp> | |
#include <boost/graph/is_straight_line_drawing.hpp> | |
#include <boost/graph/chrobak_payne_drawing.hpp> | |
// This example shows how to start with a connected planar graph | |
// and add edges to make the graph maximal planar (triangulated.) | |
// Any maximal planar simple graph on n vertices has 3n - 6 edges and | |
// 2n - 4 faces, a consequence of Euler's formula. | |
using namespace boost; | |
// a class to hold the coordinates of the straight line embedding | |
struct coord_t { | |
std::size_t x; | |
std::size_t y; | |
}; | |
// time measurements | |
clock_t start_; | |
#define __(blk) if (output) std::cerr << #blk << " "; start_ = clock(); blk \ | |
if (output) std::cerr << (clock()-start_)*1.0/CLOCKS_PER_SEC << std::endl; | |
template <class Graph> | |
void read_leda_graph(Graph& g, const char* gname) { | |
int n, m; | |
std::string line; | |
std::ifstream in(gname); | |
assert(in); | |
std::getline(in, line); | |
in >> line >> line >> n; | |
g = Graph(n); | |
for (int i=1; i <= n; ++i) { | |
in >> line; | |
} | |
in >> m; | |
for (int i=1; i <= m; ++i) { | |
int s, t, v; | |
in >> s >> t >> v; | |
add_edge(s-1, t-1, g); | |
} | |
} | |
int main(int argc, char** argv) { | |
typedef adjacency_list< vecS, vecS, undirectedS, | |
no_property, property< edge_index_t, int > > | |
graph; | |
assert((argc >> 1) == 1); | |
bool output = (argc == 3) && strchr(argv[2], 't'); | |
bool dbg = (argc == 3) && strchr(argv[2], 'd'); | |
bool coords = (argc == 3) && strchr(argv[2], 'c'); | |
bool noisld= (argc == 3) && strchr(argv[2], 'n'); | |
graph g; | |
__(read_leda_graph(g, argv[1]);) | |
int edge_count_input = num_edges(g); | |
__(make_connected(g);) | |
// Initialize the interior edge index | |
property_map< graph, edge_index_t >::type e_index = get(edge_index, g); | |
graph_traits< graph >::edges_size_type edge_count = 0; | |
graph_traits< graph >::edge_iterator ei, ei_end; | |
for (boost::tie(ei, ei_end) = edges(g); ei != ei_end; ++ei) | |
put(e_index, *ei, edge_count++); | |
// Test for planarity; compute the planar embedding as a side-effect | |
typedef std::vector< graph_traits< graph >::edge_descriptor > vec_t; | |
std::vector< vec_t > embedding2(num_vertices(g)); | |
__(assert(boyer_myrvold_planarity_test(boyer_myrvold_params::graph = g, | |
boyer_myrvold_params::embedding = &embedding2[0]));) | |
__(make_biconnected_planar(g, &embedding2[0]);) | |
// Re-initialize the edge index, since we just added a few edges | |
edge_count = 0; | |
for (boost::tie(ei, ei_end) = edges(g); ei != ei_end; ++ei) | |
put(e_index, *ei, edge_count++); | |
// Test for planarity again; compute the planar embedding as a side-effect | |
__(assert(boyer_myrvold_planarity_test(boyer_myrvold_params::graph = g, | |
boyer_myrvold_params::embedding = &embedding2[0]));) | |
__(make_maximal_planar(g, &embedding2[0]);) | |
// Re-initialize the edge index, since we just added a few edges | |
edge_count = 0; | |
for (boost::tie(ei, ei_end) = edges(g); ei != ei_end; ++ei) | |
put(e_index, *ei, edge_count++); | |
// Test for planarity one final time; compute the planar embedding as a | |
// side-effect | |
__(assert(boyer_myrvold_planarity_test(boyer_myrvold_params::graph = g, | |
boyer_myrvold_params::embedding = &embedding2[0]));) | |
typedef std::vector< std::vector< graph_traits< graph >::edge_descriptor > > | |
embedding_storage_t; | |
typedef boost::iterator_property_map< embedding_storage_t::iterator, | |
property_map< graph, vertex_index_t >::type > | |
embedding_t; | |
// Create the planar embedding | |
embedding_storage_t embedding_storage(num_vertices(g)); | |
embedding_t embedding(embedding_storage.begin(), get(vertex_index, g)); | |
__(assert(boyer_myrvold_planarity_test(boyer_myrvold_params::graph = g, | |
boyer_myrvold_params::embedding = embedding));) | |
// Find a canonical ordering | |
std::vector< graph_traits< graph >::vertex_descriptor > ordering; | |
__(planar_canonical_ordering(g, embedding, std::back_inserter(ordering));) | |
// Set up a property map to hold the mapping from vertices to coord_t's | |
typedef std::vector< coord_t > straight_line_drawing_storage_t; | |
typedef boost::iterator_property_map< | |
straight_line_drawing_storage_t::iterator, | |
property_map< graph, vertex_index_t >::type > | |
straight_line_drawing_t; | |
straight_line_drawing_storage_t straight_line_drawing_storage( | |
num_vertices(g)); | |
straight_line_drawing_t straight_line_drawing( | |
straight_line_drawing_storage.begin(), get(vertex_index, g)); | |
// Compute the straight line drawing | |
__(chrobak_payne_straight_line_drawing( | |
g, embedding, ordering.begin(), ordering.end(), straight_line_drawing);) | |
if (coords) { | |
std::ofstream out("coords.txt"); | |
BGL_FORALL_VERTICES(v, g, graph) { | |
out << v << " "; | |
out << straight_line_drawing[v].x << " "; | |
out << straight_line_drawing[v].y << std::endl; | |
} | |
} | |
// Verify that the drawing is actually a plane drawing | |
if (!noisld) | |
__(assert(is_straight_line_drawing(g, straight_line_drawing));) | |
if (!output) { | |
std::cout << "graph {" << std::endl; | |
std::cout << " layout=neato" << std::endl; | |
if (dbg) { | |
std::cout << " size=18" << std::endl; | |
std::cout << " node [shape=none,fontsize=24]" << std::endl; | |
} else { | |
std::cout << " node [shape=none]" << std::endl; | |
} | |
// get the property map for vertex indices | |
typedef property_map<graph, vertex_index_t>::type IndexMap; | |
IndexMap index = get(vertex_index, g); | |
graph_traits< graph >::vertex_iterator vi, vi_end; | |
for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) { | |
coord_t coord(get(straight_line_drawing, *vi)); | |
std::cout << " " << *vi << " [pos=\"" << coord.x << "," << coord.y | |
<< "!\""; | |
if (dbg) | |
std::cout << " label=\"" << *vi <<"\""; | |
std::cout << "]" << std::endl; | |
} | |
for (boost::tie(ei, ei_end) = edges(g); ei != ei_end; ++ei) { | |
std::cout << " " << index[source(*ei, g)] | |
<< "--" << index[target(*ei, g)] | |
<< "[style=" << (edge_count_input-- > 0 ? "bold" : "dotted") | |
<< "]" << std::endl; | |
} | |
std::cout << "}" << std::endl; | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Tested on 384GB RAM server with maximal planar randomgraph inputs from 10,000 up to 100 million vertices.
Maximal planar randomgraph created with:
https://github.com/Hermann-SW/randomgraph
Last row determined from output of:
Biggest graph execution:
Option "t" does the timings, option "n" excludes "is_straight_line_drawing()" because of new issue:
boostorg/graph#388
Server used: