Commit 8e046d6c authored by Tiago Peixoto's avatar Tiago Peixoto
Browse files

Implement make_maximal_planar()

parent a7a1a83b
......@@ -22,6 +22,7 @@ libgraph_tool_topology_la_SOURCES = \
graph_diameter.cc \
graph_dominator_tree.cc \
graph_isomorphism.cc \
graph_maximal_planar.cc \
graph_maximal_vertex_set.cc \
graph_minimum_spanning_tree.cc \
graph_planar.cc \
......
// graph-tool -- a general graph modification and manipulation thingy
//
// Copyright (C) 2007-2012 Tiago de Paula Peixoto <tiago@skewed.de>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "graph_filtering.hh"
#include "graph.hh"
#include "graph_properties.hh"
#include <boost/graph/make_maximal_planar.hpp>
#include <boost/graph/make_biconnected_planar.hpp>
#include <boost/graph/boyer_myrvold_planar_test.hpp>
using namespace std;
using namespace boost;
using namespace graph_tool;
template <class EdgeMap>
struct mark_planar_edge
{
mark_planar_edge(EdgeMap map, bool force): _map(map), _force(force) {}
EdgeMap _map;
bool _force;
template <typename Graph, typename Vertex>
void visit_vertex_pair(Vertex u, Vertex v, Graph& g)
{
if (!is_adjacent(u, v, g))
add_edge(u, v, g);
}
template <typename Graph, typename Vertex, class EdgePredicate, class VertexPredicate>
void visit_vertex_pair(Vertex u, Vertex v, UndirectedAdaptor<filtered_graph<Graph,
EdgePredicate,
VertexPredicate> >& g)
{
if (_force && !is_adjacent(u, v, g))
{
add_edge(u, v, g);
return;
}
typedef typename graph_traits<Graph>::edge_descriptor edge_t;
std::pair<edge_t, bool> e = edge(u, v, UndirectedAdaptor<Graph>(g.OriginalGraph().m_g));
if (e.second)
_map[e.first] = true;
}
};
struct do_maximal_planar
{
template <class Graph, class VertexIndex, class EdgeIndex, class EdgeMap>
void operator()(Graph& g, VertexIndex vertex_index, EdgeIndex edge_index,
EdgeMap emap, bool augment) const
{
unchecked_vector_property_map
<vector<typename graph_traits<Graph>::edge_descriptor>, VertexIndex>
embedding(vertex_index, num_vertices(g));
bool is_planar = boyer_myrvold_planarity_test
(boyer_myrvold_params::graph = g,
boyer_myrvold_params::edge_index_map = edge_index,
boyer_myrvold_params::embedding = embedding);
if (!is_planar)
throw GraphException("Graph is not planar!");
mark_planar_edge<EdgeMap> vis(emap, augment);
make_biconnected_planar(g, embedding, edge_index, vis);
boyer_myrvold_planarity_test
(boyer_myrvold_params::graph = g,
boyer_myrvold_params::edge_index_map = edge_index,
boyer_myrvold_params::embedding = embedding);
make_maximal_planar(g, embedding, vertex_index, edge_index, vis);
}
};
void maximal_planar(GraphInterface& gi, boost::any edge_map, bool augment)
{
if (augment)
{
run_action<graph_tool::detail::never_directed, mpl::true_>()
(gi, bind<void>(do_maximal_planar(), _1, gi.GetVertexIndex(),
gi.GetEdgeIndex(), false, true))();
}
else
{
run_action<graph_tool::detail::never_directed, mpl::true_>()
(gi, bind<void>(do_maximal_planar(), _1, gi.GetVertexIndex(),
gi.GetEdgeIndex(), _2, false),
edge_scalar_properties())
(edge_map);
}
}
......@@ -32,6 +32,7 @@ bool topological_sort(GraphInterface& gi, vector<int32_t>& sort);
void dominator_tree(GraphInterface& gi, size_t entry, boost::any pred_map);
void transitive_closure(GraphInterface& gi, GraphInterface& tcgi);
bool is_planar(GraphInterface& gi, boost::any embed_map, boost::any kur_map);
void maximal_planar(GraphInterface& gi, boost::any edge_map, bool augment);
void subgraph_isomorphism(GraphInterface& gi1, GraphInterface& gi2,
boost::any vertex_label1, boost::any vertex_label2,
boost::any edge_label1, boost::any edge_label2,
......@@ -65,6 +66,7 @@ BOOST_PYTHON_MODULE(libgraph_tool_topology)
def("dominator_tree", &dominator_tree);
def("transitive_closure", &transitive_closure);
def("is_planar", &is_planar);
def("maximal_planar", &maximal_planar);
def("reciprocity", &reciprocity);
def("sequential_coloring", &sequential_coloring);
def("is_bipartite", &is_bipartite);
......
......@@ -51,6 +51,7 @@ Summary
is_bipartite
is_DAG
is_planar
make_maximal_planar
edge_reciprocity
Contents
......@@ -74,7 +75,7 @@ __all__ = ["isomorphism", "subgraph_isomorphism", "mark_subgraph",
"label_largest_component", "label_biconnected_components",
"label_out_component", "shortest_distance", "shortest_path",
"pseudo_diameter", "is_bipartite", "is_DAG", "is_planar",
"similarity", "edge_reciprocity"]
"make_maximal_planar", "similarity", "edge_reciprocity"]
def similarity(g1, g2, label1=None, label2=None, norm=True):
......@@ -1319,6 +1320,76 @@ def is_planar(g, embedding=False, kuratowski=False):
else:
return tuple(ret)
def make_maximal_planar(g, unfilter=False):
"""
Add edges to the graph to make it maximally planar.
Parameters
----------
g : :class:`~graph_tool.Graph`
Graph to be used.
unfilter : bool (optional, default: False)
If true, and the `g` is filtered, the edges will be unfiltered instead
of added. Note that in this case the resulting graph may not be
maximally planar if the necessary edges are not existent in the
underlying unfiltered graph.
Returns
-------
`None`
Notes
-----
A graph is maximal planar if no additional edges can be added to it without
creating a non-planar graph. By Euler's formula, a maximal planar graph with
V > 2 vertices always has 3V - 6 edges and 2V - 4 faces.
This algorithm runs in :math:`O(V + E)` time.
Examples
--------
>>> from numpy.random import seed, random
>>> seed(42)
>>> g = gt.triangulation(random((100,2)))[0]
>>> p, embed_order = gt.is_planar(g, embedding=True)
>>> print(p)
True
>>> print(list(embed_order[g.vertex(0)]))
[0, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
>>> g = gt.random_graph(100, lambda: 4, directed=False)
>>> p, kur = gt.is_planar(g, kuratowski=True)
>>> print(p)
False
>>> g.set_edge_filter(kur, True)
>>> gt.graph_draw(g, output_size=(300, 300), output="kuratowski.pdf")
<...>
.. figure:: kuratowski.*
:align: center
Obstructing Kuratowski subgraph of a random graph.
References
----------
.. [boyer-myrvold] John M. Boyer and Wendy J. Myrvold, "On the Cutting Edge:
Simplified O(n) Planarity by Edge Addition" Journal of Graph Algorithms
and Applications, 8(2): 241-273, 2004. http://www.emis.ams.org/journals/JGAA/accepted/2004/BoyerMyrvold2004.8.3.pdf
.. [boost-planarity] http://www.boost.org/libs/graph/doc/boyer_myrvold.html
"""
if unfilter and g.get_edge_filter() is not None:
emap = g.get_edge_filter()[0]
else:
unfilter = False
emap = None
g = GraphView(g, directed=False)
libgraph_tool_topology.maximal_planar(g._Graph__graph,
_prop("e", g, emap),
not unfilter)
def is_DAG(g):
"""
Return `True` if the graph is a directed acyclic graph (DAG).
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment