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