[Lemon-commits] deba: r3339 - lemon/trunk/lemon
Lemon SVN
svn at lemon.cs.elte.hu
Fri Oct 19 18:24:32 CEST 2007
Author: deba
Date: Fri Oct 19 18:24:31 2007
New Revision: 3339
Modified:
lemon/trunk/lemon/planarity.h
Log:
Planar Grid Embedding
Modified: lemon/trunk/lemon/planarity.h
==============================================================================
--- lemon/trunk/lemon/planarity.h (original)
+++ lemon/trunk/lemon/planarity.h Fri Oct 19 18:24:31 2007
@@ -18,7 +18,7 @@
#ifndef LEMON_PLANARITY_H
#define LEMON_PLANARITY_H
-/// \ingroup graph_prop
+/// \ingroup planar
/// \file
/// \brief Planarity checking, embedding
@@ -29,6 +29,8 @@
#include <lemon/radix_sort.h>
#include <lemon/maps.h>
#include <lemon/path.h>
+#include <lemon/iterable_maps.h>
+#include <lemon/edge_set.h>
namespace lemon {
@@ -134,11 +136,11 @@
}
- /// \ingroup graph_prop
+ /// \ingroup planar
///
/// \brief Planarity checking of an undirected simple graph
///
- /// This class implements the Boyer-Myrvold algorithm for planar
+ /// This class implements the Boyer-Myrvold algorithm for planarity
/// checking of an undirected graph. This class is a simplified
/// version of the PlanarEmbedding algorithm class, and it does
/// provide neither embedding nor kuratowski subdivisons.
@@ -146,7 +148,7 @@
class PlanarityChecking {
private:
- UGRAPH_TYPEDEFS(typename UGraph)
+ UGRAPH_TYPEDEFS(typename UGraph);
const UGraph& _ugraph;
@@ -522,7 +524,7 @@
};
- /// \ingroup graph_prop
+ /// \ingroup planar
///
/// \brief Planar embedding of an undirected simple graph
///
@@ -541,7 +543,7 @@
class PlanarEmbedding {
private:
- UGRAPH_TYPEDEFS(typename UGraph)
+ UGRAPH_TYPEDEFS(typename UGraph);
const UGraph& _ugraph;
typename UGraph::template EdgeMap<Edge> _embedding;
@@ -586,6 +588,9 @@
public:
+ /// \brief The map for store of embedding
+ typedef typename UGraph::template EdgeMap<Edge> EmbeddingMap;
+
/// \brief Constructor
///
/// \warining The graph should be simple, i.e. parallel and loop edge
@@ -701,6 +706,14 @@
return _embedding[edge];
}
+ /// \brief Gives back the calculated embedding map
+ ///
+ /// The returned map contains the successor of each edge in the
+ /// graph.
+ const EmbeddingMap& embedding() const {
+ return _embedding;
+ }
+
/// \brief Gives back true when the undirected edge is in the
/// kuratowski subdivision
///
@@ -1806,6 +1819,623 @@
};
+ namespace _planarity_bits {
+
+ template <typename UGraph, typename EmbeddingMap>
+ void makeConnected(UGraph& ugraph, EmbeddingMap& embedding) {
+ DfsVisitor<UGraph> null_visitor;
+ DfsVisit<UGraph, DfsVisitor<UGraph> > dfs(ugraph, null_visitor);
+ dfs.init();
+
+ typename UGraph::Node u = INVALID;
+ for (typename UGraph::NodeIt n(ugraph); n != INVALID; ++n) {
+ if (!dfs.reached(n)) {
+ dfs.addSource(n);
+ dfs.start();
+ if (u == INVALID) {
+ u = n;
+ } else {
+ typename UGraph::Node v = n;
+
+ typename UGraph::Edge ue = typename UGraph::OutEdgeIt(ugraph, u);
+ typename UGraph::Edge ve = typename UGraph::OutEdgeIt(ugraph, v);
+
+ typename UGraph::Edge e = ugraph.direct(ugraph.addEdge(u, v), true);
+
+ if (ue != INVALID) {
+ embedding[e] = embedding[ue];
+ embedding[ue] = e;
+ } else {
+ embedding[e] = e;
+ }
+
+ if (ve != INVALID) {
+ embedding[ugraph.oppositeEdge(e)] = embedding[ve];
+ embedding[ve] = ugraph.oppositeEdge(e);
+ } else {
+ embedding[ugraph.oppositeEdge(e)] = ugraph.oppositeEdge(e);
+ }
+ }
+ }
+ }
+ }
+
+ template <typename UGraph, typename EmbeddingMap>
+ void makeBiNodeConnected(UGraph& ugraph, EmbeddingMap& embedding) {
+ typename UGraph::template EdgeMap<bool> processed(ugraph);
+
+ std::vector<typename UGraph::Edge> edges;
+ for (typename UGraph::EdgeIt e(ugraph); e != INVALID; ++e) {
+ edges.push_back(e);
+ }
+
+ IterableBoolMap<UGraph, typename UGraph::Node> visited(ugraph, false);
+
+ for (int i = 0; i < int(edges.size()); ++i) {
+ typename UGraph::Edge pp = edges[i];
+ if (processed[pp]) continue;
+
+ typename UGraph::Edge e = embedding[ugraph.oppositeEdge(pp)];
+ processed[e] = true;
+ visited.set(ugraph.source(e), true);
+
+ typename UGraph::Edge p = e, l = e;
+ e = embedding[ugraph.oppositeEdge(e)];
+
+ while (e != l) {
+ processed[e] = true;
+
+ if (visited[ugraph.source(e)]) {
+
+ typename UGraph::Edge n =
+ ugraph.direct(ugraph.addEdge(ugraph.source(p),
+ ugraph.target(e)), true);
+ embedding[n] = p;
+ embedding[ugraph.oppositeEdge(pp)] = n;
+
+ embedding[ugraph.oppositeEdge(n)] =
+ embedding[ugraph.oppositeEdge(e)];
+ embedding[ugraph.oppositeEdge(e)] =
+ ugraph.oppositeEdge(n);
+
+ p = n;
+ e = embedding[ugraph.oppositeEdge(n)];
+ } else {
+ visited.set(ugraph.source(e), true);
+ pp = p;
+ p = e;
+ e = embedding[ugraph.oppositeEdge(e)];
+ }
+ }
+ visited.setAll(false);
+ }
+ }
+
+
+ template <typename UGraph, typename EmbeddingMap>
+ void makeMaxPlanar(UGraph& ugraph, EmbeddingMap& embedding) {
+
+ typename UGraph::template NodeMap<int> degree(ugraph);
+
+ for (typename UGraph::NodeIt n(ugraph); n != INVALID; ++n) {
+ degree[n] = countIncEdges(ugraph, n);
+ }
+
+ typename UGraph::template EdgeMap<bool> processed(ugraph);
+ IterableBoolMap<UGraph, typename UGraph::Node> visited(ugraph, false);
+
+ std::vector<typename UGraph::Edge> edges;
+ for (typename UGraph::EdgeIt e(ugraph); e != INVALID; ++e) {
+ edges.push_back(e);
+ }
+
+ for (int i = 0; i < int(edges.size()); ++i) {
+ typename UGraph::Edge e = edges[i];
+
+ if (processed[e]) continue;
+ processed[e] = true;
+
+ typename UGraph::Edge mine = e;
+ int mind = degree[ugraph.source(e)];
+
+ int face_size = 1;
+
+ typename UGraph::Edge l = e;
+ e = embedding[ugraph.oppositeEdge(e)];
+ while (l != e) {
+ processed[e] = true;
+
+ ++face_size;
+
+ if (degree[ugraph.source(e)] < mind) {
+ mine = e;
+ mind = degree[ugraph.source(e)];
+ }
+
+ e = embedding[ugraph.oppositeEdge(e)];
+ }
+
+ if (face_size < 4) {
+ continue;
+ }
+
+ typename UGraph::Node s = ugraph.source(mine);
+ for (typename UGraph::OutEdgeIt e(ugraph, s); e != INVALID; ++e) {
+ visited.set(ugraph.target(e), true);
+ }
+
+ typename UGraph::Edge oppe = INVALID;
+
+ e = embedding[ugraph.oppositeEdge(mine)];
+ e = embedding[ugraph.oppositeEdge(e)];
+ while (ugraph.target(e) != s) {
+ if (visited[ugraph.source(e)]) {
+ oppe = e;
+ break;
+ }
+ e = embedding[ugraph.oppositeEdge(e)];
+ }
+ visited.setAll(false);
+
+ if (oppe == INVALID) {
+
+ e = embedding[ugraph.oppositeEdge(mine)];
+ typename UGraph::Edge pn = mine, p = e;
+
+ e = embedding[ugraph.oppositeEdge(e)];
+ while (ugraph.target(e) != s) {
+ typename UGraph::Edge n =
+ ugraph.direct(ugraph.addEdge(s, ugraph.source(e)), true);
+
+ embedding[n] = pn;
+ embedding[ugraph.oppositeEdge(n)] = e;
+ embedding[ugraph.oppositeEdge(p)] = ugraph.oppositeEdge(n);
+
+ pn = n;
+
+ p = e;
+ e = embedding[ugraph.oppositeEdge(e)];
+ }
+
+ embedding[ugraph.oppositeEdge(e)] = pn;
+
+ } else {
+
+ mine = embedding[ugraph.oppositeEdge(mine)];
+ s = ugraph.source(mine);
+ oppe = embedding[ugraph.oppositeEdge(oppe)];
+ typename UGraph::Node t = ugraph.source(oppe);
+
+ typename UGraph::Edge ce = ugraph.direct(ugraph.addEdge(s, t), true);
+ embedding[ce] = mine;
+ embedding[ugraph.oppositeEdge(ce)] = oppe;
+
+ typename UGraph::Edge pn = ce, p = oppe;
+ e = embedding[ugraph.oppositeEdge(oppe)];
+ while (ugraph.target(e) != s) {
+ typename UGraph::Edge n =
+ ugraph.direct(ugraph.addEdge(s, ugraph.source(e)), true);
+
+ embedding[n] = pn;
+ embedding[ugraph.oppositeEdge(n)] = e;
+ embedding[ugraph.oppositeEdge(p)] = ugraph.oppositeEdge(n);
+
+ pn = n;
+
+ p = e;
+ e = embedding[ugraph.oppositeEdge(e)];
+
+ }
+ embedding[ugraph.oppositeEdge(e)] = pn;
+
+ pn = ugraph.oppositeEdge(ce), p = mine;
+ e = embedding[ugraph.oppositeEdge(mine)];
+ while (ugraph.target(e) != t) {
+ typename UGraph::Edge n =
+ ugraph.direct(ugraph.addEdge(t, ugraph.source(e)), true);
+
+ embedding[n] = pn;
+ embedding[ugraph.oppositeEdge(n)] = e;
+ embedding[ugraph.oppositeEdge(p)] = ugraph.oppositeEdge(n);
+
+ pn = n;
+
+ p = e;
+ e = embedding[ugraph.oppositeEdge(e)];
+
+ }
+ embedding[ugraph.oppositeEdge(e)] = pn;
+ }
+ }
+ }
+
+ }
+
+ /// \brief Schnyder's planar drawing algorithms
+ ///
+ /// The planar drawing algorithm calculates location for each node
+ /// in the plane, which coordinates satisfies that if each edge is
+ /// represented with a straight line then the edges will not
+ /// intersect each other.
+ ///
+ /// Scnyder's algorithm embeds the graph on \c (n-2,n-2) size grid,
+ /// ie. each node will be located in the \c [0,n-2]x[0,n-2] square.
+ /// The time complexity of the algorithm is O(n).
+ template <typename UGraph>
+ class PlanarDrawing {
+ public:
+
+ UGRAPH_TYPEDEFS(typename UGraph);
+
+ /// \brief The point type for store coordinates
+ typedef dim2::Point<int> Point;
+ /// \brief The map type for store coordinates
+ typedef typename UGraph::template NodeMap<Point> PointMap;
+
+
+ /// \brief Constructor
+ ///
+ /// Constructor
+ /// \pre The ugraph should be simple, ie. loop and parallel edge free.
+ PlanarDrawing(const UGraph& ugraph)
+ : _ugraph(ugraph), _point_map(ugraph) {}
+
+ private:
+
+ template <typename AuxUGraph, typename AuxEmbeddingMap>
+ void drawing(const AuxUGraph& ugraph,
+ const AuxEmbeddingMap& next,
+ PointMap& point_map) {
+ UGRAPH_TYPEDEFS(typename AuxUGraph);
+
+ typename AuxUGraph::template EdgeMap<Edge> prev(ugraph);
+
+ for (NodeIt n(ugraph); n != INVALID; ++n) {
+ Edge e = OutEdgeIt(ugraph, n);
+
+ Edge p = e, l = e;
+
+ e = next[e];
+ while (e != l) {
+ prev[e] = p;
+ p = e;
+ e = next[e];
+ }
+ prev[e] = p;
+ }
+
+ Node anode, bnode, cnode;
+
+ {
+ Edge e = EdgeIt(ugraph);
+ anode = ugraph.source(e);
+ bnode = ugraph.target(e);
+ cnode = ugraph.target(next[ugraph.oppositeEdge(e)]);
+ }
+
+ IterableBoolMap<AuxUGraph, Node> proper(ugraph, false);
+ typename AuxUGraph::template NodeMap<int> conn(ugraph, -1);
+
+ conn[anode] = conn[bnode] = -2;
+ {
+ for (OutEdgeIt e(ugraph, anode); e != INVALID; ++e) {
+ Node m = ugraph.target(e);
+ if (conn[m] == -1) {
+ conn[m] = 1;
+ }
+ }
+ conn[cnode] = 2;
+
+ for (OutEdgeIt e(ugraph, bnode); e != INVALID; ++e) {
+ Node m = ugraph.target(e);
+ if (conn[m] == -1) {
+ conn[m] = 1;
+ } else if (conn[m] != -2) {
+ conn[m] += 1;
+ Edge pe = ugraph.oppositeEdge(e);
+ if (conn[ugraph.target(next[pe])] == -2) {
+ conn[m] -= 1;
+ }
+ if (conn[ugraph.target(prev[pe])] == -2) {
+ conn[m] -= 1;
+ }
+
+ proper.set(m, conn[m] == 1);
+ }
+ }
+ }
+
+
+ typename AuxUGraph::template EdgeMap<int> angle(ugraph, -1);
+
+ while (proper.trueNum() != 0) {
+ Node n = typename IterableBoolMap<AuxUGraph, Node>::TrueIt(proper);
+ proper.set(n, false);
+ conn[n] = -2;
+
+ for (OutEdgeIt e(ugraph, n); e != INVALID; ++e) {
+ Node m = ugraph.target(e);
+ if (conn[m] == -1) {
+ conn[m] = 1;
+ } else if (conn[m] != -2) {
+ conn[m] += 1;
+ Edge pe = ugraph.oppositeEdge(e);
+ if (conn[ugraph.target(next[pe])] == -2) {
+ conn[m] -= 1;
+ }
+ if (conn[ugraph.target(prev[pe])] == -2) {
+ conn[m] -= 1;
+ }
+
+ proper.set(m, conn[m] == 1);
+ }
+ }
+
+ {
+ Edge e = OutEdgeIt(ugraph, n);
+ Edge p = e, l = e;
+
+ e = next[e];
+ while (e != l) {
+
+ if (conn[ugraph.target(e)] == -2 && conn[ugraph.target(p)] == -2) {
+ Edge f = e;
+ angle[f] = 0;
+ f = next[ugraph.oppositeEdge(f)];
+ angle[f] = 1;
+ f = next[ugraph.oppositeEdge(f)];
+ angle[f] = 2;
+ }
+
+ p = e;
+ e = next[e];
+ }
+
+ if (conn[ugraph.target(e)] == -2 && conn[ugraph.target(p)] == -2) {
+ Edge f = e;
+ angle[f] = 0;
+ f = next[ugraph.oppositeEdge(f)];
+ angle[f] = 1;
+ f = next[ugraph.oppositeEdge(f)];
+ angle[f] = 2;
+ }
+ }
+ }
+
+ typename AuxUGraph::template NodeMap<Node> apred(ugraph, INVALID);
+ typename AuxUGraph::template NodeMap<Node> bpred(ugraph, INVALID);
+ typename AuxUGraph::template NodeMap<Node> cpred(ugraph, INVALID);
+
+ typename AuxUGraph::template NodeMap<int> apredid(ugraph, -1);
+ typename AuxUGraph::template NodeMap<int> bpredid(ugraph, -1);
+ typename AuxUGraph::template NodeMap<int> cpredid(ugraph, -1);
+
+ for (EdgeIt e(ugraph); e != INVALID; ++e) {
+ if (angle[e] == angle[next[e]]) {
+ switch (angle[e]) {
+ case 2:
+ apred[ugraph.target(e)] = ugraph.source(e);
+ apredid[ugraph.target(e)] = ugraph.id(ugraph.source(e));
+ break;
+ case 1:
+ bpred[ugraph.target(e)] = ugraph.source(e);
+ bpredid[ugraph.target(e)] = ugraph.id(ugraph.source(e));
+ break;
+ case 0:
+ cpred[ugraph.target(e)] = ugraph.source(e);
+ cpredid[ugraph.target(e)] = ugraph.id(ugraph.source(e));
+ break;
+ }
+ }
+ }
+
+ cpred[anode] = INVALID;
+ cpred[bnode] = INVALID;
+
+ std::vector<Node> aorder, border, corder;
+
+ {
+ typename AuxUGraph::template NodeMap<bool> processed(ugraph, false);
+ std::vector<Node> st;
+ for (NodeIt n(ugraph); n != INVALID; ++n) {
+ if (!processed[n] && n != bnode && n != cnode) {
+ st.push_back(n);
+ processed[n] = true;
+ Node m = apred[n];
+ while (m != INVALID && !processed[m]) {
+ st.push_back(m);
+ processed[m] = true;
+ m = apred[m];
+ }
+ while (!st.empty()) {
+ aorder.push_back(st.back());
+ st.pop_back();
+ }
+ }
+ }
+ }
+
+ {
+ typename AuxUGraph::template NodeMap<bool> processed(ugraph, false);
+ std::vector<Node> st;
+ for (NodeIt n(ugraph); n != INVALID; ++n) {
+ if (!processed[n] && n != cnode && n != anode) {
+ st.push_back(n);
+ processed[n] = true;
+ Node m = bpred[n];
+ while (m != INVALID && !processed[m]) {
+ st.push_back(m);
+ processed[m] = true;
+ m = bpred[m];
+ }
+ while (!st.empty()) {
+ border.push_back(st.back());
+ st.pop_back();
+ }
+ }
+ }
+ }
+
+ {
+ typename AuxUGraph::template NodeMap<bool> processed(ugraph, false);
+ std::vector<Node> st;
+ for (NodeIt n(ugraph); n != INVALID; ++n) {
+ if (!processed[n] && n != anode && n != bnode) {
+ st.push_back(n);
+ processed[n] = true;
+ Node m = cpred[n];
+ while (m != INVALID && !processed[m]) {
+ st.push_back(m);
+ processed[m] = true;
+ m = cpred[m];
+ }
+ while (!st.empty()) {
+ corder.push_back(st.back());
+ st.pop_back();
+ }
+ }
+ }
+ }
+
+ typename AuxUGraph::template NodeMap<int> atree(ugraph, 0);
+ for (int i = aorder.size() - 1; i >= 0; --i) {
+ Node n = aorder[i];
+ atree[n] = 1;
+ for (OutEdgeIt e(ugraph, n); e != INVALID; ++e) {
+ if (apred[ugraph.target(e)] == n) {
+ atree[n] += atree[ugraph.target(e)];
+ }
+ }
+ }
+
+ typename AuxUGraph::template NodeMap<int> btree(ugraph, 0);
+ for (int i = border.size() - 1; i >= 0; --i) {
+ Node n = border[i];
+ btree[n] = 1;
+ for (OutEdgeIt e(ugraph, n); e != INVALID; ++e) {
+ if (bpred[ugraph.target(e)] == n) {
+ btree[n] += btree[ugraph.target(e)];
+ }
+ }
+ }
+
+ typename AuxUGraph::template NodeMap<int> apath(ugraph, 0);
+ apath[bnode] = apath[cnode] = 1;
+ typename AuxUGraph::template NodeMap<int> apath_btree(ugraph, 0);
+ apath_btree[bnode] = btree[bnode];
+ for (int i = 1; i < int(aorder.size()); ++i) {
+ Node n = aorder[i];
+ apath[n] = apath[apred[n]] + 1;
+ apath_btree[n] = btree[n] + apath_btree[apred[n]];
+ }
+
+ typename AuxUGraph::template NodeMap<int> bpath_atree(ugraph, 0);
+ bpath_atree[anode] = atree[anode];
+ for (int i = 1; i < int(border.size()); ++i) {
+ Node n = border[i];
+ bpath_atree[n] = atree[n] + bpath_atree[bpred[n]];
+ }
+
+ typename AuxUGraph::template NodeMap<int> cpath(ugraph, 0);
+ cpath[anode] = cpath[bnode] = 1;
+ typename AuxUGraph::template NodeMap<int> cpath_atree(ugraph, 0);
+ cpath_atree[anode] = atree[anode];
+ typename AuxUGraph::template NodeMap<int> cpath_btree(ugraph, 0);
+ cpath_btree[bnode] = btree[bnode];
+ for (int i = 1; i < int(corder.size()); ++i) {
+ Node n = corder[i];
+ cpath[n] = cpath[cpred[n]] + 1;
+ cpath_atree[n] = atree[n] + cpath_atree[cpred[n]];
+ cpath_btree[n] = btree[n] + cpath_btree[cpred[n]];
+ }
+
+ typename AuxUGraph::template NodeMap<int> third(ugraph);
+ for (NodeIt n(ugraph); n != INVALID; ++n) {
+ point_map[n].x =
+ bpath_atree[n] + cpath_atree[n] - atree[n] - cpath[n] + 1;
+ point_map[n].y =
+ cpath_btree[n] + apath_btree[n] - btree[n] - apath[n] + 1;
+ }
+
+ }
+
+ public:
+
+ /// \brief Calculates the node locations
+ ///
+ /// This function calculates the node locations.
+ bool run() {
+ PlanarEmbedding<UGraph> pe(_ugraph);
+ if (!pe.run()) return false;
+
+ run(pe);
+ return true;
+ }
+
+ /// \brief Calculates the node locations according to a
+ /// combinatorical embedding
+ ///
+ /// This function calculates the node locations. The \c embedding
+ /// parameter should contain a valid combinatorical embedding, ie.
+ /// a valid cyclic order of the edges.
+ template <typename EmbeddingMap>
+ void run(const EmbeddingMap& embedding) {
+ typedef SmartUEdgeSet<UGraph> AuxUGraph;
+
+ if (3 * countNodes(_ugraph) - 6 == countUEdges(_ugraph)) {
+ drawing(_ugraph, embedding, _point_map);
+ return;
+ }
+
+ AuxUGraph aux_ugraph(_ugraph);
+ typename AuxUGraph::template EdgeMap<typename AuxUGraph::Edge>
+ aux_embedding(aux_ugraph);
+
+ {
+
+ typename UGraph::template UEdgeMap<typename AuxUGraph::UEdge>
+ ref(_ugraph);
+
+ for (UEdgeIt e(_ugraph); e != INVALID; ++e) {
+ ref[e] = aux_ugraph.addEdge(_ugraph.source(e), _ugraph.target(e));
+ }
+
+ for (UEdgeIt e(_ugraph); e != INVALID; ++e) {
+ Edge ee = embedding[_ugraph.direct(e, true)];
+ aux_embedding[aux_ugraph.direct(ref[e], true)] =
+ aux_ugraph.direct(ref[ee], _ugraph.direction(ee));
+ ee = embedding[_ugraph.direct(e, false)];
+ aux_embedding[aux_ugraph.direct(ref[e], false)] =
+ aux_ugraph.direct(ref[ee], _ugraph.direction(ee));
+ }
+ }
+ _planarity_bits::makeConnected(aux_ugraph, aux_embedding);
+ _planarity_bits::makeBiNodeConnected(aux_ugraph, aux_embedding);
+ _planarity_bits::makeMaxPlanar(aux_ugraph, aux_embedding);
+ drawing(aux_ugraph, aux_embedding, _point_map);
+ }
+
+ /// \brief The coordinate of the given node
+ ///
+ /// The coordinate of the given node.
+ Point operator[](const Node& node) {
+ return _point_map[node];
+ }
+
+ /// \brief Returns the grid embedding in a \e NodeMap.
+ ///
+ /// Returns the grid embedding in a \e NodeMap of \c dim2::Point<int> .
+ const PointMap& coords() const {
+ return _point_map;
+ }
+
+ private:
+
+ const UGraph& _ugraph;
+ PointMap _point_map;
+
+ };
+
}
#endif
More information about the Lemon-commits
mailing list