{ "cells": [ { "cell_type": "code", "execution_count": 1, "id": "7ee10bd7-40c0-49aa-b66a-664c8fa5bbf5", "metadata": {}, "outputs": [], "source": [ "# Der eigentliche LP/(M)IP-Solver \"Gurobi\"\n", "import gurobipy as grb\n", "\n", "# Eine Menge nützlicher Routinen zu Iteratoren (erlaubt z.B. Iteration über alle Kombinationen)\n", "import itertools\n", "\n", "# Graphen\n", "import networkx as nx\n", "from networkx.classes.graphviews import subgraph_view\n", "\n", "# Generation von zufälligen Zahlen für Instanzen/Punktmengen\n", "import random\n", "\n", "# Fürs Wurzelziehen\n", "import math\n", "\n", "# Fürs Zeichnen (hier von Graphen, kann aber auch Daten visualisieren)\n", "import matplotlib\n", "import matplotlib.pyplot as plt" ] }, { "cell_type": "markdown", "id": "98e49156-6a70-4eb4-9f45-e1f9cf1d85aa", "metadata": {}, "source": [ "## Hilfsroutinen\n", "Zur Generierung von Instanzen und Erzeugung/Sortierung der Kantenmenge." ] }, { "cell_type": "code", "execution_count": 2, "id": "16d94ecd-1448-4172-9bed-9f7d0cfd21c2", "metadata": {}, "outputs": [], "source": [ "def random_points(n, w=10_000, h=10_000):\n", " \"\"\"\n", " n zufällige Punkte mit ganzzahligen Koordinaten in einem w * h-Rechteck.\n", " :param n: Anzahl der Punkte\n", " :param w: Breite des Rechtecks.\n", " :param h: Höhe des Rechtecks.\n", " :return: Eine Liste von Punkten als (x,y)-Tupel.\n", " \"\"\"\n", " return [(random.randint(0,w), random.randint(0,h)) for _ in range(n)]\n", "\n", "def squared_distance(p1, p2):\n", " \"\"\"\n", " Berechne die (quadrierte) euklidische Distanz zwischen Punkten p1 und p2.\n", " \"\"\"\n", " return (p1[0]-p2[0])**2 + (p1[1]-p2[1])**2\n", "\n", "def all_edges(points):\n", " \"\"\"\n", " Erzeuge eine Liste aller Kanten zwischen den\n", " gegebenen Punkten und sortiere sie (aufsteigend) nach Länge.\n", " \"\"\"\n", " edges = [(v,w) for v, w in itertools.combinations(points, 2)]\n", " edges.sort(key=lambda p: squared_distance(*p)) # *p ist hier wie p[0], p[1]\n", " return edges\n", "\n", "def filter_edges(edges, max_sq_length):\n", " return [e for e in edges if squared_distance(*e) <= max_sq_length]" ] }, { "cell_type": "markdown", "id": "a8dcce0a-3b70-4862-b53e-da059cc5ac29", "metadata": {}, "source": [ "## Zeichnen von Lösungen" ] }, { "cell_type": "code", "execution_count": 3, "id": "f436c90b-a091-49e4-8c80-aa6bdd929024", "metadata": {}, "outputs": [], "source": [ "def draw_edges(edges):\n", " \"\"\"\n", " Malt eine gegebene Liste von Kanten als Graph.\n", " Die längste Kante wird dabei hervorgehoben (rot, dicker) dargestellt.\n", " \"\"\"\n", " points = set([e[0] for e in edges] + [e[1] for e in edges])\n", " draw_graph = nx.empty_graph()\n", " draw_graph.add_nodes_from(points)\n", " draw_graph.add_edges_from(edges)\n", " g_edges = draw_graph.edges()\n", " max_length = max((squared_distance(*e) for e in g_edges))\n", " color = [('red' if squared_distance(*e) == max_length else 'black') for e in g_edges]\n", " width = [(1.0 if squared_distance(*e) == max_length else 0.5) for e in g_edges]\n", " plt.clf()\n", " fig, ax = plt.gcf(), plt.gca()\n", " fig.set_size_inches(7,7)\n", " ax.set_aspect(1.0)\n", " nx.draw_networkx(draw_graph, pos={p: p for p in points}, node_size=8,\n", " with_labels=False, edgelist=g_edges, edge_color=color, width=width, ax=ax)\n", " plt.show()" ] }, { "cell_type": "markdown", "id": "ea3eb541-29f5-41ad-b1da-b5bc3b3b8fe9", "metadata": {}, "source": [ "## Greedy-Heuristik\n", "Genau wie bei SAT." ] }, { "cell_type": "code", "execution_count": 4, "id": "ce48e10e-4a97-4396-864a-3e7efaa4a8fa", "metadata": {}, "outputs": [], "source": [ "class GreedyDBST:\n", " \"\"\"\n", " Löse Degree-Constrained Bottleneck Spanning Tree mit einer Greedy-Heuristik.\n", " Geht durch die (aufsteigend nach Länge sortierte) Liste der möglichen Kanten,\n", " und fügt eine Kante ein, wenn das vom Grad her noch geht und die Endpunkte\n", " noch nicht in derselben Zusammenhangskomponente sind (im Prinzip wie Kruskal).\n", " \"\"\"\n", " def __init__(self, points, degree):\n", " self.points = points\n", " self.all_edges = all_edges(points)\n", " self._component_of = {v: v for v in points}\n", " self.degree = degree\n", " \n", " def __component_root(self, v):\n", " cof = self._component_of[v]\n", " if cof != v:\n", " cof = self.__component_root(cof)\n", " self._component_of[v] = cof\n", " return cof\n", " \n", " def __merge_if_not_same_component(self, v, w):\n", " cv = self.__component_root(v)\n", " cw = self.__component_root(w)\n", " if cv != cw:\n", " self._component_of[cw] = cv\n", " return True\n", " return False\n", " \n", " def solve(self):\n", " edges = []\n", " degree = {v: 0 for v in self.points}\n", " n = len(self.points)\n", " m = 0\n", " for v,w in self.all_edges:\n", " if degree[v] < self.degree and degree[w] < self.degree:\n", " if self.__merge_if_not_same_component(v,w):\n", " edges.append((v,w))\n", " degree[v] += 1\n", " degree[w] += 1\n", " m += 1\n", " if m == n-1:\n", " self.max_sq_length = squared_distance(v,w)\n", " print(f\"Bottleneck bei Greedy: {math.sqrt(self.max_sq_length)}\")\n", " break\n", " return edges" ] }, { "cell_type": "markdown", "id": "84d4ae29-bade-4b66-b9cd-15a39971b340", "metadata": {}, "source": [ "## Eigentlicher Solver" ] }, { "cell_type": "code", "execution_count": 5, "id": "e55fe5d3-2098-4e71-a393-bab221a4bc6d", "metadata": {}, "outputs": [], "source": [ "class DBSTSolverIP:\n", " def __make_vars(self):\n", " # Erzeuge binäre Variablen (vtype=grb.GRB.BINARY) für die Kanten\n", " self.bnvars = {e: self.model_bottleneck.addVar(lb=0, ub=1, vtype=grb.GRB.BINARY)\n", " for e in self.all_edges}\n", " # Erzeuge eine nicht ganzzahlige Variable (vtype=grb.GRB.CONTINUOUS) fürs Bottleneck\n", " self.l = self.model_bottleneck.addVar(lb=0,\n", " ub=squared_distance(*self.all_edges[-1]),\n", " vtype=grb.GRB.CONTINUOUS)\n", " \n", " def __add_degree_bounds(self, model, varmap):\n", " for v in self.points:\n", " edgevars = 0\n", " for e in self.edges_of[v]:\n", " if e in varmap:\n", " edgevars += varmap[e]\n", " model.addConstr(edgevars >= 1)\n", " model.addConstr(edgevars <= self.degree)\n", " \n", " def __add_total_edges(self, model, varmap):\n", " model.addConstr(sum(varmap.values()) == len(self.points)-1)\n", "\n", " def __make_edges(self):\n", " edges_of = {p: [] for p in self.points}\n", " for e in self.all_edges:\n", " edges_of[e[0]].append(e)\n", " edges_of[e[1]].append(e)\n", " return edges_of\n", " \n", " def __add_bottleneck_constraints(self):\n", " for e, x_e in self.bnvars.items():\n", " self.model_bottleneck.addConstr(self.l >= squared_distance(*e) * x_e)\n", " \n", " def __get_integral_solution(self, model, varmap):\n", " \"\"\"\n", " Bestimmt den Graph, der durch die aktuelle ganzzahlige Zwischenlösung gebildet wird.\n", " \"\"\"\n", " variables = [x_e for e, x_e in varmap.items()]\n", " values = model.cbGetSolution(variables)\n", " graph = nx.empty_graph()\n", " graph.add_nodes_from(self.points)\n", " for i, (e, x_e) in enumerate(varmap.items()):\n", " # x_e = v in der aktuellen Lösung\n", " v = values[i]\n", " if v >= 0.5: # die Werte sind nicht unbedingt immer exakt genau 0 oder 1 (Numerik)\n", " graph.add_edge(e[0], e[1])\n", " return graph\n", " \n", " def __forbid_component(self, model, varmap, component):\n", " \"\"\"\n", " Verbiete die Komponente component, indem erzwungen wird,\n", " dass wenigstens eine Kante über den Rand der Komponente gewählt werden muss.\n", " \"\"\"\n", " crossing_edges = 0\n", " for v in component:\n", " for e in self.edges_of[v]:\n", " if e in varmap:\n", " target = e[0] if e[0] != v else e[1]\n", " if target not in component:\n", " crossing_edges += varmap[e]\n", " # Das eigentliche Constraint wird statt mit addConstr über cbLazy eingefügt.\n", " model.cbLazy(crossing_edges >= 1)\n", " \n", " def __callback_integral(self, model, varmap):\n", " # Hier müssen wir überprüfen, ob die Lösung zusammenhängend ist.\n", " # Falls das nicht der Fall ist, müssen wir zusätzliche Bedingungen hinzufügen,\n", " # die die aktuelle Lösung verbieten.\n", " graph = self.__get_integral_solution(model, varmap)\n", " for component in nx.connected_components(graph):\n", " if len(component) == len(self.points):\n", " # Die Komponente enthält alle Knoten,\n", " # der Graph ist also zusammenhängend\n", " return\n", " self.__forbid_component(model, varmap, component)\n", "\n", " def __callback_fractional(self, model, varmap):\n", " # hier müssen wir streng genommen nichts tun;\n", " # es gibt allerdings Dinge die wir tun können,\n", " # die die Suche beschleunigen können.\n", " # Die aktuelle Lösung erhalten wir über die Methode\n", " # model.cbGetNodeRel(Liste der Variablen).\n", " # Sie kann nicht-ganzzahlige Werte für die Variablen enthalten,\n", " # die eigentlich ganzzahlig sein sollten.\n", " pass\n", "\n", " def callback(self, where, model, varmap):\n", " if where == grb.GRB.Callback.MIPSOL:\n", " # wir haben eine ganzzahlige Zwischenlösung\n", " self.__callback_integral(model, varmap)\n", " elif where == grb.GRB.Callback.MIPNODE and \\\n", " model.cbGet(grb.GRB.Callback.MIPNODE_STATUS) == grb.GRB.OPTIMAL:\n", " # wir haben eine nicht-ganzzahlige Zwischenlösung\n", " self.__callback_fractional(model, varmap)\n", "\n", " def __init__(self, points, edges, degree):\n", " self.points = points\n", " self.all_edges = edges\n", " self.degree = degree\n", " self.edges_of = self.__make_edges()\n", " self.model_bottleneck = grb.Model() # Das IP-Modell für das min Bottleneck\n", " self.model_minsum = grb.Model()\n", " self.remaining_edges = None\n", " self.msvars = None\n", " self.__make_vars()\n", " self.__add_degree_bounds(self.model_bottleneck, self.bnvars)\n", " self.__add_total_edges(self.model_bottleneck, self.bnvars)\n", " self.__add_bottleneck_constraints()\n", " # Wir müssen vorher ankündigen, dass wir Lazy Constraints nutzen.\n", " # Sonst macht der Solver möglicherweise Optimierungen, die nur zulässig sind,\n", " # wenn er alle Constraints vorher kennt, und wir bekommen eine Exception.\n", " self.model_bottleneck.Params.lazyConstraints = 1\n", " # Setze die Zielfunktion\n", " self.model_bottleneck.setObjective(self.l, grb.GRB.MINIMIZE)\n", " \n", " def __init_minsum_model(self):\n", " # Erzeuge binäre Variablen (vtype=grb.GRB.BINARY) für die Kanten\n", " self.msvars = {e: self.model_minsum.addVar(lb=0, ub=1, vtype=grb.GRB.BINARY)\n", " for e in self.remaining_edges}\n", " self.__add_degree_bounds(self.model_minsum, self.msvars)\n", " self.__add_total_edges(self.model_minsum, self.msvars)\n", " self.model_minsum.Params.lazyConstraints = 1\n", " obj = sum((math.sqrt(squared_distance(*e)) * x_e for e, x_e in self.msvars.items()))\n", " self.model_minsum.setObjective(obj, grb.GRB.MINIMIZE)\n", " \n", " def __solve_bottleneck(self):\n", " # Finde optimales Bottleneck\n", " cb_bn = lambda model, where: self.callback(where, model, self.bnvars)\n", " self.model_bottleneck.optimize(cb_bn)\n", " if self.model_bottleneck.status != grb.GRB.OPTIMAL:\n", " raise RuntimeError(\"Unerwarteter Status nach Optimierung!\")\n", " sqlen = int(round(self.model_bottleneck.objVal))\n", " print(f\"Optimales Bottleneck: {math.sqrt(sqlen)}\")\n", " self.remaining_edges = filter_edges(self.all_edges, sqlen)\n", " self.__init_minsum_model()\n", " \n", " def __solve_minsum(self):\n", " # Finde optimalen Baum\n", " cb_ms = lambda model, where: self.callback(where, model, self.msvars)\n", " self.model_minsum.optimize(cb_ms)\n", " if self.model_bottleneck.status != grb.GRB.OPTIMAL:\n", " raise RuntimeError(\"Unerwarteter Status nach Optimierung!\")\n", " # Gib alle Kanten mit Wert >= 0.5 zurück\n", " # (es gibt numerische Gründe für >= 0.5 statt == 1)\n", " return [e for e, x_e in self.msvars.items() if x_e.x >= 0.5]\n", " \n", " def solve(self):\n", " self.__solve_bottleneck()\n", " return self.__solve_minsum()\n", "\n", " \n", "def solve(points, degree):\n", " greedy = GreedyDBST(points, degree)\n", " greedy_sol = greedy.solve()\n", " remaining_edges = filter_edges(greedy.all_edges, greedy.max_sq_length)\n", " ip = DBSTSolverIP(points, remaining_edges, degree)\n", " return ip.solve()" ] }, { "cell_type": "code", "execution_count": 8, "id": "781aa3bb-c937-4167-ac46-3d4baeb64386", "metadata": {}, "outputs": [], "source": [ "points = random_points(100)" ] }, { "cell_type": "code", "execution_count": 9, "id": "59292449-026c-409d-a002-0ede0433a892", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Bottleneck bei Greedy: 1918.5955801054063\n", "Changed value of parameter lazyConstraints to 1\n", " Prev: 0 Min: 0 Max: 1 Default: 0\n", "Gurobi Optimizer version 9.1.1 build v9.1.1rc0 (mac64)\n", "Thread count: 4 physical cores, 8 logical processors, using up to 8 threads\n", "Optimize a model with 670 rows, 470 columns and 3283 nonzeros\n", "Model fingerprint: 0xfa4262eb\n", "Variable types: 1 continuous, 469 integer (469 binary)\n", "Coefficient statistics:\n", " Matrix range [1e+00, 4e+06]\n", " Objective range [1e+00, 1e+00]\n", " Bounds range [1e+00, 4e+06]\n", " RHS range [1e+00, 1e+02]\n", "Presolve removed 479 rows and 3 columns\n", "Presolve time: 0.00s\n", "Presolved: 191 rows, 467 columns, 2315 nonzeros\n", "Variable types: 0 continuous, 467 integer (467 binary)\n", "\n", "Root relaxation: objective 3.681009e+06, 81 iterations, 0.00 seconds\n", "\n", " Nodes | Current Node | Objective Bounds | Work\n", " Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time\n", "\n", " 0 0 3681009.00 0 4 - 3681009.00 - - 0s\n", " 0 0 3681009.00 0 10 - 3681009.00 - - 0s\n", " 0 0 3681009.00 0 6 - 3681009.00 - - 0s\n", " 0 2 3681009.00 0 9 - 3681009.00 - - 0s\n", "* 95 16 7 3681009.0000 3681009.00 0.00% 3.7 0s\n", "\n", "Cutting planes:\n", " Lazy constraints: 212\n", "\n", "Explored 160 nodes (792 simplex iterations) in 0.21 seconds\n", "Thread count was 8 (of 8 available processors)\n", "\n", "Solution count 1: 3.68101e+06 \n", "\n", "Optimal solution found (tolerance 1.00e-04)\n", "Best objective 3.681009000000e+06, best bound 3.681009000000e+06, gap 0.0000%\n", "\n", "User-callback calls 513, time in user-callback 0.10 sec\n", "Optimales Bottleneck: 1918.5955801054063\n", "Changed value of parameter lazyConstraints to 1\n", " Prev: 0 Min: 0 Max: 1 Default: 0\n", "Gurobi Optimizer version 9.1.1 build v9.1.1rc0 (mac64)\n", "Thread count: 4 physical cores, 8 logical processors, using up to 8 threads\n", "Optimize a model with 201 rows, 469 columns and 2345 nonzeros\n", "Model fingerprint: 0x70c3c96d\n", "Variable types: 0 continuous, 469 integer (469 binary)\n", "Coefficient statistics:\n", " Matrix range [1e+00, 1e+00]\n", " Objective range [7e+01, 2e+03]\n", " Bounds range [1e+00, 1e+00]\n", " RHS range [1e+00, 1e+02]\n", "Presolve removed 10 rows and 2 columns\n", "Presolve time: 0.00s\n", "Presolved: 191 rows, 467 columns, 2315 nonzeros\n", "Variable types: 0 continuous, 467 integer (467 binary)\n", "\n", "Root relaxation: objective 5.972984e+04, 43 iterations, 0.00 seconds\n", "\n", " Nodes | Current Node | Objective Bounds | Work\n", " Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time\n", "\n", " 0 0 61746.6735 0 4 - 61746.6735 - - 0s\n", " 0 0 62518.5506 0 31 - 62518.5506 - - 0s\n", " 0 0 63093.9798 0 18 - 63093.9798 - - 0s\n", " 0 0 63101.1671 0 24 - 63101.1671 - - 0s\n", " 0 0 63163.7378 0 24 - 63163.7378 - - 0s\n", " 0 0 63229.2871 0 22 - 63229.2871 - - 0s\n", " 0 0 63416.3201 0 29 - 63416.3201 - - 0s\n", " 0 0 63477.7205 0 24 - 63477.7205 - - 0s\n", " 0 0 63477.7205 0 24 - 63477.7205 - - 0s\n", " 0 2 63477.7205 0 24 - 63477.7205 - - 0s\n", " 13989 11783 66129.3988 36 22 - 65705.9009 - 7.5 5s\n", " 32481 28680 66830.5284 50 24 - 65818.3099 - 7.1 10s\n", "*47132 34865 176 68988.462661 65877.2869 4.51% 6.9 14s\n", "*47304 32206 163 68665.783639 65878.7705 4.06% 6.9 14s\n", " 47724 32436 66672.7919 44 36 68665.7836 65879.3386 4.06% 6.9 15s\n", "H52126 34290 68519.316465 65924.1302 3.79% 6.9 18s\n", " 55615 37343 68002.5391 112 17 68519.3165 65954.6783 3.74% 6.8 20s\n", "*61582 41868 145 68504.459351 65997.3165 3.66% 6.8 21s\n", "*64851 43648 162 68460.083559 66014.3888 3.57% 6.8 23s\n", "*66873 40569 162 68235.596512 66023.3597 3.24% 6.8 23s\n", " 69484 42547 68118.4221 85 10 68235.5965 66036.0005 3.22% 6.8 25s\n", " 80057 50350 67721.8180 59 26 68235.5965 66077.6498 3.16% 6.9 30s\n", "*84611 51830 153 68175.720226 66093.4232 3.05% 6.9 31s\n", "H85401 48076 68024.408069 66095.3386 2.84% 6.9 32s\n", "H85403 43207 67863.666742 66095.3386 2.61% 6.9 32s\n", " 89897 46152 66396.3244 48 30 67863.6667 66110.6463 2.58% 7.1 35s\n", " 101144 53573 66674.3675 43 33 67863.6667 66151.7900 2.52% 7.2 40s\n", " 110719 59620 66641.0387 38 28 67863.6667 66182.7708 2.48% 7.4 45s\n", " 120936 66190 67846.4741 70 30 67863.6667 66207.1812 2.44% 7.5 50s\n", " 130741 72428 66884.7414 44 33 67863.6667 66227.6028 2.41% 7.6 55s\n", " 139537 77646 66725.4563 49 29 67863.6667 66245.4110 2.38% 7.6 60s\n", " 149414 84093 66286.9973 42 20 67863.6667 66263.1922 2.36% 7.7 65s\n", " 159746 90710 66859.3623 48 29 67863.6667 66281.2011 2.33% 7.7 70s\n", " 170741 97553 67802.2334 68 16 67863.6667 66297.6467 2.31% 7.8 75s\n", " 179778 103229 67474.5691 53 23 67863.6667 66310.6496 2.29% 7.8 80s\n", " 187823 108012 cutoff 61 67863.6667 66323.1588 2.27% 7.9 85s\n", " 198472 114680 67837.5683 74 18 67863.6667 66338.2120 2.25% 7.9 90s\n", " 207922 120352 67180.5998 62 34 67863.6667 66348.5893 2.23% 7.9 95s\n", " 218108 126631 67788.3817 56 24 67863.6667 66360.4202 2.22% 8.0 100s\n", " 228110 132784 67425.9132 57 22 67863.6667 66372.4288 2.20% 8.0 105s\n", " 237391 138090 67842.7904 62 28 67863.6667 66382.3153 2.18% 8.0 110s\n", " 247774 144560 cutoff 56 67863.6667 66392.0133 2.17% 8.0 115s\n", " 258668 150698 66860.2231 46 37 67863.6667 66402.2850 2.15% 8.0 120s\n", " 268963 156934 66858.6619 49 24 67863.6667 66411.0660 2.14% 8.1 125s\n", " 279521 163328 67780.4331 71 27 67863.6667 66420.3515 2.13% 8.1 130s\n", " 289048 169074 67837.7662 92 10 67863.6667 66427.5097 2.12% 8.1 135s\n", " 298862 174454 66719.2552 46 25 67863.6667 66436.3046 2.10% 8.1 140s\n", " 309177 180282 66870.6044 51 30 67863.6667 66445.1786 2.09% 8.1 145s\n", " 319370 186203 67192.0818 47 25 67863.6667 66453.0699 2.08% 8.1 150s\n", " 328341 191606 66948.6978 52 30 67863.6667 66459.5273 2.07% 8.1 155s\n", " 337895 197335 67252.2607 51 27 67863.6667 66466.8054 2.06% 8.1 160s\n", " 345957 202051 67796.8851 61 22 67863.6667 66472.1832 2.05% 8.2 165s\n", " 354162 206418 67119.2330 53 26 67863.6667 66477.3105 2.04% 8.2 170s\n", " 364558 212426 cutoff 76 67863.6667 66484.5359 2.03% 8.2 175s\n", " 373702 217764 67003.8116 42 37 67863.6667 66490.1937 2.02% 8.2 180s\n", " 383966 223351 67862.3428 59 29 67863.6667 66496.0227 2.02% 8.2 185s\n", " 393657 228974 66641.1384 42 33 67863.6667 66501.9187 2.01% 8.2 190s\n", " 403303 234511 67798.8709 61 21 67863.6667 66507.1843 2.00% 8.2 195s\n", " 412405 240051 cutoff 53 67863.6667 66511.9182 1.99% 8.2 200s\n", " 423565 246087 67304.7863 53 26 67863.6667 66518.9137 1.98% 8.2 205s\n", " 431540 250764 67730.8589 61 16 67863.6667 66522.8526 1.98% 8.2 210s\n", " 441903 256546 67734.5477 58 28 67863.6667 66528.7026 1.97% 8.3 215s\n", " 451784 262173 66779.8146 47 22 67863.6667 66533.7323 1.96% 8.3 220s\n", " 461370 267737 66941.8361 48 22 67863.6667 66539.0286 1.95% 8.3 225s\n", " 469062 272112 67785.3625 58 28 67863.6667 66542.3430 1.95% 8.3 230s\n", " 477718 276589 cutoff 60 67863.6667 66546.6307 1.94% 8.3 235s\n", " 488051 282223 67313.5073 47 24 67863.6667 66551.8927 1.93% 8.3 240s\n", " 497544 287387 66921.2946 48 33 67863.6667 66556.4581 1.93% 8.3 245s\n", " 508203 293158 67796.4045 101 8 67863.6667 66561.3618 1.92% 8.3 250s\n", " 518393 298716 67248.8757 54 24 67863.6667 66565.9799 1.91% 8.3 255s\n", " 529108 304600 67615.4199 80 19 67863.6667 66570.6083 1.91% 8.3 260s\n", "H535464 297079 67784.689665 66573.3974 1.79% 8.3 262s\n", " 538815 299063 67695.9477 59 28 67784.6897 66574.8928 1.78% 8.3 265s\n", " 550140 304731 67667.0679 73 16 67784.6897 66579.7281 1.78% 8.3 270s\n", " 559806 309622 cutoff 59 67784.6897 66583.8284 1.77% 8.3 275s\n", " 568609 314341 67496.4582 64 16 67784.6897 66587.6917 1.77% 8.3 280s\n", " 579343 319661 67165.2797 44 22 67784.6897 66591.9865 1.76% 8.3 285s\n", " 586782 323612 67606.9428 50 24 67784.6897 66594.6446 1.76% 8.3 290s\n", " 596539 328515 66776.9128 37 37 67784.6897 66598.6566 1.75% 8.3 295s\n", " 605886 333228 67494.9097 50 34 67784.6897 66602.0400 1.74% 8.4 300s\n", " 614208 337523 67098.5197 57 34 67784.6897 66605.3128 1.74% 8.4 305s\n", " 624352 342496 67765.1763 64 25 67784.6897 66609.5331 1.73% 8.4 310s\n", " 632726 346275 66996.8894 45 24 67784.6897 66612.3531 1.73% 8.4 315s\n", " 641769 351496 67432.0755 53 28 67784.6897 66615.8808 1.72% 8.4 320s\n", " 650441 355747 67421.2660 57 27 67784.6897 66619.0160 1.72% 8.4 325s\n", " 659373 360028 67597.3593 54 29 67784.6897 66622.2971 1.71% 8.4 330s\n", " 669447 364873 66645.5133 49 32 67784.6897 66625.7582 1.71% 8.4 335s\n", " 678667 369480 67397.4325 69 17 67784.6897 66629.1211 1.70% 8.4 340s\n", " 688461 374183 cutoff 69 67784.6897 66632.5108 1.70% 8.4 345s\n", " 698414 379143 67452.6379 49 16 67784.6897 66635.7282 1.70% 8.4 350s\n", " 707177 383254 67392.0473 58 30 67784.6897 66638.6710 1.69% 8.4 355s\n", " 717031 388218 67627.5640 57 21 67784.6897 66641.7969 1.69% 8.4 360s\n", " 726812 392990 67127.1787 44 29 67784.6897 66644.7668 1.68% 8.4 365s\n", " 734957 396990 66884.4227 51 27 67784.6897 66647.3006 1.68% 8.4 370s\n", " 745094 401944 66861.8459 43 26 67784.6897 66650.4592 1.67% 8.4 375s\n", " 754690 406460 67644.8363 50 28 67784.6897 66653.2871 1.67% 8.4 380s\n", " 763596 410586 66875.1284 53 30 67784.6897 66655.8379 1.67% 8.4 385s\n", " 771708 414403 67778.0212 77 - 67784.6897 66657.9596 1.66% 8.4 390s\n", " 781389 419259 67485.2281 57 22 67784.6897 66661.0186 1.66% 8.4 395s\n", " 790444 423901 66860.8818 43 24 67784.6897 66663.3930 1.65% 8.4 400s\n", " 800128 428516 67462.7277 65 25 67784.6897 66666.4175 1.65% 8.4 405s\n", " 809103 432946 67417.2201 65 30 67784.6897 66668.8959 1.65% 8.4 410s\n", " 819067 437572 67317.8637 48 30 67784.6897 66671.5111 1.64% 8.4 415s\n", " 828144 441808 67465.8577 48 28 67784.6897 66674.1792 1.64% 8.4 420s\n", " 837387 446188 cutoff 57 67784.6897 66676.7831 1.63% 8.4 425s\n", " 847111 450722 67049.1391 65 31 67784.6897 66679.3620 1.63% 8.4 430s\n", " 856121 454368 67568.8117 59 37 67784.6897 66681.6587 1.63% 8.4 435s\n", " 863981 458543 66794.3141 44 24 67784.6897 66683.6780 1.62% 8.4 440s\n", " 871516 462498 67240.8740 50 35 67784.6897 66685.6293 1.62% 8.4 445s\n", " 880488 466848 66954.9609 49 34 67784.6897 66688.0161 1.62% 8.4 450s\n", " 889393 470976 cutoff 74 67784.6897 66690.2413 1.61% 8.4 455s\n", " 898165 475313 67555.6473 54 20 67784.6897 66692.6947 1.61% 8.4 460s\n", " 906586 479062 67534.8714 48 28 67784.6897 66694.7366 1.61% 8.4 465s\n", " 915749 483082 cutoff 69 67784.6897 66697.0031 1.60% 8.4 470s\n", " 926078 488205 67070.9066 49 24 67784.6897 66699.5702 1.60% 8.4 475s\n", " 935253 492198 67725.6254 66 20 67784.6897 66701.7236 1.60% 8.4 480s\n", " 945325 497051 cutoff 60 67784.6897 66704.1504 1.59% 8.4 485s\n", " 954390 501068 cutoff 61 67784.6897 66706.3393 1.59% 8.4 490s\n", " 962248 504946 67614.3996 55 21 67784.6897 66708.2850 1.59% 8.4 495s\n", " 971715 509358 66957.9452 54 40 67784.6897 66710.2605 1.59% 8.4 500s\n", " 980848 513606 66926.3920 50 33 67784.6897 66712.1928 1.58% 8.5 505s\n", " 990919 518203 66930.8350 64 18 67784.6897 66714.4064 1.58% 8.5 510s\n", " 999655 522451 67583.7692 54 30 67784.6897 66716.3361 1.58% 8.5 515s\n", " 1009960 527254 66779.5980 53 22 67784.6897 66718.7894 1.57% 8.5 520s\n", " 1018714 531257 67604.9369 49 28 67784.6897 66720.6244 1.57% 8.5 525s\n", " 1029256 536217 67575.8578 67 23 67784.6897 66722.9874 1.57% 8.5 530s\n", " 1038070 540212 67484.0551 49 25 67784.6897 66725.1376 1.56% 8.5 535s\n", " 1046963 544279 67557.8589 50 27 67784.6897 66727.0296 1.56% 8.5 540s\n", " 1056617 548652 67705.4197 50 28 67784.6897 66729.1094 1.56% 8.5 545s\n", " 1065680 553031 67442.4064 46 33 67784.6897 66730.9509 1.55% 8.5 550s\n", " 1075906 556911 67617.4918 57 17 67784.6897 66732.9121 1.55% 8.5 555s\n", " 1083686 560542 67501.4524 44 22 67784.6897 66734.6312 1.55% 8.5 560s\n", " 1092550 564611 66972.3803 46 26 67784.6897 66736.4920 1.55% 8.5 565s\n", " 1101138 568463 66879.7430 49 42 67784.6897 66738.3822 1.54% 8.5 570s\n", " 1111415 573316 67757.5137 51 31 67784.6897 66740.5307 1.54% 8.5 575s\n", " 1121516 577410 67420.7498 57 36 67784.6897 66742.5390 1.54% 8.5 580s\n", " 1129342 581389 67103.7967 52 30 67784.6897 66744.1504 1.54% 8.5 585s\n", " 1139868 586028 infeasible 81 67784.6897 66746.1716 1.53% 8.5 590s\n", " 1148934 590174 67319.3366 56 25 67784.6897 66748.1318 1.53% 8.5 595s\n", " 1158192 594272 cutoff 58 67784.6897 66750.0772 1.53% 8.5 600s\n", " 1168133 598734 67513.6080 53 38 67784.6897 66751.7291 1.52% 8.5 605s\n", " 1177001 602595 66990.5419 45 30 67784.6897 66753.5064 1.52% 8.5 610s\n", " 1187346 607029 67154.9855 49 28 67784.6897 66755.5167 1.52% 8.5 615s\n", " 1195292 610720 67130.1296 44 25 67784.6897 66756.9031 1.52% 8.5 620s\n", " 1203615 614689 67354.3427 49 21 67784.6897 66758.4882 1.51% 8.5 625s\n", " 1213052 618807 67417.4784 47 24 67784.6897 66760.1294 1.51% 8.5 630s\n", " 1222255 622795 67751.0029 48 23 67784.6897 66761.9021 1.51% 8.5 635s\n", " 1231486 626723 67480.8947 42 27 67784.6897 66763.5594 1.51% 8.5 640s\n", " 1241709 631329 cutoff 58 67784.6897 66765.4754 1.50% 8.5 645s\n", " 1250954 635429 67023.0770 52 22 67784.6897 66767.0901 1.50% 8.5 650s\n", " 1260949 639600 67598.1456 56 20 67784.6897 66768.9355 1.50% 8.5 655s\n", " 1270337 643781 67534.4962 54 25 67784.6897 66770.5326 1.50% 8.5 660s\n", " 1279183 647704 67473.1291 52 24 67784.6897 66772.1859 1.49% 8.5 665s\n", " 1287942 651570 cutoff 50 67784.6897 66773.7986 1.49% 8.5 670s\n", "\n", "Cutting planes:\n", " Gomory: 8\n", " MIR: 27\n", " Flow cover: 27\n", " Zero half: 62\n", " Lazy constraints: 2825\n", "\n", "Explored 1289942 nodes (10940722 simplex iterations) in 671.10 seconds\n", "Thread count was 8 (of 8 available processors)\n", "\n", "Solution count 10: 67784.7 67863.7 68024.4 ... 68988.5\n", "\n", "Solve interrupted\n", "Best objective 6.778468966455e+04, best bound 6.677416308379e+04, gap 1.4908%\n", "\n", "User-callback calls 2603210, time in user-callback 10.39 sec\n" ] }, { "data": { "image/png": "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\n", "text/plain": [ "<Figure size 504x504 with 1 Axes>" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "draw_edges(solve(points, 3))" ] }, { "cell_type": "code", "execution_count": null, "id": "b5180deb-4cc3-41f2-a440-e04f787b93df", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.12" } }, "nbformat": 4, "nbformat_minor": 5 }