test/planarity_test.cc
author Alpar Juttner <alpar@cs.elte.hu>
Thu, 25 Feb 2021 09:46:12 +0100
changeset 1209 4a170261cc54
parent 1181 1e5da3fc4fbc
permissions -rw-r--r--
Merge #638
     1 /* -*- mode: C++; indent-tabs-mode: nil; -*-
     2  *
     3  * This file is a part of LEMON, a generic C++ optimization library.
     4  *
     5  * Copyright (C) 2003-2009
     6  * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
     7  * (Egervary Research Group on Combinatorial Optimization, EGRES).
     8  *
     9  * Permission to use, modify and distribute this software is granted
    10  * provided that this copyright notice appears in all copies. For
    11  * precise terms see the accompanying LICENSE file.
    12  *
    13  * This software is provided "AS IS" with no warranty of any kind,
    14  * express or implied, and with no claim as to its suitability for any
    15  * purpose.
    16  *
    17  */
    18 
    19 #include <iostream>
    20 
    21 #include <lemon/planarity.h>
    22 
    23 #include <lemon/smart_graph.h>
    24 #include <lemon/lgf_reader.h>
    25 #include <lemon/connectivity.h>
    26 #include <lemon/dim2.h>
    27 
    28 #include "test_tools.h"
    29 
    30 using namespace lemon;
    31 using namespace lemon::dim2;
    32 
    33 const int lgfn = 8;
    34 const std::string lgf[lgfn] = {
    35   "@nodes\n"
    36   "label\n"
    37   "@edges\n"
    38   "     label\n",
    39 
    40   "@nodes\n"
    41   "label\n"
    42   "0\n"
    43   "@edges\n"
    44   "     label\n",
    45 
    46   "@nodes\n"
    47   "label\n"
    48   "0\n"
    49   "1\n"
    50   "@edges\n"
    51   "     label\n"
    52   "0 1  0\n",
    53 
    54   "@nodes\n"
    55   "label\n"
    56   "0\n"
    57   "1\n"
    58   "2\n"
    59   "@edges\n"
    60   "     label\n"
    61   "0 1  0\n"
    62   "1 2  1\n"
    63   "2 0  2\n",
    64 
    65   "@nodes\n"
    66   "label\n"
    67   "0\n"
    68   "1\n"
    69   "2\n"
    70   "3\n"
    71   "4\n"
    72   "@edges\n"
    73   "     label\n"
    74   "0 1  0\n"
    75   "0 2  0\n"
    76   "0 3  0\n"
    77   "0 4  0\n"
    78   "1 2  0\n"
    79   "1 3  0\n"
    80   "1 4  0\n"
    81   "2 3  0\n"
    82   "2 4  0\n"
    83   "3 4  0\n",
    84 
    85   "@nodes\n"
    86   "label\n"
    87   "0\n"
    88   "1\n"
    89   "2\n"
    90   "3\n"
    91   "4\n"
    92   "@edges\n"
    93   "     label\n"
    94   "0 1  0\n"
    95   "0 2  0\n"
    96   "0 3  0\n"
    97   "0 4  0\n"
    98   "1 2  0\n"
    99   "1 3  0\n"
   100   "2 3  0\n"
   101   "2 4  0\n"
   102   "3 4  0\n",
   103 
   104   "@nodes\n"
   105   "label\n"
   106   "0\n"
   107   "1\n"
   108   "2\n"
   109   "3\n"
   110   "4\n"
   111   "5\n"
   112   "@edges\n"
   113   "     label\n"
   114   "0 3  0\n"
   115   "0 4  0\n"
   116   "0 5  0\n"
   117   "1 3  0\n"
   118   "1 4  0\n"
   119   "1 5  0\n"
   120   "2 3  0\n"
   121   "2 4  0\n"
   122   "2 5  0\n",
   123 
   124   "@nodes\n"
   125   "label\n"
   126   "0\n"
   127   "1\n"
   128   "2\n"
   129   "3\n"
   130   "4\n"
   131   "5\n"
   132   "@edges\n"
   133   "     label\n"
   134   "0 3  0\n"
   135   "0 4  0\n"
   136   "0 5  0\n"
   137   "1 3  0\n"
   138   "1 4  0\n"
   139   "1 5  0\n"
   140   "2 3  0\n"
   141   "2 5  0\n"
   142 };
   143 
   144 
   145 
   146 typedef SmartGraph Graph;
   147 GRAPH_TYPEDEFS(Graph);
   148 
   149 typedef PlanarEmbedding<SmartGraph> PE;
   150 typedef PlanarDrawing<SmartGraph> PD;
   151 typedef PlanarColoring<SmartGraph> PC;
   152 
   153 void checkEmbedding(const Graph& graph, PE& pe) {
   154   int face_num = 0;
   155 
   156   Graph::ArcMap<int> face(graph, -1);
   157 
   158   for (ArcIt a(graph); a != INVALID; ++a) {
   159     if (face[a] == -1) {
   160       Arc b = a;
   161       while (face[b] == -1) {
   162         face[b] = face_num;
   163         b = pe.next(graph.oppositeArc(b));
   164       }
   165       check(face[b] == face_num, "Wrong face");
   166       ++face_num;
   167     }
   168   }
   169 
   170   if (face_num != 0) {
   171     check(face_num + countNodes(graph) - countConnectedComponents(graph) ==
   172           countEdges(graph) + 1, "Euler test does not passed");
   173   }
   174 }
   175 
   176 void checkKuratowski(const Graph& graph, PE& pe) {
   177   std::map<int, int> degs;
   178   for (NodeIt n(graph); n != INVALID; ++n) {
   179     int deg = 0;
   180     for (IncEdgeIt e(graph, n); e != INVALID; ++e) {
   181       if (pe.kuratowski(e)) {
   182         ++deg;
   183       }
   184     }
   185     ++degs[deg];
   186   }
   187   for (std::map<int, int>::iterator it = degs.begin(); it != degs.end(); ++it) {
   188     check(it->first == 0 || it->first == 2 ||
   189           (it->first == 3 && it->second == 6) ||
   190           (it->first == 4 && it->second == 5),
   191           "Wrong degree in Kuratowski graph");
   192   }
   193 
   194   // Not full test
   195   check((degs[3] == 0) != (degs[4] == 0), "Wrong Kuratowski graph");
   196 }
   197 
   198 bool intersect(Point<int> e1, Point<int> e2, Point<int> f1, Point<int> f2) {
   199   int l, r;
   200   if (std::min(e1.x, e2.x) > std::max(f1.x, f2.x)) return false;
   201   if (std::max(e1.x, e2.x) < std::min(f1.x, f2.x)) return false;
   202   if (std::min(e1.y, e2.y) > std::max(f1.y, f2.y)) return false;
   203   if (std::max(e1.y, e2.y) < std::min(f1.y, f2.y)) return false;
   204 
   205   l = (e2.x - e1.x) * (f1.y - e1.y) - (e2.y - e1.y) * (f1.x - e1.x);
   206   r = (e2.x - e1.x) * (f2.y - e1.y) - (e2.y - e1.y) * (f2.x - e1.x);
   207   if (!((l >= 0 && r <= 0) || (l <= 0 && r >= 0))) return false;
   208   l = (f2.x - f1.x) * (e1.y - f1.y) - (f2.y - f1.y) * (e1.x - f1.x);
   209   r = (f2.x - f1.x) * (e2.y - f1.y) - (f2.y - f1.y) * (e2.x - f1.x);
   210   if (!((l >= 0 && r <= 0) || (l <= 0 && r >= 0))) return false;
   211   return true;
   212 }
   213 
   214 bool collinear(Point<int> p, Point<int> q, Point<int> r) {
   215   int v;
   216   v = (q.x - p.x) * (r.y - p.y) - (q.y - p.y) * (r.x - p.x);
   217   if (v != 0) return false;
   218   v = (q.x - p.x) * (r.x - p.x) + (q.y - p.y) * (r.y - p.y);
   219   if (v < 0) return false;
   220   return true;
   221 }
   222 
   223 void checkDrawing(const Graph& graph, PD& pd) {
   224   for (Graph::NodeIt n(graph); n != INVALID; ++n) {
   225     Graph::NodeIt m(n);
   226     for (++m; m != INVALID; ++m) {
   227       check(pd[m] != pd[n], "Two nodes with identical coordinates");
   228     }
   229   }
   230 
   231   for (Graph::EdgeIt e(graph); e != INVALID; ++e) {
   232     for (Graph::EdgeIt f(e); f != e; ++f) {
   233       Point<int> e1 = pd[graph.u(e)];
   234       Point<int> e2 = pd[graph.v(e)];
   235       Point<int> f1 = pd[graph.u(f)];
   236       Point<int> f2 = pd[graph.v(f)];
   237 
   238       if (graph.u(e) == graph.u(f)) {
   239         check(!collinear(e1, e2, f2), "Wrong drawing");
   240       } else if (graph.u(e) == graph.v(f)) {
   241         check(!collinear(e1, e2, f1), "Wrong drawing");
   242       } else if (graph.v(e) == graph.u(f)) {
   243         check(!collinear(e2, e1, f2), "Wrong drawing");
   244       } else if (graph.v(e) == graph.v(f)) {
   245         check(!collinear(e2, e1, f1), "Wrong drawing");
   246       } else {
   247         check(!intersect(e1, e2, f1, f2), "Wrong drawing");
   248       }
   249     }
   250   }
   251 }
   252 
   253 void checkColoring(const Graph& graph, PC& pc, int num) {
   254   for (NodeIt n(graph); n != INVALID; ++n) {
   255     check(pc.colorIndex(n) >= 0 && pc.colorIndex(n) < num,
   256           "Wrong coloring");
   257   }
   258   for (EdgeIt e(graph); e != INVALID; ++e) {
   259     check(pc.colorIndex(graph.u(e)) != pc.colorIndex(graph.v(e)),
   260           "Wrong coloring");
   261   }
   262 }
   263 
   264 int main() {
   265 
   266   for (int i = 0; i < lgfn; ++i) {
   267     std::istringstream lgfs(lgf[i]);
   268 
   269     SmartGraph graph;
   270     graphReader(graph, lgfs).run();
   271 
   272     check(simpleGraph(graph), "Test graphs must be simple");
   273 
   274     PE pe(graph);
   275     bool planar = pe.run();
   276     check(checkPlanarity(graph) == planar, "Planarity checking failed");
   277 
   278     if (planar) {
   279       checkEmbedding(graph, pe);
   280 
   281       {
   282         PlanarDrawing<Graph> pd(graph);
   283         pd.run(pe.embeddingMap());
   284         checkDrawing(graph, pd);
   285       }
   286 
   287       {
   288         PlanarDrawing<Graph> pd(graph);
   289         pd.run();
   290         checkDrawing(graph, pd);
   291       }
   292 
   293       {
   294         PlanarColoring<Graph> pc(graph);
   295         pc.runFiveColoring(pe.embeddingMap());
   296         checkColoring(graph, pc, 5);
   297       }
   298 
   299       {
   300         PlanarColoring<Graph> pc(graph);
   301         pc.runFiveColoring();
   302         checkColoring(graph, pc, 5);
   303       }
   304 
   305     } else {
   306       checkKuratowski(graph, pe);
   307     }
   308   }
   309 
   310   return 0;
   311 }