deba@861: /* -*- mode: C++; indent-tabs-mode: nil; -*- deba@861: * deba@861: * This file is a part of LEMON, a generic C++ optimization library. deba@861: * deba@861: * Copyright (C) 2003-2009 deba@861: * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport deba@861: * (Egervary Research Group on Combinatorial Optimization, EGRES). deba@861: * deba@861: * Permission to use, modify and distribute this software is granted deba@861: * provided that this copyright notice appears in all copies. For deba@861: * precise terms see the accompanying LICENSE file. deba@861: * deba@861: * This software is provided "AS IS" with no warranty of any kind, deba@861: * express or implied, and with no claim as to its suitability for any deba@861: * purpose. deba@861: * deba@861: */ deba@861: deba@861: #include deba@861: deba@861: #include deba@861: deba@861: #include deba@861: #include deba@861: #include deba@861: #include deba@861: deba@861: #include "test_tools.h" deba@861: deba@861: using namespace lemon; deba@861: using namespace lemon::dim2; deba@861: deba@1400: const int lgfn = 8; deba@861: const std::string lgf[lgfn] = { deba@861: "@nodes\n" deba@861: "label\n" deba@1400: "@edges\n" deba@1400: " label\n", deba@1400: deba@1400: "@nodes\n" deba@1400: "label\n" deba@1400: "0\n" deba@1400: "@edges\n" deba@1400: " label\n", deba@1400: deba@1400: "@nodes\n" deba@1400: "label\n" deba@1400: "0\n" deba@1400: "1\n" deba@1400: "@edges\n" deba@1400: " label\n" deba@1400: "0 1 0\n", deba@1400: deba@1400: "@nodes\n" deba@1400: "label\n" deba@1400: "0\n" deba@1400: "1\n" deba@1400: "2\n" deba@1400: "@edges\n" deba@1400: " label\n" deba@1400: "0 1 0\n" deba@1400: "1 2 1\n" deba@1400: "2 0 2\n", deba@1400: deba@1400: "@nodes\n" deba@1400: "label\n" deba@861: "0\n" deba@861: "1\n" deba@861: "2\n" deba@861: "3\n" deba@861: "4\n" deba@861: "@edges\n" deba@861: " label\n" deba@861: "0 1 0\n" deba@861: "0 2 0\n" deba@861: "0 3 0\n" deba@861: "0 4 0\n" deba@861: "1 2 0\n" deba@861: "1 3 0\n" deba@861: "1 4 0\n" deba@861: "2 3 0\n" deba@861: "2 4 0\n" deba@861: "3 4 0\n", deba@861: deba@861: "@nodes\n" deba@861: "label\n" deba@861: "0\n" deba@861: "1\n" deba@861: "2\n" deba@861: "3\n" deba@861: "4\n" deba@861: "@edges\n" deba@861: " label\n" deba@861: "0 1 0\n" deba@861: "0 2 0\n" deba@861: "0 3 0\n" deba@861: "0 4 0\n" deba@861: "1 2 0\n" deba@861: "1 3 0\n" deba@861: "2 3 0\n" deba@861: "2 4 0\n" deba@861: "3 4 0\n", deba@861: deba@861: "@nodes\n" deba@861: "label\n" deba@861: "0\n" deba@861: "1\n" deba@861: "2\n" deba@861: "3\n" deba@861: "4\n" deba@861: "5\n" deba@861: "@edges\n" deba@861: " label\n" deba@861: "0 3 0\n" deba@861: "0 4 0\n" deba@861: "0 5 0\n" deba@861: "1 3 0\n" deba@861: "1 4 0\n" deba@861: "1 5 0\n" deba@861: "2 3 0\n" deba@861: "2 4 0\n" deba@861: "2 5 0\n", deba@861: deba@861: "@nodes\n" deba@861: "label\n" deba@861: "0\n" deba@861: "1\n" deba@861: "2\n" deba@861: "3\n" deba@861: "4\n" deba@861: "5\n" deba@861: "@edges\n" deba@861: " label\n" deba@861: "0 3 0\n" deba@861: "0 4 0\n" deba@861: "0 5 0\n" deba@861: "1 3 0\n" deba@861: "1 4 0\n" deba@861: "1 5 0\n" deba@861: "2 3 0\n" deba@861: "2 5 0\n" deba@861: }; deba@861: deba@861: deba@861: deba@861: typedef SmartGraph Graph; deba@861: GRAPH_TYPEDEFS(Graph); deba@861: deba@861: typedef PlanarEmbedding PE; deba@861: typedef PlanarDrawing PD; deba@861: typedef PlanarColoring PC; deba@861: deba@861: void checkEmbedding(const Graph& graph, PE& pe) { deba@861: int face_num = 0; deba@861: deba@861: Graph::ArcMap face(graph, -1); deba@861: deba@861: for (ArcIt a(graph); a != INVALID; ++a) { deba@861: if (face[a] == -1) { deba@861: Arc b = a; deba@861: while (face[b] == -1) { deba@861: face[b] = face_num; deba@861: b = pe.next(graph.oppositeArc(b)); deba@861: } deba@861: check(face[b] == face_num, "Wrong face"); deba@861: ++face_num; deba@861: } deba@861: } deba@1400: deba@1400: if (face_num != 0) { deba@1400: check(face_num + countNodes(graph) - countConnectedComponents(graph) == deba@1400: countEdges(graph) + 1, "Euler test does not passed"); deba@1400: } deba@861: } deba@861: deba@861: void checkKuratowski(const Graph& graph, PE& pe) { deba@861: std::map degs; deba@861: for (NodeIt n(graph); n != INVALID; ++n) { deba@861: int deg = 0; deba@861: for (IncEdgeIt e(graph, n); e != INVALID; ++e) { deba@861: if (pe.kuratowski(e)) { deba@861: ++deg; deba@861: } deba@861: } deba@861: ++degs[deg]; deba@861: } deba@861: for (std::map::iterator it = degs.begin(); it != degs.end(); ++it) { deba@861: check(it->first == 0 || it->first == 2 || deba@861: (it->first == 3 && it->second == 6) || deba@861: (it->first == 4 && it->second == 5), deba@861: "Wrong degree in Kuratowski graph"); deba@861: } deba@861: deba@861: // Not full test deba@861: check((degs[3] == 0) != (degs[4] == 0), "Wrong Kuratowski graph"); deba@861: } deba@861: deba@861: bool intersect(Point e1, Point e2, Point f1, Point f2) { deba@861: int l, r; deba@861: if (std::min(e1.x, e2.x) > std::max(f1.x, f2.x)) return false; deba@861: if (std::max(e1.x, e2.x) < std::min(f1.x, f2.x)) return false; deba@861: if (std::min(e1.y, e2.y) > std::max(f1.y, f2.y)) return false; deba@861: if (std::max(e1.y, e2.y) < std::min(f1.y, f2.y)) return false; deba@861: deba@861: l = (e2.x - e1.x) * (f1.y - e1.y) - (e2.y - e1.y) * (f1.x - e1.x); deba@861: r = (e2.x - e1.x) * (f2.y - e1.y) - (e2.y - e1.y) * (f2.x - e1.x); deba@861: if (!((l >= 0 && r <= 0) || (l <= 0 && r >= 0))) return false; deba@861: l = (f2.x - f1.x) * (e1.y - f1.y) - (f2.y - f1.y) * (e1.x - f1.x); deba@861: r = (f2.x - f1.x) * (e2.y - f1.y) - (f2.y - f1.y) * (e2.x - f1.x); deba@861: if (!((l >= 0 && r <= 0) || (l <= 0 && r >= 0))) return false; deba@861: return true; deba@861: } deba@861: deba@861: bool collinear(Point p, Point q, Point r) { deba@861: int v; deba@861: v = (q.x - p.x) * (r.y - p.y) - (q.y - p.y) * (r.x - p.x); deba@861: if (v != 0) return false; deba@861: v = (q.x - p.x) * (r.x - p.x) + (q.y - p.y) * (r.y - p.y); deba@861: if (v < 0) return false; deba@861: return true; deba@861: } deba@861: deba@861: void checkDrawing(const Graph& graph, PD& pd) { deba@861: for (Graph::NodeIt n(graph); n != INVALID; ++n) { deba@861: Graph::NodeIt m(n); deba@861: for (++m; m != INVALID; ++m) { deba@861: check(pd[m] != pd[n], "Two nodes with identical coordinates"); deba@861: } deba@861: } deba@861: deba@861: for (Graph::EdgeIt e(graph); e != INVALID; ++e) { deba@861: for (Graph::EdgeIt f(e); f != e; ++f) { deba@861: Point e1 = pd[graph.u(e)]; deba@861: Point e2 = pd[graph.v(e)]; deba@861: Point f1 = pd[graph.u(f)]; deba@861: Point f2 = pd[graph.v(f)]; deba@861: deba@861: if (graph.u(e) == graph.u(f)) { deba@861: check(!collinear(e1, e2, f2), "Wrong drawing"); deba@861: } else if (graph.u(e) == graph.v(f)) { deba@861: check(!collinear(e1, e2, f1), "Wrong drawing"); deba@861: } else if (graph.v(e) == graph.u(f)) { deba@861: check(!collinear(e2, e1, f2), "Wrong drawing"); deba@861: } else if (graph.v(e) == graph.v(f)) { deba@861: check(!collinear(e2, e1, f1), "Wrong drawing"); deba@861: } else { deba@861: check(!intersect(e1, e2, f1, f2), "Wrong drawing"); deba@861: } deba@861: } deba@861: } deba@861: } deba@861: deba@861: void checkColoring(const Graph& graph, PC& pc, int num) { deba@861: for (NodeIt n(graph); n != INVALID; ++n) { deba@861: check(pc.colorIndex(n) >= 0 && pc.colorIndex(n) < num, deba@861: "Wrong coloring"); deba@861: } deba@861: for (EdgeIt e(graph); e != INVALID; ++e) { deba@861: check(pc.colorIndex(graph.u(e)) != pc.colorIndex(graph.v(e)), deba@861: "Wrong coloring"); deba@861: } deba@861: } deba@861: deba@861: int main() { deba@861: deba@861: for (int i = 0; i < lgfn; ++i) { deba@861: std::istringstream lgfs(lgf[i]); deba@861: deba@861: SmartGraph graph; deba@861: graphReader(graph, lgfs).run(); deba@861: deba@861: check(simpleGraph(graph), "Test graphs must be simple"); deba@861: deba@861: PE pe(graph); deba@862: bool planar = pe.run(); deba@862: check(checkPlanarity(graph) == planar, "Planarity checking failed"); deba@862: deba@862: if (planar) { deba@861: checkEmbedding(graph, pe); deba@861: deba@1399: { deba@1399: PlanarDrawing pd(graph); deba@1399: pd.run(pe.embeddingMap()); deba@1399: checkDrawing(graph, pd); deba@1399: } deba@861: deba@1399: { deba@1399: PlanarDrawing pd(graph); deba@1399: pd.run(); deba@1399: checkDrawing(graph, pd); deba@1399: } deba@1399: deba@1399: { deba@1399: PlanarColoring pc(graph); deba@1399: pc.runFiveColoring(pe.embeddingMap()); deba@1399: checkColoring(graph, pc, 5); deba@1399: } deba@1399: deba@1399: { deba@1399: PlanarColoring pc(graph); deba@1399: pc.runFiveColoring(); deba@1399: checkColoring(graph, pc, 5); deba@1399: } deba@861: deba@861: } else { deba@861: checkKuratowski(graph, pe); deba@861: } deba@861: } deba@861: deba@861: return 0; deba@861: }