test/planarity_test.cc
author Peter Kovacs <kpeter@inf.elte.hu>
Tue, 15 Mar 2011 19:32:21 +0100
changeset 1047 ddd3c0d3d9bf
parent 861 30cb42e3e43a
child 1399 1e5da3fc4fbc
permissions -rw-r--r--
Implement the scaling Price Refinement heuristic in CostScaling (#417)
instead of Early Termination.

These two heuristics are similar, but the newer one is faster
and not only makes it possible to skip some epsilon phases, but
it can improve the performance of the other phases, as well.
     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 = 4;
    34 const std::string lgf[lgfn] = {
    35   "@nodes\n"
    36   "label\n"
    37   "0\n"
    38   "1\n"
    39   "2\n"
    40   "3\n"
    41   "4\n"
    42   "@edges\n"
    43   "     label\n"
    44   "0 1  0\n"
    45   "0 2  0\n"
    46   "0 3  0\n"
    47   "0 4  0\n"
    48   "1 2  0\n"
    49   "1 3  0\n"
    50   "1 4  0\n"
    51   "2 3  0\n"
    52   "2 4  0\n"
    53   "3 4  0\n",
    54 
    55   "@nodes\n"
    56   "label\n"
    57   "0\n"
    58   "1\n"
    59   "2\n"
    60   "3\n"
    61   "4\n"
    62   "@edges\n"
    63   "     label\n"
    64   "0 1  0\n"
    65   "0 2  0\n"
    66   "0 3  0\n"
    67   "0 4  0\n"
    68   "1 2  0\n"
    69   "1 3  0\n"
    70   "2 3  0\n"
    71   "2 4  0\n"
    72   "3 4  0\n",
    73 
    74   "@nodes\n"
    75   "label\n"
    76   "0\n"
    77   "1\n"
    78   "2\n"
    79   "3\n"
    80   "4\n"
    81   "5\n"
    82   "@edges\n"
    83   "     label\n"
    84   "0 3  0\n"
    85   "0 4  0\n"
    86   "0 5  0\n"
    87   "1 3  0\n"
    88   "1 4  0\n"
    89   "1 5  0\n"
    90   "2 3  0\n"
    91   "2 4  0\n"
    92   "2 5  0\n",
    93 
    94   "@nodes\n"
    95   "label\n"
    96   "0\n"
    97   "1\n"
    98   "2\n"
    99   "3\n"
   100   "4\n"
   101   "5\n"
   102   "@edges\n"
   103   "     label\n"
   104   "0 3  0\n"
   105   "0 4  0\n"
   106   "0 5  0\n"
   107   "1 3  0\n"
   108   "1 4  0\n"
   109   "1 5  0\n"
   110   "2 3  0\n"
   111   "2 5  0\n"
   112 };
   113 
   114 
   115 
   116 typedef SmartGraph Graph;
   117 GRAPH_TYPEDEFS(Graph);
   118 
   119 typedef PlanarEmbedding<SmartGraph> PE;
   120 typedef PlanarDrawing<SmartGraph> PD;
   121 typedef PlanarColoring<SmartGraph> PC;
   122 
   123 void checkEmbedding(const Graph& graph, PE& pe) {
   124   int face_num = 0;
   125 
   126   Graph::ArcMap<int> face(graph, -1);
   127 
   128   for (ArcIt a(graph); a != INVALID; ++a) {
   129     if (face[a] == -1) {
   130       Arc b = a;
   131       while (face[b] == -1) {
   132         face[b] = face_num;
   133         b = pe.next(graph.oppositeArc(b));
   134       }
   135       check(face[b] == face_num, "Wrong face");
   136       ++face_num;
   137     }
   138   }
   139   check(face_num + countNodes(graph) - countConnectedComponents(graph) ==
   140         countEdges(graph) + 1, "Euler test does not passed");
   141 }
   142 
   143 void checkKuratowski(const Graph& graph, PE& pe) {
   144   std::map<int, int> degs;
   145   for (NodeIt n(graph); n != INVALID; ++n) {
   146     int deg = 0;
   147     for (IncEdgeIt e(graph, n); e != INVALID; ++e) {
   148       if (pe.kuratowski(e)) {
   149         ++deg;
   150       }
   151     }
   152     ++degs[deg];
   153   }
   154   for (std::map<int, int>::iterator it = degs.begin(); it != degs.end(); ++it) {
   155     check(it->first == 0 || it->first == 2 ||
   156           (it->first == 3 && it->second == 6) ||
   157           (it->first == 4 && it->second == 5),
   158           "Wrong degree in Kuratowski graph");
   159   }
   160 
   161   // Not full test
   162   check((degs[3] == 0) != (degs[4] == 0), "Wrong Kuratowski graph");
   163 }
   164 
   165 bool intersect(Point<int> e1, Point<int> e2, Point<int> f1, Point<int> f2) {
   166   int l, r;
   167   if (std::min(e1.x, e2.x) > std::max(f1.x, f2.x)) return false;
   168   if (std::max(e1.x, e2.x) < std::min(f1.x, f2.x)) return false;
   169   if (std::min(e1.y, e2.y) > std::max(f1.y, f2.y)) return false;
   170   if (std::max(e1.y, e2.y) < std::min(f1.y, f2.y)) return false;
   171 
   172   l = (e2.x - e1.x) * (f1.y - e1.y) - (e2.y - e1.y) * (f1.x - e1.x);
   173   r = (e2.x - e1.x) * (f2.y - e1.y) - (e2.y - e1.y) * (f2.x - e1.x);
   174   if (!((l >= 0 && r <= 0) || (l <= 0 && r >= 0))) return false;
   175   l = (f2.x - f1.x) * (e1.y - f1.y) - (f2.y - f1.y) * (e1.x - f1.x);
   176   r = (f2.x - f1.x) * (e2.y - f1.y) - (f2.y - f1.y) * (e2.x - f1.x);
   177   if (!((l >= 0 && r <= 0) || (l <= 0 && r >= 0))) return false;
   178   return true;
   179 }
   180 
   181 bool collinear(Point<int> p, Point<int> q, Point<int> r) {
   182   int v;
   183   v = (q.x - p.x) * (r.y - p.y) - (q.y - p.y) * (r.x - p.x);
   184   if (v != 0) return false;
   185   v = (q.x - p.x) * (r.x - p.x) + (q.y - p.y) * (r.y - p.y);
   186   if (v < 0) return false;
   187   return true;
   188 }
   189 
   190 void checkDrawing(const Graph& graph, PD& pd) {
   191   for (Graph::NodeIt n(graph); n != INVALID; ++n) {
   192     Graph::NodeIt m(n);
   193     for (++m; m != INVALID; ++m) {
   194       check(pd[m] != pd[n], "Two nodes with identical coordinates");
   195     }
   196   }
   197 
   198   for (Graph::EdgeIt e(graph); e != INVALID; ++e) {
   199     for (Graph::EdgeIt f(e); f != e; ++f) {
   200       Point<int> e1 = pd[graph.u(e)];
   201       Point<int> e2 = pd[graph.v(e)];
   202       Point<int> f1 = pd[graph.u(f)];
   203       Point<int> f2 = pd[graph.v(f)];
   204 
   205       if (graph.u(e) == graph.u(f)) {
   206         check(!collinear(e1, e2, f2), "Wrong drawing");
   207       } else if (graph.u(e) == graph.v(f)) {
   208         check(!collinear(e1, e2, f1), "Wrong drawing");
   209       } else if (graph.v(e) == graph.u(f)) {
   210         check(!collinear(e2, e1, f2), "Wrong drawing");
   211       } else if (graph.v(e) == graph.v(f)) {
   212         check(!collinear(e2, e1, f1), "Wrong drawing");
   213       } else {
   214         check(!intersect(e1, e2, f1, f2), "Wrong drawing");
   215       }
   216     }
   217   }
   218 }
   219 
   220 void checkColoring(const Graph& graph, PC& pc, int num) {
   221   for (NodeIt n(graph); n != INVALID; ++n) {
   222     check(pc.colorIndex(n) >= 0 && pc.colorIndex(n) < num,
   223           "Wrong coloring");
   224   }
   225   for (EdgeIt e(graph); e != INVALID; ++e) {
   226     check(pc.colorIndex(graph.u(e)) != pc.colorIndex(graph.v(e)),
   227           "Wrong coloring");
   228   }
   229 }
   230 
   231 int main() {
   232 
   233   for (int i = 0; i < lgfn; ++i) {
   234     std::istringstream lgfs(lgf[i]);
   235 
   236     SmartGraph graph;
   237     graphReader(graph, lgfs).run();
   238 
   239     check(simpleGraph(graph), "Test graphs must be simple");
   240 
   241     PE pe(graph);
   242     bool planar = pe.run();
   243     check(checkPlanarity(graph) == planar, "Planarity checking failed");
   244 
   245     if (planar) {
   246       checkEmbedding(graph, pe);
   247 
   248       PlanarDrawing<Graph> pd(graph);
   249       pd.run(pe.embeddingMap());
   250       checkDrawing(graph, pd);
   251 
   252       PlanarColoring<Graph> pc(graph);
   253       pc.runFiveColoring(pe.embeddingMap());
   254       checkColoring(graph, pc, 5);
   255 
   256     } else {
   257       checkKuratowski(graph, pe);
   258     }
   259   }
   260 
   261   return 0;
   262 }