diff --git a/sheets/04_mip/dbst_mip/README.md b/sheets/04_mip/MIP/dbst_mip/README.md similarity index 100% rename from sheets/04_mip/dbst_mip/README.md rename to sheets/04_mip/MIP/dbst_mip/README.md diff --git a/sheets/04_mip/MIP/dbst_mip/__init__.py b/sheets/04_mip/MIP/dbst_mip/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..c1076424360a9f6b3f86ce3fa742624a4f709724 --- /dev/null +++ b/sheets/04_mip/MIP/dbst_mip/__init__.py @@ -0,0 +1,5 @@ +from .util import Node, Edge, Set, draw_edges, squared_distance + +from .greedy import GreedyDBST + +from .solver import DBSTSolverIP \ No newline at end of file diff --git a/sheets/04_mip/MIP/dbst_mip/greedy.py b/sheets/04_mip/MIP/dbst_mip/greedy.py new file mode 100644 index 0000000000000000000000000000000000000000..cdb7c2741f1ecf7662465ff17c6439f7010863e2 --- /dev/null +++ b/sheets/04_mip/MIP/dbst_mip/greedy.py @@ -0,0 +1,51 @@ +from .util import all_edges_sorted, squared_distance +import math + +class GreedyDBST: + """ + Solve DBST using a greedy heuristic, similar to Kruskal's algorithm for MST. + Sort all edges of the graph, iteratively pick the shortest viable edge + (That does not create a cycle or violates the degree constraint of a node) + and add it to the tree, until all nodes are connected (n-1 edges needed). + The connected components are managed in a 'disjoint-set' or 'union-find' + datastructure, which is used to efficiently check whether two vertices are + partof the same component (adding an edge would create a cycle). + """ + def __init__(self, points, degree): + self.points = points + self.all_edges = all_edges_sorted(points) + self._component_of = {v: v for v in points} + self.degree = degree + + def __component_root(self, v): + cof = self._component_of[v] + if cof != v: + cof = self.__component_root(cof) + self._component_of[v] = cof + return cof + + def __merge_if_not_same_component(self, v, w): + cv = self.__component_root(v) + cw = self.__component_root(w) + if cv != cw: + self._component_of[cw] = cv + return True + return False + + def solve(self): + edges = [] + degree = {v: 0 for v in self.points} + n = len(self.points) + m = 0 + for v,w in self.all_edges: + if degree[v] < self.degree and degree[w] < self.degree: + if self.__merge_if_not_same_component(v,w): + edges.append((v,w)) + degree[v] += 1 + degree[w] += 1 + m += 1 + if m == n-1: + self.max_sq_length = squared_distance(v,w) + print(f"Greedy bottleneck: {math.dist(v,w)}") + break + return edges \ No newline at end of file diff --git a/sheets/04_mip/MIP/dbst_mip/solver.py b/sheets/04_mip/MIP/dbst_mip/solver.py new file mode 100644 index 0000000000000000000000000000000000000000..2ce46b16d8a4f4e6078dd51449a4cf3428e08e60 --- /dev/null +++ b/sheets/04_mip/MIP/dbst_mip/solver.py @@ -0,0 +1,169 @@ +import gurobipy as grb +import itertools +import networkx as nx +from networkx.classes.graphviews import subgraph_view +import math + +class DBSTSolverIP: + def __make_vars(self): + # Create binary variables for every *undirected* edge + self.bnvars = {e: self.model_bottleneck.addVar(lb=0, ub=1, vtype=grb.GRB.BINARY) for e in self.all_edges} + # Create a fractional variable (vtype=grb.GRB.CONTINUOUS) for the bottleneck length + self.l = self.model_bottleneck.addVar(lb=0, ub=math.dist(*self.all_edges[-1]), vtype=grb.GRB.CONTINUOUS) + + def __add_degree_bounds(self, model, varmap: dict): + """ + Enforce the degree constraint. + This implementation accepts a dictionary for the edge variables, + which is useful for use in multiple models. + """ + for v in self.points: + edgevars = 0 + for e in self.edges_of[v]: + if e in varmap: + edgevars += varmap[e] + model.addConstr(edgevars >= 1) + model.addConstr(edgevars <= self.degree) + + def __add_total_edges(self, model, varmap: dict): + """ + Enforce the constraint sum(x_e) = n-1 + """ + model.addConstr(sum(varmap.values()) == len(self.points)-1) + + def __make_edges(self): + edges_of = {p: list() for p in self.points} + for e in self.all_edges: + edges_of[e[0]].append(e) + edges_of[e[1]].append(e) + return edges_of + + def __add_bottleneck_constraints(self): + """ + Enforce the bottleneck constraints. + """ + for e, x_e in self.bnvars.items(): + self.model_bottleneck.addConstr(self.l >= math.dist(*e) * x_e) + + def __get_integral_solution(self, model, varmap: dict) -> nx.Graph: + """ + Constructs a graph from the current solution of the given model. + To be used inside of a callback. + """ + variables = [x_e for e, x_e in varmap.items()] + values = model.cbGetSolution(variables) + graph = nx.empty_graph() + graph.add_nodes_from(self.points) + for i, (e, x_e) in enumerate(varmap.items()): + # x_e has value v in the current solution + v = values[i] + if v >= 0.5: # the values are not always 0 or 1 due to numerical errors + graph.add_edge(e[0], e[1]) + return graph + + def __forbid_component(self, model, varmap: dict, component): + """ + Forbid the occurence of multiple, disconnected components, by enforcing + leaving edges for all occuring components. + """ + crossing_edges = 0 + for v in component: + for e in self.edges_of[v]: + if e in varmap: + target = e[0] if e[0] != v else e[1] + if target not in component: + crossing_edges += varmap[e] + # The constraint is added using "cbLazy" instaed of "addConstr" in a callback. + model.cbLazy(crossing_edges >= 1) + + def __callback_integral(self, model, varmap): + # Check whether the solution is connected + graph = self.__get_integral_solution(model, varmap) + components = list(nx.connected_components(graph)) + + if len(components) == 1: + # Graph is connected. Do nothing! + return + else: + # Make components connected. + for component in components: + self.__forbid_component(model, varmap, component) + + def __callback_fractional(self, model, varmap): + # Nothing has to be done in here. + # Some more advanced techniques can be used to add helpful constraints + # just from looking at a fractional solution, but this exceeds the scope + # of this course. It can still be interesting to analyze fractional solutions + # that the solver comes up with. + pass + + def callback(self, where, model, varmap): + if where == grb.GRB.Callback.MIPSOL: + # we have an integral solution (potentially valid solution) + self.__callback_integral(model, varmap) + elif where == grb.GRB.Callback.MIPNODE and \ + model.cbGet(grb.GRB.Callback.MIPNODE_STATUS) == grb.GRB.OPTIMAL: + # we have a fractional solution + # (intermediate solution with fractional values for all booleans) + self.__callback_fractional(model, varmap) + + def __init__(self, points, edges, degree): + self.points = points + self.all_edges = edges + self.degree = degree + self.edges_of = self.__make_edges() + self.model_bottleneck = grb.Model() # "First stage" model for finding the bottleneck edge + self.model_minsum = grb.Model() # "Second stage" model for finding the cost-minimal DBST with fixed bottleneck. + self.remaining_edges = None + self.msvars = None + self.__make_vars() + self.__add_degree_bounds(self.model_bottleneck, self.bnvars) + self.__add_total_edges(self.model_bottleneck, self.bnvars) + self.__add_bottleneck_constraints() + # Give the solver a heads up that lazy constraints will be utilized + self.model_bottleneck.Params.lazyConstraints = 1 + # Set the first objective + self.model_bottleneck.setObjective(self.l, grb.GRB.MINIMIZE) + + def __init_minsum_model(self): + """ + Set up variables, constraints and objective function for the + second stage model. + """ + # Create binary variables (vtype=grb.GRB.BINARY) for all edges + self.msvars = {e: self.model_minsum.addVar(lb=0, ub=1, vtype=grb.GRB.BINARY) + for e in self.remaining_edges} + self.__add_degree_bounds(self.model_minsum, self.msvars) + self.__add_total_edges(self.model_minsum, self.msvars) + self.model_minsum.Params.lazyConstraints = 1 + obj = sum((math.dist(*e) * x_e for e, x_e in self.msvars.items())) + self.model_minsum.setObjective(obj, grb.GRB.MINIMIZE) + + def __solve_bottleneck(self): + # Find the optimal bottleneck (first stage) + cb_bn = lambda model, where: self.callback(where, model, self.bnvars) + self.model_bottleneck.optimize(cb_bn) + if self.model_bottleneck.status != grb.GRB.OPTIMAL: + raise RuntimeError("Unexpected status after optimization!") + bottleneck = self.model_bottleneck.objVal + print(f"[DBST SOLVER]: Found the optimal bottleneck! Bottleneck length is {bottleneck}") + self.remaining_edges = [e for e in self.all_edges if math.dist(*e) <= bottleneck] + return [e for e, x_e in self.bnvars.items() if x_e.x >= 0.5] + + def __solve_minsum(self): + # Find the optimal tree (second stage) + self.__init_minsum_model() + cb_ms = lambda model, where: self.callback(where, model, self.msvars) + self.model_minsum.optimize(cb_ms) + if self.model_bottleneck.status != grb.GRB.OPTIMAL: + raise RuntimeError("Unexpected status after optimization!") + # Return all edges with value >= 0.5 (numerical reasons) + print(f"[DBST SOLVER]: Found the optimal tree! Total cost: {self.model_minsum.objVal}") + return [e for e, x_e in self.msvars.items() if x_e.x >= 0.5] + + def solve(self, minsum: bool = False): + dbst_edges = self.__solve_bottleneck() + if not minsum: + return dbst_edges + else: + return self.__solve_minsum() \ No newline at end of file diff --git a/sheets/04_mip/MIP/dbst_mip/util.py b/sheets/04_mip/MIP/dbst_mip/util.py new file mode 100644 index 0000000000000000000000000000000000000000..30d7e8643c1815932114eab0071b7348e349f6ee --- /dev/null +++ b/sheets/04_mip/MIP/dbst_mip/util.py @@ -0,0 +1,39 @@ +from typing import List, Set, Tuple, Iterable, Optional +import matplotlib.pyplot as plt +import networkx as nx +import itertools + +Node = Tuple[int, int] +Edge = Tuple[Node, Node] + +def squared_distance(p1: Node, p2: Node): + """ + Calculate the squared euclidian distance between two points p1, p2. + """ + return (p1[0]-p2[0])**2 + (p1[1]-p2[1])**2 + +def all_edges_sorted(points: Iterable[Node]) -> List[Node]: + """ + Create a list containing all edges between each two points of the given + point set/list and returns them in sorted, ascending order. + """ + edges = [(v,w) for v, w in itertools.combinations(points, 2)] + edges.sort(key=lambda e: squared_distance(*e)) # *e is like e[0], e[1] + return edges + +def draw_edges(edges): + """ + Draws the list of edges as a graph using networkx. The bottleneck + edge is highlighted using a thicker stroke and red color. + """ + draw_graph = nx.Graph(edges) + g_edges = draw_graph.edges() + max_length = max((squared_distance(*e) for e in g_edges)) + color = [('red' if squared_distance(*e) == max_length else 'black') for e in g_edges] + width = [(1.0 if squared_distance(*e) == max_length else 0.5) for e in g_edges] + plt.clf() + fig, ax = plt.gcf(), plt.gca() + fig.set_size_inches(8,6) + nx.draw_networkx(draw_graph, pos={p: p for p in draw_graph.nodes}, node_size=8, + with_labels=False, edgelist=g_edges, edge_color=color, width=width, ax=ax) + plt.show() \ No newline at end of file diff --git a/sheets/04_mip/MIP/integer_programming.ipynb b/sheets/04_mip/MIP/integer_programming.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..47261bdbc5c50705b92ff6523d85b72730a4936e --- /dev/null +++ b/sheets/04_mip/MIP/integer_programming.ipynb @@ -0,0 +1,325 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 19, + "id": "7ee10bd7-40c0-49aa-b66a-664c8fa5bbf5", + "metadata": {}, + "outputs": [], + "source": [ + "import networkx as nx\n", + "import random\n", + "import matplotlib\n", + "import matplotlib.pyplot as plt\n", + "\n", + "from dbst_mip import *" + ] + }, + { + "attachments": {}, + "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": 20, + "id": "16d94ecd-1448-4172-9bed-9f7d0cfd21c2", + "metadata": {}, + "outputs": [], + "source": [ + "def random_points(n, w=10_000, h=10_000) -> Set[Node]:\n", + " \"\"\"\n", + " n random points with integer coordinates within the w * h rectangle.\n", + " :param n: Number of points\n", + " :param w: The width of the rectangle.\n", + " :param h: The height of the rectangle.\n", + " :return: A set of points as (x,y)-tuples.\n", + " \"\"\"\n", + " return set((random.randint(0,w), random.randint(0,h)) for _ in range(n))" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "781aa3bb-c937-4167-ac46-3d4baeb64386", + "metadata": {}, + "outputs": [], + "source": [ + "points = random_points(50)\n", + "degree = 3" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "5336a075", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Greedy bottleneck: 2211.790677256779\n", + "The greedy algorithm managed to reduce the number of edges in question to 15.755% of the graph!\n" + ] + } + ], + "source": [ + "def filter_edges(edges, max_sq_length):\n", + " \"\"\"\n", + " Return a filtered copy of the given edgelist, filtered by squared length.\n", + " \"\"\"\n", + " return [e for e in edges if squared_distance(*e) <= max_sq_length]\n", + "\n", + "# Use greedy to eliminate as many edges as possible preemptively\n", + "greedy_alg = GreedyDBST(points, degree)\n", + "greedy_tree = greedy_alg.solve()\n", + "remaining_edges = filter_edges(greedy_alg.all_edges, greedy_alg.max_sq_length)\n", + "edges_left_perc = round(100.0 * len(remaining_edges) / len(greedy_alg.all_edges), 3)\n", + "print(f\"The greedy algorithm managed to reduce the number of edges in question to {edges_left_perc}% of the graph!\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "8483ef6d", + "metadata": {}, + "source": [ + "### \"Old\" problem. Only find the bottleneck-minimal DBST." + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "893b31b5", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Set parameter LazyConstraints to value 1\n", + "Gurobi Optimizer version 9.5.2 build v9.5.2rc0 (linux64)\n", + "Thread count: 12 physical cores, 24 logical processors, using up to 24 threads\n", + "Optimize a model with 294 rows, 194 columns and 1351 nonzeros\n", + "Model fingerprint: 0xf15bc0d2\n", + "Variable types: 1 continuous, 193 integer (193 binary)\n", + "Coefficient statistics:\n", + " Matrix range [1e+00, 2e+03]\n", + " Objective range [1e+00, 1e+00]\n", + " Bounds range [1e+00, 2e+03]\n", + " RHS range [1e+00, 5e+01]\n", + "Presolve removed 206 rows and 4 columns\n", + "Presolve time: 0.00s\n", + "Presolved: 88 rows, 190 columns, 926 nonzeros\n", + "Variable types: 0 continuous, 190 integer (190 binary)\n", + "\n", + "Root relaxation: objective 2.211791e+03, 62 iterations, 0.00 seconds (0.00 work units)\n", + "\n", + " Nodes | Current Node | Objective Bounds | Work\n", + " Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time\n", + "\n", + " 0 0 2211.79068 0 6 - 2211.79068 - - 0s\n", + " 0 0 2211.79068 0 4 - 2211.79068 - - 0s\n", + " 0 0 2211.79068 0 4 - 2211.79068 - - 0s\n", + " 0 0 2211.79068 0 4 - 2211.79068 - - 0s\n", + " 0 2 2211.79068 0 6 - 2211.79068 - - 0s\n", + "* 3 4 2 2211.7906773 2211.79068 0.00% 2.0 0s\n", + "\n", + "Cutting planes:\n", + " Gomory: 2\n", + " MIR: 1\n", + " Lazy constraints: 41\n", + "\n", + "Explored 7 nodes (121 simplex iterations) in 0.04 seconds (0.00 work units)\n", + "Thread count was 24 (of 24 available processors)\n", + "\n", + "Solution count 1: 2211.79 \n", + "\n", + "Optimal solution found (tolerance 1.00e-04)\n", + "Best objective 2.211790677257e+03, best bound 2.211790677257e+03, gap 0.0000%\n", + "\n", + "User-callback calls 203, time in user-callback 0.01 sec\n", + "[DBST SOLVER]: Found the optimal bottleneck! Bottleneck length is 2211.790677256779\n" + ] + }, + { + "data": { + "image/png": "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kJqairfffhsbNmww+f2ePn0akZGROH78OPz9/dGjRw+89tprcHFxMel9W6KzZ89iypQp+Pzzz1G/fn3RcYjsRlZWFr766itER0dj/PjxCA0NtYvnnhfFs4CpUFKzVMhWaR96iwxamQL1m7dG706tUaNGDbse+dFqtcJXzMpkMrz55ptYvnw53nvvPfj4+CAjIwMqlcqkl9BlMhkaNGiABg0aAMhflRwVFYUVK1bA1dUV3bp1Q9euXVGyZEmTZbAUP//8MyIiIrB582Z4e5tvDigRAZ6enpg5cyYmTJiAb775Bp06dcK4cePQo0cPu35+MgZ+9eyYj6czPJwVMPwylb/SVY4aAeWwevVqdOvWDX369MH//d//4cSJE9BoNGIDm1laWppFPOF37doVv/32G5RKJQDgtddew/79+82aoVKlSpg8eTKioqLw7bffAgDGjx+PkJAQLFu2DImJiWbNYw46nQ4zZszA8ePHsW3bNov4XiCyV56ennjvvfewdetWxMfHo1OnTti8eXPBXq9UdLwEbOeeNwcwOzsbx48fx+HDh3Hq1CkAwKuvvoqgoCA0a9YMHh4eoqKb3JkzZ7BlyxbMmzdPdBSsX78eubm5CAsLw7Vr1/Dpp59ixYoVomNBqVTijz/+QGRkJK5fv46mTZuiR48eePXVV636Ms39+/cxevRo9OjRA8OGDRMdh4j+IycnB8uXL8eePXswduxY9OnTh4uywDmAVERFWQWs0Whw6tQpHDp0CMePH0dubi5q1qyJVq1aoVWrVihdurSZUpve3r178c8//2DChAmio0Cj0eD111/H3r17oVAo0KlTJ+zevduiHvD0ej1OnDiByMhInDp1CtWqVUNoaChat24NJycn0fEK7cKFC5g4cSIWLVqERo0aiY5DRM+Qm5uL7777Djt37sTo0aPRr18/i3pcNDcWQDIbvV6Py5cv49ChQzh8+DDS0tJQoUIFtGrVCkFBQahYsaLVjgT98MMPcHd3R58+fURHAQB8+eWX8PHxQf/+/TF79mx06tQJLVq0EB3rqa5cuYLIyEgcOHAAJUqUQEhICDp37mzRjyHbt2/HypUr8f3333NfRCIrkpeXh5UrVyIqKgojR47EgAED7LIIsgCSUElJSTh06BAOHTqExMRElCxZEi1btkSrVq1Qp04dq5m4u2jRIjRv3hxBQUGiowDI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", + "text/plain": [ + "<Figure size 800x600 with 1 Axes>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "solution_dbst = DBSTSolverIP(points, remaining_edges, degree).solve(minsum=False)\n", + "draw_edges(solution_dbst)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "08a54aad", + "metadata": {}, + "source": [ + "### \"New\" problem. Find the bottleneck and then minimize the rest of the tree as well. This can take SIGNIFICANTLY more time. You might want to implement a time limit." + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "59292449-026c-409d-a002-0ede0433a892", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Set parameter LazyConstraints to value 1\n", + "Gurobi Optimizer version 9.5.2 build v9.5.2rc0 (linux64)\n", + "Thread count: 12 physical cores, 24 logical processors, using up to 24 threads\n", + "Optimize a model with 294 rows, 194 columns and 1351 nonzeros\n", + "Model fingerprint: 0xf15bc0d2\n", + "Variable types: 1 continuous, 193 integer (193 binary)\n", + "Coefficient statistics:\n", + " Matrix range [1e+00, 2e+03]\n", + " Objective range [1e+00, 1e+00]\n", + " Bounds range [1e+00, 2e+03]\n", + " RHS range [1e+00, 5e+01]\n", + "Presolve removed 206 rows and 4 columns\n", + "Presolve time: 0.00s\n", + "Presolved: 88 rows, 190 columns, 926 nonzeros\n", + "Variable types: 0 continuous, 190 integer (190 binary)\n", + "\n", + "Root relaxation: objective 2.211791e+03, 62 iterations, 0.00 seconds (0.00 work units)\n", + "\n", + " Nodes | Current Node | Objective Bounds | Work\n", + " Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time\n", + "\n", + " 0 0 2211.79068 0 6 - 2211.79068 - - 0s\n", + " 0 0 2211.79068 0 4 - 2211.79068 - - 0s\n", + " 0 0 2211.79068 0 4 - 2211.79068 - - 0s\n", + " 0 0 2211.79068 0 4 - 2211.79068 - - 0s\n", + " 0 2 2211.79068 0 6 - 2211.79068 - - 0s\n", + "* 3 4 2 2211.7906773 2211.79068 0.00% 2.0 0s\n", + "\n", + "Cutting planes:\n", + " Gomory: 2\n", + " MIR: 1\n", + " Lazy constraints: 41\n", + "\n", + "Explored 7 nodes (121 simplex iterations) in 0.02 seconds (0.00 work units)\n", + "Thread count was 24 (of 24 available processors)\n", + "\n", + "Solution count 1: 2211.79 \n", + "\n", + "Optimal solution found (tolerance 1.00e-04)\n", + "Best objective 2.211790677257e+03, best bound 2.211790677257e+03, gap 0.0000%\n", + "\n", + "User-callback calls 193, time in user-callback 0.01 sec\n", + "[DBST SOLVER]: Found the optimal bottleneck! Bottleneck length is 2211.790677256779\n", + "Set parameter LazyConstraints to value 1\n", + "Gurobi Optimizer version 9.5.2 build v9.5.2rc0 (linux64)\n", + "Thread count: 12 physical cores, 24 logical processors, using up to 24 threads\n", + "Optimize a model with 101 rows, 193 columns and 965 nonzeros\n", + "Model fingerprint: 0xad1b479c\n", + "Variable types: 0 continuous, 193 integer (193 binary)\n", + "Coefficient statistics:\n", + " Matrix range [1e+00, 1e+00]\n", + " Objective range [1e+02, 2e+03]\n", + " Bounds range [1e+00, 1e+00]\n", + " RHS range [1e+00, 5e+01]\n", + "Presolve removed 13 rows and 3 columns\n", + "Presolve time: 0.00s\n", + "Presolved: 88 rows, 190 columns, 926 nonzeros\n", + "Variable types: 0 continuous, 190 integer (190 binary)\n", + "\n", + "Root relaxation: objective 3.806143e+04, 25 iterations, 0.00 seconds (0.00 work units)\n", + "\n", + " Nodes | Current Node | Objective Bounds | Work\n", + " Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time\n", + "\n", + " 0 0 38061.4312 0 4 - 38061.4312 - - 0s\n", + " 0 0 40450.4479 0 14 - 40450.4479 - - 0s\n", + " 0 0 41142.4378 0 21 - 41142.4378 - - 0s\n", + " 0 0 41435.8176 0 20 - 41435.8176 - - 0s\n", + " 0 0 41504.1230 0 14 - 41504.1230 - - 0s\n", + " 0 0 41561.4239 0 23 - 41561.4239 - - 0s\n", + " 0 0 41561.7464 0 23 - 41561.7464 - - 0s\n", + " 0 0 41574.2847 0 21 - 41574.2847 - - 0s\n", + " 0 0 41574.2847 0 21 - 41574.2847 - - 0s\n", + " 0 2 41574.2847 0 21 - 41574.2847 - - 0s\n", + "H 2117 1727 47018.612599 42959.7586 8.63% 3.9 0s\n", + "H 2121 1643 46275.216124 42959.7586 7.16% 3.9 0s\n", + "H 2134 1569 46221.282839 42959.7586 7.06% 3.8 0s\n", + "H 2134 1490 45948.562293 42959.7586 6.50% 3.8 0s\n", + "H 2149 1425 45849.561082 43428.2745 5.28% 3.8 0s\n", + "H 2157 1357 45725.338945 43551.9043 4.75% 3.8 0s\n", + "H 3331 1622 45704.427892 43947.7015 3.84% 4.6 0s\n", + "\n", + "Cutting planes:\n", + " Gomory: 3\n", + " MIR: 12\n", + " Flow cover: 16\n", + " Zero half: 80\n", + " Lazy constraints: 238\n", + "\n", + "Explored 20862 nodes (119818 simplex iterations) in 1.23 seconds (1.47 work units)\n", + "Thread count was 24 (of 24 available processors)\n", + "\n", + "Solution count 7: 45704.4 45725.3 45849.6 ... 47018.6\n", + "\n", + "Optimal solution found (tolerance 1.00e-04)\n", + "Best objective 4.570442789235e+04, best bound 4.570442789235e+04, gap 0.0000%\n", + "\n", + "User-callback calls 42524, time in user-callback 0.11 sec\n", + "[DBST SOLVER]: Found the optimal tree! Total cost: 45704.42789235007\n" + ] + }, + { + "data": { + "image/png": "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Fi3Qr18/NGrUSHUvIna7HT/88AM+/vhj6HQ6REZGok2bNor+PnzzzTeYP38+5s6di+bNmyv2du/EZrNh5cqVWL9+PV577TW0a9dOdCTCzUtSbDYb3n33Xfz222/44IMPEBwcLDoiKezYsWP49NNPsWDBAtFR3AYLIBEKCtBvv/2GTZs24Y8//sDDDz+Mvn37olmzZh5dBi9fvozVq1fjyy+/xGOPPYYXXnhB6O7c9PR0jBs3DjVq1MCrr74KvV4vLMu+ffswe/Zs9O7dGy+++CJ0Oh6E4OoOHz6MiRMnYty4cejevbvoOKSgFStWICAgAP369RMdxW2wABLdQJZlHDp0CJs2bcJvv/2G+vXro1+/fnjkkUeuO+bEnf3+++/46KOPkJqaiueeew7du3d3qYLzxRdf4NNPP8WiRYsUv9T93LlzmDZtGvz8/DB79mweK+FmTCYTXn31VeTk5GDBggXw9fUVHYkU8OKLL2LmzJmqu3XnfrAAEt2BLMs4evQoNm/ejP3796NWrVro168f2rRp43YH/ZpMJmzYsAFr165FnTp1MGLECDz44IOiY93W+fPnMXr0aLRt2xZjx451evk2mUxYuHAh9u3bh+joaDRs2NCpb4+c64cffsCcOXMwZ84ctGzZUnQccjIeAH3vWACJ7sGJEyewefNm/PTTT6hatSr69u2Lxx9/XOijyrs5ffo0li5dij/++AMDBgxAeHg4fHxuvm7LFcmyjGXLlmHnzp348MMPnbL5QpZl7NixA4sWLcKIESPQv39/j37sryYZGRkYN24cqlatitdee82lP06p+LKysvDCCy9gw4YNoqO4FRZAomI6deoUNm/ejD179qBixYro27cvOnToAINB3C0pDjabDV9//XXhupgRI0agefPmblts4uPjMWbMGISHh+OZZ54psffjr7/+wrRp09CwYUNMnTrVJXcg0/1bv349Vq5ciffff9+lp95UPLt378ahQ4cwadIk0VHcCgsgUQk4c+YMtmzZgu+++w5ly5ZF79690blzZ8XPibt48SJWrlyJb7/9Fp07d8bzzz/vMXckW61WvP322zh8+DAWL158X5e9Z2ZmYvbs2UhOTsbcuXNRrVq1kgtKLuns2bMYNWoUOnXqhJEjR7rtP4boZnPmzEG7du3w6KOPio7iVlgAiUrY+fPnsXXrVnzzzTfw8fFB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CaCLqFu3Lnr37o05c+Yo8vYKbyEwF2xAyc23ut0tBDfepOCO7wMR0bVYAEkpnAC6kOeeew5Dhw7F//73Pzz22GMl+mvn5OTg6NGjOHLkCI4cOYKT5y4hp3ZE4f+X5YJbCHqGPwODJbtE37azmPV+yKk1qPDbjvchNduM0EBvgcmIiIqHBZCUwgLoQiRJwuLFi9GjRw/Uq1cP5cqVu+dfw263IzExEUeOHMHhw4dx9OhR5OXlwcfHBw0aNEDDhg0xceJEVKwcgqbRu5GbX3AVlSQVHES77YvP3OY4CpPFhqZzvr/pfeBNCkTkrlgASSksgC7G19cXCxcuRGRkJNasW4+LuZbbHhCblZWFo0eP4vDhwzhy5AjOnDkDjUaDatWqoWHDhujSpQsmTZoEHx+fW76tZRFNCtfPueMtBI6bFNz5fSAiuhYLICmFBdAFNWrUCA+27YGGs76CBVr4GnSY8UQFaC/G48iRIzh27BiuXLkCPz8/NGjQAI0aNULXrl0REhICyXGxaBF4wi0EnvA+EBE56HQ6Xg5AimABdEEmiw07MirCIlsACcgx5WPargRMCctE9+7dMXXqVHh7l8waN8ctBO7ME94HIiKAE0BSDgugC0rNNiPHbC1Y1AYAkgZWaNC5TziLDhGRB2MBJKXwGBgXFOxngK9B91//kwBfAzc3EBF5OhZAUgoLoAtybG7w8SoY0HJzAxGROrAAklL4CNhFcXMDEZH6sACSUlgAXRg3NxARqQsLICmFj4CJiIhchKTTIznbwistyelYAImIiFzAvvg0LD5bGTMPAk3nfI998WmiI5EHYwEkIiISzGSxITImDvn2guMfcvOtiIyJ4ySQnIYFkIiISDDH+a8yCgqgLAM5ZitSs82Ck5GnYgEkIiISjOe/ktJYAImIiATj+a+kNB4DQ0RE5AJ4/ispiQWQiIjIRfD8V1IKHwETERERqQwLIBEREZHKsAASERERqQwLIBEREZHKsAASERERqQwLIBEREZHKsAASERERqQwLIBEREZHKsAASERERqQwLIBEREZHKsAASERERqQwLIBEREZHKsAASERERqQwLIBEREZHKsAASERERqQwLIBEREZHKsAASERERqQwLIBEREZHKsAASERERqQwLIBEREZHKsAASERERqQwLIBEREZHKsAASERERqQwLIBEREZHKsAASERERqQwLIBEREZHKsAASERERqQwLIBEREZHKsAASERERqQwLIBEREZHKsAASERERqQwLIBEREZHKsAASERERqQwLIBEREZHK6Iryg2RZBgBkZWU5NQwRERERFY+jpzl6250UqQBmZ2cDAEJCQu4jFhERERE5W3Z2NgICAu74YyS5CDXRbrfj/Pnz8PPzgyRJJRaQiIiIiEqGLMvIzs5GpUqVoNHceZVfkQogEREREXkObgIhIiIiUhkWQCIiIiKVYQEkIiIiUhkWQCIiIiKVYQEkIiIiUhkWQCIiIiKVYQEkIiIiUpn/B4Ar2fxF1zpYAAAAAElFTkSuQmCC", + "text/plain": [ + "<Figure size 800x600 with 1 Axes>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "solution_dbst_minsum = DBSTSolverIP(points, remaining_edges, degree).solve(minsum=True)\n", + "draw_edges(solution_dbst_minsum)" + ] + } + ], + "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.10.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/sheets/04_mip/dbst_mip/integer_programming.ipynb b/sheets/04_mip/dbst_mip/integer_programming.ipynb deleted file mode 100644 index 3f39dc70459e3090691b7f5cc90a40f618067555..0000000000000000000000000000000000000000 --- a/sheets/04_mip/dbst_mip/integer_programming.ipynb +++ /dev/null @@ -1,651 +0,0 @@ -{ - "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": "iVBORw0KGgoAAAANSUhEUgAAAZMAAAGRCAYAAACg1F5qAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4zLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvIxREBQAAIABJREFUeJzs3XdUFOcaBvBntlEEFAQUKyJqEERFsGKJvRF7jzG2FGOMmgSVIkUjEbFFTbHEEoO9xWg01iTEhhUbFhB7WUGRBWTb3D8IXLuU3f1mdt/fOTn3JmFnnuDuvvN1jud5EEIIIaUhYR2AEEKI+FExIYQQUmpUTAghhJQaFRNCCCGlRsWEEEJIqVExIYQQUmpUTAghhJQaFRNCCCGlRsWEEEJIqcmK88POzs68u7u7kaIQQggRmhMnTjzked7lbT9XrGLi7u6O48ePlzwVIYQQUeE47npRfo66uQghhJQaFRNCCCGlRsWEEEJIqVExIYQQUmpUTAghhJQaFRNCCCGlRsWEEEJIqVExIYQQUmpUTAghhJQaFRNCCCGlRsWEEEJIqVExIYQQUmpUTAghhJQaFRMzl6pUYV3iDaQqVayjEELMWLG2oCfikqpUofvCBOj1PABg/YiG8KnuComEniEIEZpUpQqJaRkIcHeCh4sd6zjFRsXEjCWmZYDngadaPeScHvPjd6C67jZ4nn/u5579e57nYW1tjbJly772L3t7e0ilUlP/5xBitgoe/Hge4Djg97GBoisoVEzMWIC7EzgOsJFLwXFShH40oEhv0KdPnyIzM/O5v65cuVL4/7OysqDX6597DcdxzxUluVz+xoLk4OAAmaz4bz+xP70R8irH0jKg1mig5SWwkUuRmJYhuvc3FRMz5uFih9/HBhb7y9fa2hrW1taoUKFCie+tVqtfKkjXrl0r/P9PnjyBTqd75WsLipJMJnuuAOXK7BF5JA9AfvFaOegdeFZwgFwuh0KhgFwuL3aLiYoTYU2r1eLwtl8glTSAhOeh1+sQ4O7EOlaxUTExcx4udky+JBUKBVxcXODi8tajo19Lo9E8V4y2n08Hz+uh1nOQczqs2JGAutaPoVarodFooFarX2oxvUmm3grbNd6QyWSQSCSi7Fog4qZSqRAaGooxY8bgC6fKOJaWgT2//gD38l1YRys2KiZEsORyOZydneHs7AwAKFdVhXVXEyDlAY6T4usPe5Xqy39d4g3s2n4euRo9rOW8KLsWiHjduXMH33zzDSIiIuDq6gog/+GvmiYI69atw6BBgxgnLB4qJkQ0Stpt9zr5Y0ocbOQSqNVq+FaiQkJM4+zZs1i+fDni4uJgY2Pz3L9r3rw5Nm3ahD59+kChUDBKWHzcizN73sTf358/fvy4EeMQYloFYyZVbTTYsGwh4uLiaKbaC2hcybD27NmDI0eOIDQ09LXT9C9evIgDBw5gzJgxJk73Mo7jTvA87/+2n6OWCbFoz44plR01ClFRUYiKigLHcYyTCUOqUoVuCxIAiHfKqpCsWLECGo0G4eHhb/w5Ly8vrF69Gk+ePIGDg4OJ0pUOrV4j5D/e3t5o3749vvvuO9ZRBCMxLQM6nQ65Gh14Pv/vSfHp9XrExMTAxcUFo0ePLtJrxowZg++//97IyQyHigkhz2jVqhWqVKmC+Ph41lEEIcDdCTKZFAoJD61WI8opq6w9ffoUwcHB6NSpE7p161bk11WuXBk6nQ737t0zYjrDoWJCyAv69OmDJ0+eYM+ePayjMFcw6WFaT1+Mq5ODo3u3s44kKunp6fjyyy/xxRdfwM/Pr9iv/+yzz7Bo0SIjJDM80RYT2sCQGNMnn3yCI0eO4NSpU6yjMOfhYocBAdXw+bAByMvLw5YtW1hHEoWrV68iMjISMTExqFq1aomuUa5cObi4uODy5csGTmd4oiwmqUoVui/4B5G/nUf3hQlUUIhRhIaGIj4+HmlpaayjCMaHH36Ie/fu4Y8//mAdRdAOHTqEn3/+GXPmzCn1APpHH32EJUuWGCiZ8YiymCSmZYDXapGr1YPneRoUJEYhkUjwzTffIC4uDunp6azjCMann36K5ORkHDx4kHUUQdq4cSOOHj2Kb775BnK5vNTXs7a2hq+vL44dO2aAdMYjymIS4O4ETi6HjV4DTq2mQUFiNAqFAjNmzMDUqVORm5vLOo5gTJgwAYcOHcKRI0dYRxGEVKUKaxNvIGrOD9DpdJgwYYJBp5cPHjwY8fHxL+34LSSiLCYFg4KR3evi971x8Ni2lnUkYsYcHBwQGhqKKVOmvHZzSks0ZcoU/PHHHxY/rpTf7Z6A0M2nEZ9RDQFtiz5jq6ikUik6duyI3bt3G/zahiLKYgL8NyjYsjY8fl0KhIQAhw+zjkTMWKVKlfDxxx8jMjJS0E+HpsRxHCIiIrB+/XpcvHiRdRxmEtMyoNProIMUEonUaN3uXbp0wa5du4q1makpibaYFKpTB/j5Z6BfP+DOHdZpiBnz8vJC586dMX/+fNZRBEMikWD69OlYtmwZUlJSWMdhIsDdCVKp9L9zg2C0bneO4wq7u4RI/MUEALp3Bz75BOjbF8jLY52GmLEWLVrA3d0dq1evZh1FMKRSKWJiYrBgwQLcvHmTdRyTK+x2D6pr9O1mGjdujNOnT+Pp06dGu0dJmUcxAfK7uipWBMaNY52EmLmePXsiNzdX0P3XpiaXy/Htt98iNjZWNCu2DalgLY4p9i0T6lRh8ykmEgmwciWQkAAsXsw6DTFzo0ePxokTJ3DixAnWUQTD2toa3377LaZNm0ZTqY2odu3auH//PjIzM1lHeY75FBMAsLcHtm4FwsKAQ4dYpyFmbsqUKVi/fj1SU1NZRxGMMmXKICYmBlOnThXcl505EeI2K+ZVTACgVi1gxQoakCdGx3Ecpk+fjnnz5uHhw4es4wiGg4MDpk2bhpCQEGRnZ7OOY5bc3NzAcRzuCOg7zvyKCQB07Qp89hnQpw8NyBOjksvlhUev5uTksI4jGE5OTpg6dSomT54syMFicyC01ol5FhMAmDIFqFwZGDsWoHUBxIjs7e0RHh6OkJAQaLVa1nEEo0KFCggODsakSZOg0WhYxzE7Dg4OqFSpEpKTk1lHAWDOxYTj8ru7Dh8GfvqJdRpi5ipWrIhPP/0UERERtKjxGVWrVsW4ceMwefJk2j3ACEaNGoWlS5eyjgHAnIsJANjZ5Q/IR0Tkz/IixIjq1KmDoKAgzJkzh3UUQalZsyZGjhyJ0NBQwa7eFisrKyv4+fnhsAB2ADHvYgIAnp75U4b79wdu3WKdhpi5pk2bonbt2li5ciXrKIJSt25dDBw4EFFRUdRyM7CBAwdi7dq1zH+v5l9MAKBz5/zFjH36ADQYSIwsKCgIOp0OO3fuZB1FUBo0aIAuXbpgxowZzL/4zIlEIkG3bt2wY8cOtjmY3t2UJk0CqlfPn+VFb2RiZCNGjMDZs2eRmJjIOoqgNG3aFC1atMDcuXNZRzErHTp0wN69e5mOS1lOMeG4/A0hExOB779nnYZYgODgYGzevBlXr15lHUVQ2rRpAy8vL3xPn0OD4TgO77//PtM94yynmAD5A/JbtgDR0cDff7NOQ8wcx3GIjo7Gd999hwcPHrCOIyhdunSBm5sb4n5ahXWJN+jobQPw9/fHuXPnmB3iZlnFBABq1gRWrQIGDgQscIdTYlpyuRwzZsxAVFQUVCr6wnxW/cAOWHzdCeFbz6L7wgQqKAbw8ccfYzGjvQktr5gAQKdOwBdf0IA8MQk7OztEREQgJCSEFu89IzEtA1KZDGo9wPO80Q6VsiSenp5IT0/Ho0ePTH5vyywmABAcDNSokX8OCg3IEyNzdXXFuHHjMHXqVJrJ9J8AdydwHGAlBbRandEOlbI0Y8eOZbLNiuUWk4IB+VOngIULWachFsDT0xO9evXCrFmzkKpUWfxYQcGhUtE96qGd5hiqlFWwjmQWXF1dIZfL8e/ZqyZ9j3HFeUry9/fnjx8/bsQ4DKSmAs2aAevXA61bs05DLMDPG3cg5qQeMpkcHAejn84nBufPn8ehQ4cwevRo1lHMwtm0++j101HI5YpSv8c4jjvB87z/237OclsmBTw8gNWr8wfkb9xgnYZYgDLV6wEAcjU68DxorACAt7c3TqXcwS+HUiy6tWYoF5R54GHa9xgVEwDo0AGYOBHo3RtgNK2OWI4AdyfIZDJIoQPHgcYKAKQqVdgvD0D07xdoZpcB1LDTgwNgI5ea7D1GxaTAV1/lH6z18cc0IE+MysPFDjs+bwl/7hq2fNzE4ru4gPwnZ46TQMNLqLVmAH9uWo0NIxshMqiuybpRqZgU4Dhg2TIgKQn47jvWaYiZ83Cxw4T3muD8kQOsowhCwcwuaq2V3qNHj8DzPBp6VsaAgGome1ihYvIsW9v8FfIxMcAB+pAT42rSpAmOHj3KOoYgFMzsaiK9ThMSSmnJkiUYNWqUye9LxeRFNWrkD8gPHgxcv846DTFjHMehUqVKuEVHIwDILyi1ZelUSEpBpVIhKysLbm5uJr83FZNXad8+fwylVy+AzvUmRjR48GDEx8ezjkHMxPLlyzFixAgm96Zi8joTJwJeXsBHH9GAPDEaFxcXpKen0wmEpNTy8vJw584d1KhRg8n9qZi8DscBS5YA588D8+axTkPM2LvvvouDBw+yjkFEbtWqVRg6dCiz+1MxeZOCAfmZM4H9+1mnIWaqQ4cO2LNnD+sYRMS0Wi0uX76MunXrMstAxeRt3N2B+Pj8Afm0NNZpiBmSSqWwt7dnstOr0MhkMtpZuQTWr1+PAQMGMM1AxaQo2rbNP/aXBuSJkQwePBhr1qxhHYM5e3t7OvelmPR6PU6ePAl//7dun2VUVEyKavx4wMcHGDWKBuSJwbm7uyMtLc3it6e3s7NDVlYW6xiisn37dgQFBbGOQcWkyDgOWLwYuHQJmDOHdRpSBGLb5t3Pzw8nT55kHYMpapkUD8/z+Ouvv9CqVSvWUaiYFIuNTf6AfFwcsHcv6zTkDVKVKnRbkICI386LZuPAnj17YuvWraxjMEUtk+LZv38/2rVrB47jWEehYlJs1aoBa9YAQ4YA166xTkNeIzEtAzq9Dk+1etFsHGhtbQ2O45BrwTtX29nZUcukGHbs2IGuXbuyjgGAiknJtGkDhIQAPXsC2dms05BXCHB3Aq/Xw1rGiWrjwL59+2LTpk2sYzBjb29PLZMiOnLkCJo0aSKIVglAxaTkxo0DGjQARo6kAXkB8nCxQzfZOUQEeYtq40BfX18kJSWxjsEMtUyKbuPGjejbty/rGIWomJQUxwE//ghcvZo/hkIExwG5GNS4umgKSYGaNWvi6tWrrGMwQS2ToklKSoK3tzekUinrKIWomJRGwYD8nDnAn3+yTkNeINZptgMHDsTatWtZx2CCWiZF8+uvv2LIkCGsYzyHiklpVa0KrF0LDB0KpKSwTkP+k5eXB4VCwTpGiZQtWxbZ2dnQarWso5icra0tsmkc8o2uXr2KatWqCe79TcXEEFq3BsLC8lfI0wdBEFJSUlCrVi3WMUqsS5cuWLn5D1GtkzEEiUQi2halqSxfvhzDhw9nHeMlVEwMZexYoFEjYMQIGpAXgOTkZLzzzjusY5SYs4c3ZpzUI3L7BdGskyHGd+vWLTg5OcHW1pZ1lJdQMTEUjgN++CF/7UlsLOs0Fu/SpUuoXbs26xjFplarsWTJEkQsXAUAyNXoRLNOhhjf0qVLmRzJWxQy1gHMirU1sHkz0LgxUL8+0Lkz60QWKzc3V5BPb6+j1WoRHx+Pc+fOYdiwYWjXszq6zP8LUp4X1ToZYjxKpRIKhQJly5ZlHeWVqGViaFWqAOvWAcOG5U8bJuQN9Ho91q1bh0mTJsHHxwexsbHw9vaGh4sddoxrBT8+VVTrZIjxLFmyRLCtEoBaJsbRsiUwdWr+CvkjRwA7+iIwJTEM4PI8j+3bt+PAgQPo16/fK8+i8HS1R03uPtzLi6eFRYzjzLV7OJdjDxVnC1fWYV6DWibGMmYM0LgxUkePs7gZOazdu3cPbm5urGO8Es/z+PPPPzFhwgTY2dlh7ty5aN68+Wt/vlGjRha/k7ClS1Wq0HdxIk5yNQU9GYOKibFwHFKnxaF71SCEbz6DbguE+yYwN0KdyfXPP/9gwoQJ0Gg0mDt3Ltq2bfvW13To0AHrdx2kBxILFrdqKziJBE+1vKAnY1A3lxEl3lGBt7aGWqOHVKPGN4vXYdanveDkRIOpxpScnIwePXqwjoFUpQqJaRmwenILf/2+AYGBgZgzZw4kkqI/wymfctisqo3t28+D4zgaP7Ew69atg5ezHAefSCHlIejJGFRMjCjA3Qkcx8FGLgXHSTG657v48ccfkZubiyFDhgjy6dkc3L17l3k3V6pSha7f/Q2NRgupRIKdk6PgWcGh2NdJTMuAVCZFriZ/B+TEtAyzLyYcx4HnecHshsvKrl278PjxY3z+8cfo9t+DSYC7k2D//KmYGJGHix1+Hxv43JugqXcIcnJyEB8fj6VLl6JTp05o3769xX9wDI317zPh0j1oNBroOBkUMilO3HhcomIS4O4EqVQKGwkPjUaD8wd/g7r+R4LbSsOQbG1tkZOTgzJlyrCOwkSqUoU1+xKRfS0ZM6aMB5D/XSLUIlKAiomRvepNYGtri1GjRhUOxgYHB+Odd97B4MGDYWNjwygpMaSTu9dDIW8IcKU7T+XFBxLtozsIDg5Gr1690Lp1awOnFoaCo3stsZikKlXovjABeXlqWFm9g1FKleCLSAEqJgxxHIdOnTqhU6dOuHDhAmbMmAFbW1t8+OGHzLtpxConJ4d5Qd69ezda+NbCuDYtDdI18dwDiUttzJ07F+vWrcPkyZMxceJEuLoKdbJoyRQc3VuhQgXWUUwuMS0DPA/oOCm0Wp2oujWpmAhE3bp1MW3aNKSnp2PFihV4+PAh+vXrBz8/P9bRROXy5ctMt1HJyMjAvn37EPvfljrG+CLgOA4DBw5Ely5dMGfOHFSrVg3Dhw8v1sC+kBW0TCxR/jgrYCOXQK1W453yctaRisw83n1mpHz58vjyyy8RHR2N5ORkfPXVV9iyZQt0Oh3raKJw6dIlphMbYmJiMGXKFJPcq2zZsoiKikL9+vXxxRdf4MyZMya5r7EVtEwsUUG3ZmSQNzaMbITVP8wRxSJcgIqJYMnlcgwePBizZs2Cq6srQkJCsGDBAjx58oR1NEG7cuUKPD09mdx77dq16NSpExwdHU16X39/f8ybNw9HjhxBVFSU6L+ILbllAuQXlAEB1eBXqwo6deqENWvWsI5UJFRMBI7jOLRo0QIzZ85EUFAQ5s2bh8jISKSmprKOJkhqtRpWVlYmv++tW7eQnJyM9u3bm/zeACCVSvHxxx/jo48+wrRp07Bp0ybRPNG+yJJbJi9q3749UlJScO3aNdZR3oqKiYi4u7tj6tSp+PLLL7Fr1y4EBwfj77//Rooyi1ZIM6TX6xEbG4vg4GDWUeDm5obY2FiULVsWEyZMEOVDh6W3TF4UHByM2bNnC/7kTRqAFyF7e3uMGTMGOp0OyzfuwPCd+yGVySCTSi16hbRer2eyvmTJkiUYOnSooLa8b9++PQIDA7FgwQJIJBKMHTuWSYutJKhl8jwrKyt8+umnmD9/Pr788kvWcV6LWiYiJpVKYV3VBwCg1kHQ+/aYwuFzKXhYtrZJW2iXLl1CZmYmAgICTHbPorK2tsbXX3+NHj16YNKkSThw4ADrSEViZ2dHLZMXeHt7w87ODkePHmUd5bWomIhYXl4e9q9bDLlc8d+WLcLdt8fYUpUqjFh3GXsyyplsZ1WNRoMFCxZgwoQJRr9XaXh6emLu3LlQKpWYNGkS7t+/zzrSGykUCmg0GtYxBOejjz5CfHy8YFtt1M0lUmq1GpMmTULExAnQ2ZYX/L49xpaYlgEe+S008Fr8e/kePFyMO6tr3rx5GDt2LORy4a8F4DgO/fv3R+fOnTFnzhxUrlwZI0eONJu1KZaA4ziEhIRgxowZiImJYR3nJfROEiGNRoPJkydj3LhxqF69euFUQkstJEB+i0wmk8JGLgHHcTizdzNCQkKwZMkS3L171+D3S0xMhL29veg263RwcEBkZCQaNWqEL774AqdOnWId6ZXEOhPN2CpUqIDAwEBs2rSJdZSXUMtEZLRaLSZPnowxY8bAw8ODdRzBeHlTzW4AgNTUVGzcuBF3796Fg4MDunTpAl9f31IN1Ofk5OCXX37BvHnzDBXf5Pz8/FC/fn0sW7YM27Ztw8SJE+HgUPyNKInpdevWDeHh4WjSpAmqVKnCOk4hrjhPAP7+/vzx48eNGIe8iU6nw5QpUzBixAjRPRELwePHj7Fr1y4kJSVBKpWiZcuWaN26dbFnOUVERGD06NGC+iCXxr179zB37lz4+/ujb9++zHdcBoDxU2PQLGiIRXfdvklOTg4+mxyFju+PQZMa5Y36O+I47gTP8/5v/TkqJuKg1+sRGhqK999/H97e3qzjiJ5Go8G///6LgwcPIi8vD15eXujatSucnZ3f+Lo9e/bg4cOHGDRokImSms6+ffuwfft2fP7556hZsyazHKlKFTrO2Q+5XAGOg0VPd3+df5Ou4IP4C5BIJJDL5Ub9HRW1mFA3lwjwPI/w8HAMGjSIComByOVytGnTBm3atAHP80hOTsbKlSvx8OFDODs7o1u3bqhTp07hU3qqUoWDF27h6O6/8eOsaMbpjaNdu3aFa1N4nse4ceNMsjaF53ncuXMHJ0+eRFJSEs7m2EOvr45cjQ42cqmods41ptu3b2Pz5s24c+cOHjl6QS53wVOtHrL/lgSw/h2JtpikiuDkMUPgeR4RERHo06cPfH19WccxSxzHwcvLC15eXgAApVKJnTt3YuXKlbCysoJX49aIOpKHPLUaCtvmuPYw22zfc1ZWVvjqq6+QkpKCSZMmISgoCO3atTPY9XmeR1paGk6ePInz588XruquXLky/Pz80L59e9xV6dBtQQLU6jwAUoud7g4A9+/fx6ZNm3Dz5k1UqlQJvXv3RuXKlZGqVOHvhQmQQgeOE8bvSJTdXAUHyBQc7WmuzWCe5xEdHY2uXbsKclGcJXj69Cm+WbMfvyZroJfIYCOXIjKoLgYEVGMdzeh4nsemTZtw7NgxTJw4ERUrVizW6/V6Pa5cuYKTJ0/i0qVL0Ov1AIAaNWrAz88PXl5erz0xMlWpwp+nUpC0bwsWfRshiHEcU1EqldiyZQtSU1NRoUIF9O7dG9WrV3/p51KVKoR/txKRn72PWhXLGi2PWXdz5R8gwyNXozfbZjDP85gxYwY6duxIhYQha2trDO/eCuuu/gWOg0UtDOU4Dn379kXHjh0xd+5cVKxYEaNGjcL1jNyXegW0Wi0uXryIkydPIiUlBTzPQyKRoFatWvDz80P//v0hlUqLfG8PFzt80rE+DtllY9GiRRg7dqyx/jMFISMjA1u2bMGVK1fg7OyM3r17v3W2poeLHbrXdYIm4zZgxGJSVKIsJvkHyHCCauIZWmxsLFq1aoVmzZqxjmLxPFzsEOyrQ4bMCX1bNTC7B5e3cXBwQEREBE6dOoVRE0JwyKEVgPyWR1dJEhy4p5DJZPDy8kKLFi0wdOhQgy2GbN68Oa5cuYI///wTHTt2NMg1WXmxaz4zMxNbt27FxYsX4eTkhJ49e2LkyJHFumb9+vWRlJSEunXrGil10YmymBSsKQj7bgWmj/3Q7D7cs2fPRuPGjdGyZUvWUch/yknVaFK7rNm914qjYcOG6Khxwt+bT0PHyWAtk6LZe0Mx0MhdfsOGDUNERAQ8PDyYnVVTWs92zeu0OrTXHUfVclbo0aMHhg0bVuLr1q5dGxs2bDBg0pITZTEB8gtKbelDs/twz58/H76+vnj33XdZRyHP0Gg0r+3ftyRNapSHTCaDlOchkUjR2ES9AmFhYZg4cSK++eYbQS6uVKlUuHfv3nN/PXz4sHAl/xWdM/J01aGDFFZSCVr1GmGQIiyTyQSzNb1oi4k5WrRoEWrXro0OHTqwjkJeoFarRbEHl7F5uNhhx7hWCJu3HDPGjjDZw5xcLkdERAQiIiIwe/Zsk+wpplarcf/+/ecKxP3796HRaAonBBQUCzs7O1SsWBEVK1ZEnTp10Lp1a5QvX74w5/9bJvnjboYswkKZnEDFRCB++uknVKtWDV26dGEdhbwCtUz+z9PVHjW5+6jhXMak93V2dsbw4cMxa9YsTJo0qUTX0Ov1SE9Pf6kVkZWV9dKXskKhQIUKFVCxYkW4ubmhYcOGcHV1LdH74OXtfgxXhB0dHZGRkQEnJ7Zjx1RMBGDZsmVwdXVFUFAQ6yjkNahl8rz69evjzJkzaNCggUnv6+vri6tXr+KH1ZvgVCcAAe5OqOFcBllZWS+1ItLT0196PcdxcHZ2LmxFNGvWDBUrVoSdnfFbWB4udkZpyRUMwrdp08bg1y4OKiaMrVy5Eg4ODujVqxfrKOQNqGXyvI4dO2Lx4sUmLyYA0KBlR3SaewD686fBAeguP4+qZRWFBaJu3bpo27YtHB0dLWKL/Xr16iE+Pp6KiSUqmCJ47+y/cLVRoF+/fqwjkbeglsnzypUrh8zMTCb3TkzLgEwmL9xupVnQEItYRPo6Li4uePjwIesYVExMrWAgTqPRArDH7gltWEciRUAtk5c5OjoiPT0d5cuXN+l989eZweJPF32WEAbhzb8NKDCJaRnQaDTQ8BxkMplFn9kuJtQyeVmnTp3w559/mvy+BYPZkUF1zXYrpeKSSqXMpwhTMTEhvV6P47vWg+Mk9FQlMgX7wJH/8/HxwdmzZ5ncm04XfV6tWrVw9epVphmom8tEcnJyEBYWhmHDhuHTSjUtYsdjc/KEt8a6xBv0Z/YMjuMgkUig0+mKte8WMTxfX1+cOXOG6aF5VExM4O7du5g+fTrCwsLg5uYGAPSFJCKpShW2a7yxa/sFOqzpBU2aNEFiYiKaNm3KOopFq1OnDjZv3sw0A3VzGVlSUhJmzZqFWbNmFRYSIi7H0jLA80CuRgf+v4OISL62bdti3759rGNYPLlcDo1GwzSDqFsmBYNOMpkw/zN27tyJ06dPIy5o0+rRAAAgAElEQVQuziLmu5srze2LkEqlUEhpnOtFZcqUQXZ2NusYRACE+S1cRLa2tsjNzYW9vT3rKC/56aefYG1tjZCQENZRSCmd/udP/DE5EsfTHtGYySu4ubnh7t271PJmzNHREY8ePYKjoyOT+4v6cdnGxga5ubmsYzxHq9Vi6tSpqF27dqm2libCcOzYMQQEBKCmiz3NHnqNLl264I8//mAdw+L5+voiKSmJ2f1FXUxsbW2Rk5PDOkahJ0+eYOLEiRgyZAhtIW8mNmzYgL59+7KOIWienp5ISUlhHcPiFezRxYqou7mE1DK5ceMGYmNjERkZCWdnZ9ZxiAFcunQJnp6egh2TExK5XA61Wk27BDDk4uKCBw8eMLu/qD8lrFsmBXtsWT25hUO7t2L27NmwsrJilocY1qpVqxAWFsY6higEBgbi33//pRa5BRN1MWHZMinYY0ur1UKv57H763AqJGbk9u3bcHJygo2NDesootCyZUt8++23VEwYk0qlzBaRinrMhGUx+evibajVaqj1HORyOY6nPWKSgxjHzz//jJEjR7KOIRpWVlbIy8tjHcPieXp6MttWRdTFhEU3l06nw88//4wTf6yDXC6nPbbM0KNHj8DzPMqVK8c6iqjUqFED165dYx3DorEchKdurmJISEjA+vXrMWzYMIwYMaJwzITWHpiXZcuWYdSoUaxjiE6XLl2wbds2fPbZZ6yjWKw6depgy5YtTO4t6mJiqpbJzZs3sWDBAjRs2BDz588v3D3WWMdwEnYu3EpHYoYcveUOrKOITpUqVXDnzh3WMSyaQqFgtq2KqIvJg6fA0YdStFGqjPKlnpubi0WLFkGr1SIiIgJlypQx+D2IcKQqVejx/SFIJLXQfWECbehYAtbW1sjJyYGtrS3rKBaL1VEJoh0zSVWqMHT1eezNcETX+X/j6v0nBrs2z/PYuHEjwsPD0adPH0yePJkKiQVYt/8EeB7I0/G0oWMJvfvuuzh48CDrGBatbNmyePz4scnvK9pikv9B56DjpNDxekxdsBLh4eGYMWMG9u7di6ysrBJdNykpCePHj4eTkxPi4uJQo0YNwwYngnTlyhXcOn0QCgVNqiiNpk2b4vDhw6xjWDRfX18mh5aJtpvrxXOgp48dDg8XO2RnZ+PYsWNYtGgRVCoVOI6Dt7c3WrRogapVq772eunp6Zg3bx6qVq2K2bNn06pnC3L//n0sWLAA82bPxs3HeTSpohRkMhl0Oh2dTMmQr68vNmzYgJYtW5r0vqL9xiw4B/rFD36ZMmXw7rvvFi6e0uv1OH/+PHbs2IFbt24ByN/ltEWLFrBz88CxtAxcO7oH6vRbmDBhApyc6GnUkqhUKkRFRSE2NhZyuRweLnIqIqVUt25dJCcnw8vLi3UUi1ShQgUm26qItpgARZtNJZFIUK9ePdSrV6/wn925cwfb9h/G7HU3oNfzUCgqY+e4QXByoi8RS6LRaBASEoLIyEjY2dGfvaF06tQJq1evpmLCEM/zJr+naMdMSqNSpUpwqhMAuVwBvURGg60WiOd5TJ06FePGjYOrqyvrOGbFxcUFDx8+ZB3DokkkEuh0OtPe06R3E5D/j7lIoNNpabDVwsyaNQu9evWCp6cn6yhmyd7eHpmZmaxjWCxPT0+kpqaa9J4WW0wKxlwig7wx1OU2OJWSdSRiIj///DN8fHzQuHFj1lHMVocOHbB3717WMSyWr68vzpw5Y9J7WmwxAfILyoCAavjyo6H4+eefWcchJrB9+3ZIJBJ07dqVdRSz1rBhQ5w6dYp1DIvl5eWFixcvmvSeFl1MCtjZ2cHBwYG2gjBzR44cQXJyMj788EPWUcyeRJL/1aLX6xknsUwKhQJqtdqk96Ri8p9Ro0Zh6dKlrGMQI7l8+TJ+++03fPXVV6yjWIwqXn6I23IIqUoV6ygW6QlvjXWJN0z2+6di8h9HR0dIpVKahWJCqUqVSd7s9+/fx6JFixAdHU0L6UwkVanCvGQbLDnxCN0XJlBBMbFUpQo7dPUQuf28yX7/VEyeMXr0aCxZsoR1DItQcFJl5PYLRn2zZ2VlITo6GjNmzKBdDUwoMS0DWq0WGl5CU+8ZSEzLAM/zyNXoTfb7p2LyDFdXV+Tl5dGURhP4/5tdZ7Q3u0ajQWhoKCIjI2mjThOr51YGAE/7nDGiuZsMqVRq0t8/Paq9YNSoUVi2bBkmTpzIOopZy1/nw0HO8UZZ58PzPMLCwvDFF1/AxcXFoNcmb3fwt3VY0qc1HvD2tM+Ziel0OiTu24E/wqbjeNojk/3+qZi8oEqVKkhPT6czGYzs2b3Vzh7YiofXXOHhYrh1H7GxsejXrx9q1qxpsGuSolGr1bhx4wbGjPFmHcUirVixAsOHD0dNF3vUdLE32X2pm+sVhg8fjuXLl7OOYfYK1vlM+/pzbNq0CWlpaQa57rJly+Dr6wt/f3+DXI8Uzy+//IL333+fdQyL9OTJE6SkpKBBgwYmvzcVk1fw9PTEjRs3TD5P21JxHIdp06YhLi6u1If6/Pbbb5DL5ejSpYuB0pHi0Gq1SE5Oho+PD+soFmnBggX4/PPPmdybislrDB06FL/88gvrGBZDoVAgOjoa4eHhJT7D+vDhw7hy5Qo++OADA6cjRbVu3ToMHDiQdQyLdO3aNVhbW8PNzY3J/amYvIaPjw+Sk5Oh1WpLfA1TraMwF05OThg/fjymTp1a7C20L126hN9//50mTjCk1+tx6tQpNGrUiHUUi/T9999jzJgxzO5PA/Bv0L9/f3z/y0ZU8GlepBkRGo0Gd+/exe3bt3E65Q7mXFCAByCVSLD5o8bwrkazit6mZs2aCAoKwvz58zF+/PgivebevXv44YcfEBcXR4sSGdqyZQt69erFOoZFSkhIQKNGjWBjY8MsAxWTNyjv7oX5m+5Ace08AGBupwpA1gPcuXMHd+/ehUajee4JWi6Xw83NDZUrV0aOXSVIpY/xVKuHhAdm/rwJ1bS3YGVlhSZNmqB58+Z0INNrNG/eHLdv38aGDRvQr1+/N/5sVlYWpk2bhlmzZtGiRIZ4nse///6LOXPmsI5icfR6PTZs2IB58+YxzUGfvjdITMuAVCpFrkYPGfTYl5SGXvUrwsvLC25ublAoFK99bW2lCstOJRQuGor87H14uNjh6dOnOHbsGBYsWICcnBzI5XI0adIk/xhhKi6F+vXrh7lz5+Lw4cNo1qzZK39GrVYjJCQEUVFRNI2bsT/++IN2YmYkPj4egwYNYt4qp2LyBvkL6yRQSPSQyeT4tO+7RV7887oz6q2trdGqVSu0atUKAJCXl4djx45h4cKFUKlUUCgUCAgIQGBgIJRPuZdeb0nGjx+PkJAQVKhQAR4eHs/9O57nER4ejgkTJsDZ2ZlRQgLk/1ns3bsXs2fPZh3F4py/ocTWsw8Q26kn6yjgijPQ6e/vzx8/ftyIcYQn4cxlrNt/HBPef88kX+h5eXlITEzEjr8Tsf5JTchkMkilEvw+NtAiC4pGo8GECRMwbdo0ODo6Fv7zmJgYdOzYkQZ7BWD//v3Izs5GUFAQ6ygWJVWpQsc5ByCTSSGRGO87guO4EzzPv3XRFs3megu/WlVQRX3TZF/kVlZWCAwMRIMOfaBQyJGn4y16ozy5XI7p06cjPDwcl+48wrrEG/h20c/w8/OjQiIQO3bsQPfu3VnHsDhr9x0HxwFPtcL4jqBurrewtbVFTk6Oye9bsHeVjNOD5zmL3iivXLly6D9yLLp+9w+kUgnAu2JX/xasYxHkr+1p2rQp8/56S/PgwQOkJe6F3C4QMh6C2EyTiolAFYy5/HXxNs7t3woPF8se3LyrtYVMJkWeDrCRS5GYlmGR3X5Cs2nTJsycOZN1DIui1WoRHR2N2TExghpXpWIiYB4udvBwqYOpe7ORnZ1t0duoB7g75W+pLRHGUxgBTp06BV9fX0ilUtZRLEpsbCw+++wz2Nvbw94ezItIARozEYH3338fq1evZh2DqYKWWmRQXYudjFAcpth9Yc2aNRg0aJDRrk9etm3bNtSuXRteXl6so7yEWiYiULt2bSxevBg8z1t033R+S42KyNsUnGKp0WgKZ/nUqljWoPe4cOECatWqBblcbtDrkte7cuUKTp8+jYiICNZRXolaJkUghC/wDh06YM+ePaxjEBHIP8UShUfmhi9YidDQUOzatavEm2i+aNWqVbShpgllZ2dj3rx5CAkJYR3ltaiYFIFCoUBeXh7TDB07dqRiQookfyZg/kQFmUyKGeNHIDo6GtbW1pg2bRpCQkKwY8eOEr+nU1JSUKVKFVhZWRk4OXkVnucRFRWFsLAwQbcEqZurCJydnfHw4UNUrlyZWQaO4+Dp6YnLly+jdu3azHIQ4Xvd7gtt2rRBmzZtoNfrcejQIcyYMQMajQZNmzZFx44dYW1tDSC/m+xNM4SWL1+OKVOmmPS/yZItW7YM3bt3Z7a1fFFRMSkCFxcXKJVKpsUEyB+InzlzJqKjo5nmIML3pvEliUSCwMBABAYGQq/X49ixY5g5cyby8vJQzScA85OtAXDgODw32SFVqcLukyngHCpY9MxCUzp69Chyc3MLt18SMiomRVDQMmGtTJkykMlkyMzMRNmyhh1QJZZJIpGgadOmaNq0KXieR+zGBKg1j6CDFFLo8O2yjejXqDJsK7hj9KYU5KnVUMg9MVyposkQRqZUKrFu3TrR7HlGYyZFUNAyEYIPPvgAq1atYh2DmCGO49CvTUNYKRSQQgcrhQKje7WFtbU14vceQ55aDR2kADjmW3eYO51Oh+joaERGRgpiAlBRUDEpAqG0TADA3d0dN2/ehE6nYx2FmKGC8ZYASVr+/9aphpYtW+LLoT1gpVAUHqlAi0aNKzY2Fp988gkcHBxYRyky6uYqAkdHR2RkCOdJrFu3btixYwfee+891lGIGfJwsYO3dSYqO8if+2evGtQnhvf777/Dw8MD3t7erKMUC7VMikAqlUKv17OOUahVq1b466+/WMcgZszPzw8nT5587p95uNhhQEA1KiRGlJKSgsTERAwYMIB1lGKjYiJCHMfBx8cH586dYx2FmKmmTZviyJEjrGNYlJycHMyZMwehoaGso5QIFRORGjRoENauXcs6BjFT5cuXR1p6jtH39yL5eJ5HdHQ0QkJC3ngcuJBRMSkioc2osLa2hq2tLdLT01lHIWYoVanCDl09RG6/gO4LE6igGNny5cvRqVMn5mvZSoOKiYgNGzYMK1euZB2DmJmHDx9i0uwlkEgkyNXoBHGKnzlLTExEVlYW3n33XdZRSoWKSRFxHCeoQXgAqFy5Mu7fvw+tVss6CjEDPM/j119/xdy5cxE6egBkMhlNBTayhw8fIj4+HuPGjWMdpdRoanARlStXDpmZmXB0dGQd5Tm9evXCli1b0K9fP9ZRiIilpqZi/vz56NOnD4YMGQIA+H2sA00FNiKdToeoqChMnz5dcN3oJUHFpIicnZ2hVCoFV0yaNm2KjRs3lrqYvG1zP2KetFotvv/+e+Tm5mLmzJmFmz0CdH6MscXFxeGjjz4ym62RqJgUkYuLCx4+fCjIHXv9/Pxw4sQJNGrUqESvLzhMqeDwLTrJUBxK+wBw4sQJrFixAp988onoFsiJ3c6dO1G1alXUq1ePdRSDoTGTIipomQhR3759sXHjxhK/fv/ZG8jLUyNXo6fBVpEoeAAI23IGXb/7p1izrbKzsxEdHY2TJ09i/vz5VEhM7Nq1azh8+DAGDx7MOopBUTEpooKWiRApFAo4Ojri/v37xXodz/NYu3YtkvZthkIhp8FWEXn2NEWtVoPpP63B06dP3/q6Xbt2YerUqRg5ciRGjx4NiYS+AkwpNzcXcXFxCAsLYx3F4OidVERZnC3+vq0V7Hz7Dz/8ECtWrCjyz9+5cwcTJ06Eq6srvvsmDDs+b4nIoLrUxSUSz56mqFAoMKxrIMLCwrB582bwPP/Szz948ADBwcF4+vQpZs+eLer1DGIWHR2NyZMnm+UplTRmUgSpShV6/3QUWq0bui9MEOQXrqurKzIzM5GXl/fGNyrP81i5ciWuX7+O6dOnFx5yRIOt4vKqjRdb+8Vh3759GD9+PEaNGoUyFWvgWFoG7pz+G49vXkZoaKjZDPaK0YoVK9C+fXtUrVqVdRSjoGLyFikpKQhZuh1a1IQWUsj/G1MQ4hdv//79sX79egwdOvSV//769euYM2cOBgwYgA8//NC04YjBveoBoF27dmjdujVif1iBn29fAw8eMpkj/vgiGGXLCu89aylOnDiBjIwMs/7cUTfXa1y6dAmTJ0/Gzp07ETHmfVGMKTRo0ACnT59+qZtDr9dj8eLF+PXXXzFz5kw0b96cUUJiCjKZDDWbdoRUJoOOk0EikdKkCoYyMjKwatUqjB8/nnUUo6KWyQvOnz+PVatWwd3dHREREbCxsQEA0Zzl0Lx5cxw+fLiwYFy5cgULFizAsGHDSjx1mIhPgLsTpFIJpFo1AKlgH4DMnV6vR2RkJKKjo81+sgMVk/+cOXMGv/76K2rVqoXo6OiXxh3EMqbQo0cPjAudjuvSyrh86A/YarMQFxcn2p1ISckUjKlsTkgClCmieO+ao9mzZ2PkyJEoV64c6yhGZ/HF5MSJE1i7di28vb3xzTffQC6Xv/1FAnbj0VPskTbCrs2noVBUw85xraiQWCgPFzt81as5vvpqM/T6IWb/ZCw0u3btgpubG+rXr886iklYXDEpWDUsz7yJf//YjIYNGyImJgYymXn8KhLTMiCTyaHhdeA4iWAnCxDT6dmzJ7Zu3YrevXuzjmIx0tLS8M8//+Cbb75hHcVkzOMbtIhSlSp0W/AP1Go1pFIpdgZHwLOCA+tYBvXs+gMhTxYgphMYGIiJEyeiV69eZrGhoNA9ffoUs2bNwpw5c1hHMSmLavcmpmVArdFAx8kglcpw4sZj1pEMrqCvnBYgkme1a9cOBw4cYB3D7KUqVRgW9SMGfzzeLBcmvolFFZMGle3Bwfyf2j1c7DAgoBoVElKoa9eu2LlzJ+sYZi1VqULneQdxSlILozelCHa3DGOxqG6upH/3Iq59ZeQ5VBH8FF9CDInjOPj5+eH48ePw9/dnHccsJaZlQKfXQwcppAJe3GwsFtUySUxMRI+2zeipnVikgh0SiHE0qu5oET0fr2MxLZNr166hRo0aNABJLJZMJkPNmjVx6dIl1KlTh3UcsyNRKfFJjUxUbdjaIns+LKZlEh8fj0GDBrGOQQhTH3zwAVatWsU6hlk6ffo02jeuZ7E9HxZRTDQaDbKzsy1iFSohb2JjY4Py5cvj1q1brKOYnQsXLqBu3bqsYzBjEcVkx44d6N69O+sYhAjCyJEjsWzZMtYxzI5arbbo3SYsopgcOnQIzZo1Yx2DEEEoW7YsZDIZ0tPTWUchZsTsi8mNGzdQtWpVGngn5BnUOjGs9PR0ODlZ1uytF5l9MYmPj8eQIUNYxyBEUCpWrIisrCxkZ2ezjmIWzpw5gwYNGrCOwZRZFxOdTofHjx9b/BMDIa8yfPhwLF++nHUMs3D69GmL2R34dcy6mOzatQtdunRhHYMQQfLw8MCtW7egVqtZRxG9x48fw9HRkXUMpsy6mPz9999o1aoV6xiECNbgwYOxZs0a1jGIGRBUMUlVqrAu8UapN0hLVarw056zsHapRgPvhLyBr68vzp07B71ezzqKaD19+tTidgh+FcFsp5KqVKH7wgTwPA+Aw5aPG6OGcxkAKCwIRfnf1IcqBC38F2q1GnK5B4YpVRa5GpWQourRowe2bduGXr16sY4iShcuXIC3tzfrGMwJppgkpmVAo9FAw0sggw4xS9fjHcWj/4oLivy/l7TlkaetBh2kkMPydu4kpLgCAwPx5ZdfomfPntSSL4HTp0+jbdu2rGMwJ5hiEuDuBJ7n/9txU4qIMe+XqAgUtHA0Gi14nre4nTsJKYm2bdviwIED9KVYAmlpaahevTrrGMwJZszEw8UO3WXnSn1CYMFJg2Fd6yBIfp5aJYQUAR2eVTrUohNQMdHpdCgnVRtkx00PFzsMC6wFWW5GYfcXIeT1nj08ixQdTVz4P8EUk9TUVHh4eBj0mo0bN0ZiYqJBr0mIuerfvz82bNjAOoaopKWlGfx7S6wEU0zOnj0LX19fg16zS5cu1HQnpIhkMhk8PDxw6dIl1lFE4/Tp0xa/jUoBwRSTCxcuwMvLy6DXtLa2hlqtpqYoIUU0bNgwLFy53iDrvSyBpZ9h8izBFBO1Wm2UhT+BgYFISEgw+HUJMUd3srT4g2+AiN/Oo/vCBCoob2HpZ5g8SzDFxFjat2+PPXv2GOx6hlqlT4gQJaZlAACeavXg+f//PSFvI4h1JiqVCmXKlDHKtRUKBXieh1arhUxWuv/cC7fS0fvHo+AkHDiOK9UUZkKEKH9dVsF6L9A6rTegM0yeJ4hicv78efj4+Bjt+gULsjp06FCkn9doNLh69SrOnTuH5ORkaDQa8DyPNGkl6PmqUGs42MiltLqemJ0Kthx62V6Gf+f+CHB3ovf3G9AZJs8TRDFJSkpC586djXb91q1bY3z4DGSUq/PcB0Sv1yMtLQ3nzp3D+fPnkZOTA47jIJPJUKtWLfj4+OC9994rHMspWF0v5UFPbcQsHThwAL3bt0CzgGqsowje6dOnMXz4cNYxBEMQxeTmzZuoUqWK0a5/PSMXf/D1sXtrEvR6Ht1lZ+HAPQXHcahRowa8vb3Rrl27t3a1FayuT0zLoKc2E0lVquj3bUJHjx5FZGQk6xiiQGeYPE8QxYTneaNuR3Dwwi3o9Ty04GAtl6JZ0PsYUMInLw8XO/pSM5H/7ySd3xKkMSrj4nkeer0eUqmUdRQiQsxncxl7u5PHjx/j4IZlsLJSwEYuhYTjqHtKJBLT8rfDydXoaGaRCSQnJ+Odd95hHUMU6AyTlzFvmdy+fRtVq1Y1yrUzMzMRGhqK+dOn45FWTt0lIlNQ9GXQg+Ok9BBgZLt378bgwYNZxxAFOsPkZcyLSVJSksG3UUlVqvBP8h3sX78Uc6dNg6OjIxwBKiIi4+FihxUD38GKHQn4+sNe9OdnZEqlEq6urqxjiAKdYfIy5sXkn9OX8E6r7nA10ImIqUoVui34J39lquO7eKxTgJ5nxau8QofmFelBwNiMudbLHNEZJi9jOmaSqlRhQ1ZNfPtnisG2bijoZ9dxMgAc9bOLXHZ2Nn3JmcC+ffvQrl071jFEhc4weR7TYpKYlgG5XGHQAdYAdydIJBJIeR2tBTED5lBMxLAFz/Hjx+Hv7886hijQxrGvxrSbK8DdCRwHg27dULAWZO6v2/Fes+rUPSJyYi8mqUoVusz/CzwPyGRSQU5vpinBxUNnmLwa05ZJwRd/aY/qfdV1Y0YF4fDubQa5Hnk9Yz91i72YHLryAFqtDmo9kJenxszlm5CZmck61nNoZlLx0Bkmr8Z8AN5YiwDt7OygVqtpi2gjMsWiQrEXk5QjuyGXV4eCk4DjpBjSoQkWLlyI3Nxc9OnTBw0bNmQdEbt378YHH3zAOoZoXLhwAd27d2cdQ3CYFxNj6t69O37//Xf07t2bdRSzdCwtAxqNFhqegxQ6zF+zA+ODGsPd3d1gg5NiLiaPHj2CPvMedo4b+twap1YNQ5GXl4dNmzZhzZo18PHxQf/+/WFtbc0kZ3p6OpydnZncW4zoAfXVzLqYNGnSBJMmTaJiYgQZGRk4sG4JJNZNYSORguOkeK9pDezbtw9paWkAADc3N7Rs2RI+Pj6QSErWoyrmYrJo0SJ89tlncH1F69vKygqDBw/G4MGDcfbsWcyYMQMymQyDBw+Gp6enyTI+efIE9vb2JrsfMV9mXUw4jkPlypVx+/ZtVK5cmXUcs7Fnzx7s2bMH34ZOeXlngcb1Cn/u9u3bSEhIwIYNG8DzPMqWLYvmzZvD39+/yFtRiLWY3LhxA9bW1kVaBFivXj3Uq1cPWVlZiI+Px08//YTAwEB069at1GfwvM2+ffvQvn17o97DnJy8cgt3bNyRaqB1ceaEK87eWP7+/vzx48eNGMfwHjx4gFWrVuGrr75iHUX0cnNz8e2336Ju3boYMGBAsV//+PFjHDp0CMePHy88prlx48Zo1qwZHBwcXvmaiIgIREVFlTa6yU2ZMgVhYWElKoQ8z+PQoUP4/fff4ejoiKFDh8LNzc0IKYGwsDBER0eXuOVoSVKVKnSaezB/6YFUIsiZecbAcdwJnuffOm/crFsmAODq6gqlUgm9Xk8fmFI4ceIEVq5cieDg4BIfF1CuXDl07doVXbt2BZC/WV5iYiJ++OEHZGVlQSKRwNfXF4GBgahYsSIAIJO3xrrEG6LaU+3MmTPw8PAocYuK4zi0aNECLVq0gFKpxC+//IL79++jc+fOaNOmjcHGo3ieB8/z9LkoohU7EwDwyNPxsJGADsd7gdm3TABg586dsLW1RZs2bVhHER2tVovvvvsO1tbW+OSTT4z6xaPT6ZCUlIR//vkH9+/fxxPeGjv1vlAorES1Bf3EiRMRGxtr0C4qnU6H3bt346+//kK1atUwZMgQlCtXrlTXTEpKwoULFzBw4EADpTRfhw8fxrb9h/Gbuq7FHYlALZNndOzYEeHh4VRMiiklJQXz5s3Dp59+irp16xr9flKpFA0bNiycLrs28Qb2bj+PXI1ONMck79+/H61atTL4WIdUKi1s1aWlpWHRokXIzc1F79694efnV6Jr/vnnnxgxYoRBc5qjs2fPYufOnYiJjsZHD7Np9/HXsIhiIpPJYGdnh8ePH5f6ac4S8DyPFStW4O7du5g9ezazaZCN3Z3AcZxBd0gwJr1ej99++w1z58416n3c3d0RGhoKtVqNzZs3Y+3atfD29kb//v1hY2NT5Os8evQITk7C/p2ylpKSglWrVmHmzJngOI4Ox3sDi+jmAvLfFHv37r6P704AACAASURBVMXHH3/MOoqgPXjwADExMejTpw8CAwNZxxHVsb1r165FtWrV0Lx5c5Pf+9y5c9iwYQMkEgkGDx6MWrVqvfHnMzMz8eOPP2LSpEkmSiguqUoV9py+hmM74vHjrGjI5XLWkZihbq4X1KxZEz/99BPrGIK2fft2HDp0CFFRUa+dXWVqYnkSzMvLQ2JiIrPxBx8fH/j4+CArKwtr167FkiVL0KxZMwQFBb2yy23Pnj3o0KEDg6TC99wxFg6tcfNxHjxcLLeYFJVFTeOoV68ekpKSWMcQHJVKhdDQUOj1esTExAimkIjJ0qVLMXr0aNYxYG9vj9GjR2PmzJmoUKECwsPDERsbizt37jz3c7S/1OslpmVAo9H8d4wFHRddVBbTMgGAPn36YObMmQY/2VHMDh8+jHXr1mHy5MmF03FJ8WRmZuLu3buCOj+d4zg0b94czZs3h1KpxOrVq3Hv3j106tQJ1XwCcEXvgrT0HFG0+kytYGxOLGN1QmFRxcTW1haPtHKsPpyK5p6uFv1B0mg0mD17NlxcXDB37lw66KcUCrZNESoXFxdMmDABer0eq7bswug5+yGVeqL7wgSLmd5aHOWkagx0TEO9d3uKYqxOKCyqmKQqVdiFBtj1+wXIZJct9oN08eJFLFq0CF988cVbB2rJm92+fRsSicRoK9QNSSKRwKaaDxRnLiBXo4OUp4V3r/LXX3+hZ9vm8PevxjqKqFhMMTl+/Di+3fA3eGktaHiJRX6Q9Ho9Fi9eDJVKhXnz5hl93ydL8P3332Py5MmsYxSZMQ6kMzenTp3Ce++9xzqG6Jj1twnP89i/fz927twJf39/xEwYiR4/HIbsvxWs5vxBKphSW7GsNe5lPkU1Gw3WLJ6PoUOHIiAggHU8s3DhwgVUqVJFVLvuFhxIJ5bp1izodDo6dbIEzLKY6PV6bNu2DQkJCWjbti3i4uIKxwQs4YNUcGiVVqeHWsdDxvEAr8dvX09F3ap0boWhLFu2DDExMaxjFJtYpluzkHjpBh7Y1aRdgUvArIqJRqNBfHw8zp07hx49emD27Nkv/YwlfJAS0zKg+6+QADy0PAcbuQJn7+WgblXW6czD33//jaZNm9IhSWYkVanC4JVnwHEV8C9NTig2sygm2dnZWLFiBW7evIlBgwZh2LBhrCMxVdAvLgMPLThYySRm361nSjzPY9OmTZg3bx7rKMSAvt/4JwA51HpAotdb3JhqaYm6mDx69AhLly5FZmYmPvzwQ5OeUCdkHi52+KFHdWw7fB69OrXBvcynZt2tZ2qbNm1C7969aTq1Gfn1119RScZDLneGjOehVqtR25HGTYpDNMXk2T2arDVPsGzZMgDAqFGjRDEt09RqOJdBA/sctK799pP+SNFpNBocOnQIc+bMYR2FGMjy5cthY2ODiaMHoud/3zNezgosnj0d3377Lezs6CGsKERRTAoGlHU6PXQ6LQaUvYavxo6Fo6Mj62iCJZPJoNFoWMcwK6lKFeJWbkGPvkNZRyEGsnjxYpQvXx59+vQB8PyY6tSpUzFlyhTExcUV+ZhpSyaKvbkKBpTzdDzkcjl82/WiQvIWcrmciokBFWz+tzu9LCbsvo9UpYp1JFJKixYtQsWKFQsLyYtcXV3x1VdfISQkBDqdzsTpxEcUxSTA3Qm8Xg8rKQeO42gguQjkcjm0Wi3rGGYjMS0DWq0OOkjB87T5n9jNnTsXNWvWfOvixOrVq2PUqFGYOnUqinNchyUSRTHxcLFDD5tkhHd9h6brFRF1cxlWgLsTeF4PGznNjBMznucRGxsLX19fdO7cuUiv8fLyQs+ePUW5psiURDFmAgA2mid4v7kH6xiiQd1chuXhYoeukiS0CPqAZsaJFM/zmDFjBlq1aoWWLVsW67UBAQF48uQJFixYgM8//9xICcVNFC0TUnzUzWVYjx49QjVHawwIqEaFRIR4nkdUVBTatWtX7EJSoF27dqhatSpWrlxp4HTmgYqJmZJKpVRMDOjw4cNMjuMlpafX6xEeHo6goCA0bdq0VNfq2bMnOI7Dli1bDJTOfIiimOj1elogVkz0+zKsEydOoFGjRqxjkGLS6XQICQlBv379DPbn98EHH+D27dvYt2+fQa5nLkRRTO7evYtKlSqxjiEqqUoVLuucaQqrgeTl5dFaA5HRarWYPHkyPvjgA9SvX9+g1x47diyOHj2KxMREg15XzERRTK5fvw53d3fWMUSjYJHnMW11dF+YQAWllNRqNeRyOesYpBg0Gg2Cg4MxevRo1K1b1yj3mDJlCrZu3YqLFy8a5fpiI4pikpaWhurVq7OOIRqJaRnQ63loIaE1EQZw6tQp+Pn5sY5BiigvLw9ff/01xo4di9q1axvtPhzHITo6GkuXLsX169eNdh+xEEUxuX79OhWTYghwd4Jer4dCav6HgJnCv//+S4PvIpGbm4uvv/4aEydOhIeH8ZcSSKVSzJgxA3FxcXjw4IHR7ydkoigmubm5sLGxYR1DNDxc7NDPIQVTOnrSIk8DyMjIQPny5VnHIG+RnZ2N4OBgTJ48GdWqme78disrK8TExCAqKgqZmZkmu6/QiKKY0Myk4pNmP8TwVnWokJQSbaEhDllZWQgODkZYWBiTyTp2dnaYNm0aQkNDkZuba/L7C4Eoigl9oIsnVanCFb0LDbwbQEpKCp2TI3CPHz/G5MmTERUVhQoVKjDL4eTkhJCQEEyZMsUid58QfDGhNSbFc/VBFjrP+4tmchlIQkICWrRowToGeY2MjAyEhIRg+vTpcHZ2Zh0HlSpVwtixYzEudDrWHLtuUZ8/we/Ndf/+fVSsWJF1DMF79OgRVq1ahYQ7ekBWG/9r797jqqrz/Y+/1t6bu5dkxNLyLtZgiiLqQR17mJ4pL5DOsWMz6Uxl/UrL0jTvclEKBSVvWb981PxMZ/IyZ1QUnMmkOt7lqlk6QsSEmoAXQBDY7L3X7w+CUacShb3XXovP8/Hg8fCy9loflL3fa32vdsWM3S5bjzZWbm5us98G2l0VFxcTHR3NsmXLaNWqldbl1DO1vo/PvAaxb8cJPDw8SJ7+q2bxHnT7MJE5Jj/vxIkTbNu2DV9fXyZPnky4jz9j1x3E/MPWow+19dS6RN2TJ2P38/333/Pmm2+yfPlyt9sJMS3/CopiwoYZtaaGtVv2kvjKBMP/HLl9mOTn59OnTx+ty3ArNTU17Nixg7S0NPr06cPixYvx9vau//s9rwwlLf8KgfeY2Lg2npUrVxr+B9kZLl++jL+/DKt2N+fOnWP58uXEx8fj6+urdTn/ZkAXfxQFfDzMKIqZwYGtmTFjBtOmTePBBx/UujynUe6kczs0NFRNT093Yjn/bvny5bzyyiv4+fm59Lru6OLFi2zcuJGSkhLGjx/PwIEDb/uaI0eOkJ2dzdSpU11QobF8sG03hWpLnno0tFk0U+hBfn4+iYmJxMfH33QD5W7yfthLvm67AqvVyvr166mqquK1117T1VQHRVEyVFUNvd1xbv9kcv369WYdJKqqcuTIEZKSkggICOC5554jICCgwa8PCwsjMzOTo0ePNnrF1OYkr7icuCwVD49KNn99UObruIHc3FzeeecdVqxYgaenezff3riXPICnpyczZswgPz+fBQsW8Pjjj/PYY49pWGHTc/swaa4qKyv5+OOPOXPmDIMHDyY2NhaL5e7+u6ZNm8asWbMIDAyUyXe3uH79Orm5uZw9e5acnJz6OQI5jgAcjk5U1jjw8TDLQAaNnTlzhg0bNhAfH6/rddK6dOlCYmIiu3bt4o033mDmzJmGWcRWwsTN5OXlsXnzZux2OxMnTuS5555r9DkVRSEqKorIyEjefvttTCa3HxHepKxWK99++219YJSUlNT/na+vLz169KBnz56MHj26vg0+r7icUau/QFVlSRqtnTp1ik2bNhEfH4/ZbNa6nEZTFIVx48YxcuRIEhMTadeuHS+88ILuvze37jP5pvgai1f/P2Jfe1YXd4W3tpM2lMPhYN++fXz66ad07dqVSZMmOWWoY1ZWFp9//jkzZ85s8nNrzeFwUFBQwNmzZzl79iyFhYX1f+fh4UG3bt0IDAwkMDCQNm3aNOicuYVlLFz9R+JmTtHFz58RZWVlsX37dmJjYw17E5Sdnc0HH3zAM88845Z75jS0z8RtwySvuJwxaw9gs9nw8PBw+zbrumXf6+5kG1JvaWkpmzZt4rvvvuPXv/41I0aMcPqoqw8//BC/+7pCQHdd7GV+Y0B3betHYWEhOTk5nD17loKCAhwOBwAmk4mOHTvSs2dPevbsSbt27Zrk3zIyMpJFixa5fRu9EaWlpbF7926io6MNGyR1HA4HH374IQUFBbz++uu0bt1a65Lq6b4Dvm7Z9BrVhOWHZdTd+YNva2oG1VYrdsx4KCoH/vE93QICf/TYU6dOsXXrVry8vJg0aZJL59E8Ev4kj7/9OQ41G4vJzI6XBhHUUfuZw7eqqKhgV+oRoo5U4lBVFGCs5RQ9299DYGAgI0eOpGPHjk7/kBk5ciT79+9n1KhRTr2OuNmhQ4fYv38/MTExzWJYu8lk4vnnn6ewsJC4uDhCQkJ48skndfW9u22Y1I7VVvA01e6Y5s5t1ikpKVzLO4uX50Ooqoqqqny5fwfz9lwhLCyMB0N/Rea5MspyM8nNOszDDz/MggULNBkemJ5/FYvFg8oaO2Yg7oPtdKo5R4sWLRg2bBgDBw7UpIOzqKiIQ4cOkZ2djd1ux9fXF2vHUCwWS30neFj4JCYOcN1qsABDhgwhMjJSwsQF6p5C1aJcvj15jMWLF+vqw7Qp3HvvvSxbtozU1FRmzpzJ9OnT6d69u9ZlNYjbhkm3gBb1k++++jyJkoKzEOB+GxRt2rSJ6upq3po/g+dv6jMZjaqq/HXfwdrmL8Bi9iJlbhTdA1pqVu/NE6og5uXJdAtowbVr1zhw4ABvvvkmNpuNtm3bMnz4cHr37t3kd/+qqvLNN99w8OBBcnNzAQgICGDo0KGEh4fXj1rLKy5nW+7B+lq1uKEwm81YLBasVqs0dTlRXTOxzWbH4XDwyevTm12Q3OjRRx9lyJAhrF27FoDp06e7/bbRbttnciOHw8GsWbNYtGiR2wxtVVWV1atX07lzZ8aPH/+Tx21N+47o3V9TWWPHx8NMdHiQy++ub9WQgQLFxcV89tlnnDx5ElVV6dSpEyNGjKB79+53/Ca32WycOHGCgwcPcunSJQC6d+/O0KFDb3u+ux3U0JQOHTrE1atXGTt2rCbXbw62pn1HVNIpqmyq27xP3EVubi5r165l3LhxDB8+3OXX130H/K1KS0uJjIwkMTFR8yF0DoeDJUuWMHz4cB555JGfPfZuOubd0T//+U9SU1P55ptvUFWVX/7yl4wYMYL27dv/2wd+RUUFx44d49ixY1y/fh2z2UxwcDBDhgyhXbt2Wn8rd8zhcLBo0SLeeustrUsxrLzicv5z5X48PT1RFEW37xNnUVWV7du3k5GRwaxZs1z6PjJcmEBtx3VKSgpz5szRrIbq6moWLFjAM888Q+/evRv0Gne4u25Kqqpy+vRpUlNTOft9CSmOPiiKCVV1MMb8Jff5mRg0aBCDBg0yzOoF0dHRzJs3z62X8NCzffv28U1xOW0C+xvmfeIMpaWlJCYm0rFjR5577jmXjHIzZJgAbN26FT8/P02aHMrKyli4cCGzZ8+WPel/UNuM99UPneQmosN7GbJ54siRIxQXFxMREaF1KYZjtVqZM2cOb7/9drPuJ7kT6enpbNy4keeff57g4GCnXquhYaK7wdsTJ04kPT29vuPWVS5evMj8+fOJjo6WILlB3ai72k5yxa1H3TXGoEGDOHr0qNZlGNL69euZOnWqBMkdCA0NZdWqVRw+fJglS5ZQXl5OXnE5W9O+02xDLrcdzfVzFi5cyMyZM122BHVOTg7r1q0jPj7eMM02TeXGUXdGbp4wmUx4enpSWVmpqxVf3d25c+coLy839NLszmI2m5k6dSoXLlxgdkw8qZ4DMZvNmvU56e7JBGqXx1i4cCExMTFO3x8+PT2dDz74gBUrVkiQ/IRuAS2YOKCTYYOkzqhRo/j73/+udRmGsmbNGmbMmKF1GbrWoUMHhv/384BCZY0DVf3XpG9X0mWYALRv357w8HA2bNjgtGt88skn7Nu3j7i4OF2vVCqaxsCBAzl27JjWZRjGZ599xoABA9xup0Q9GtDFH4vFrOmcLN2GCcDQoUOx2WwcPny4yc/98ccf8+233zJ//nxpyxVA7WqvPj4+9cvUi7tXU1PDzp07mTBhgtalGEJdc3N0eJBmw6p1HSYAU6dOZceOHTetEttY69atw2Kx8OKLLzbZOYUxjB49mr1792pdhu699957vPjii3Kj1oS0bm7WfZgoikJ0dDSxsbHYbLZGnatuMmJQUBBPPvlkE1UojKR///5oPTxe777//nuuXr1KUFCQ1qWIJqT7MAHw8/Nj+vTpxMXF3fU5rFYrc+fOJSIigkcffbQJqxNGUtfUVVFRoXUpurV69WpD7qnT3BkiTAB69uxJnz59+Mtf/nLHry0vL2fWrFlMmzaNvn37OqE6YSRjxowhJSVF6zJ06cCBAwQHB9OypXaLnQrnMEyYADzxxBPk5ORw+vTpBr+mqKiIuXPnEhkZSdeuXZ1YnTCKfv36kZmZqXUZumOz2di+fTtPPfWU1qUIJzBUmADMmTOHd999l7Kystsem5eXx9KlS1m+fDkBAQEuqE4YgaIo+Pn5UV6uzUxjvXr//fd54YUXpNPdoAwXJmazmcjISKKjo392QmNWVhbvvfceiYmJMs5d3LGxY8eSnJysdRm6UVhYSFFRUYMXRxX6Y7gwAWjbti2//e1v6zeWudX+/ftJTk5m2bJlMhlR3JXg4GCys7O1LkM3Vq1aJZ3uBmfIMAEYMGAALVu2JDU19aY/37ZtG2fOnGHRokUuWb5ZGJOiKLRoUbtDpfh5R44cISgoiNatW2tdinAiQ3+aPvvss3z66acc+jKXrWnf8eaaDTgcDl5++WWtSxMGEB4ezp49e7Quw63lFpaxbNsXhD02TutShJMZOkwAJr88m9//6SsW/DWbj4o6MHCEbL0qmkbv3r05efKk1mW4rbzicsasPcDXPr2IeOeQZkujC9cwfJik519BVcGOGZPJrMlqmsKYFEWhVatWDRo52Byl5V/BZDJTo5qwWms4Lu89QzN0mBQUFPDplvfx8vTUdDVNYVwREREkJSVpXYZbqt04DXw8zJjNJlK3vC8rBxiYLjfHaojDhw+zc+dO/m/CEi5csxl+8yahjV69erF582aty3BLt26c5mvvz9y5c5k5cybdu3fXujzRxAwZJhs3bqSsrIzly5ejKArdvJEQEU6jtgjgj1/8g0eC7pefs1t0C2hxw79JCxITE4mNjWXIkCE89thjmtYmmpahmrlsNhsxMTG0a9eO6dOny0xb4XR5xeXsrHqIZfu+Yey6g9LJfBuenp4sWbKEwsJCVq1a5fSdUoXrGCZMrl69ysyZM3nqqacYNWqU1uWIZiIt/wqKYqLarmq2Xaoe/f73v2fw4MHMnj1blqUxCEM0c50+fZr169ezZMkS2rRpo3U5ohm5sZNZBnjcmYEDB9K5c+f6fpQePXpoXZJoBOVOHjNDQ0NVd9sYKCUlhfT0dBYsWIDFYohsFDqTV1wuAzwaoaamhtjYWMLCwnj88ce1LkfcQlGUDFVVQ297nF7DRFVV1qxZg7+/P5MnT9a6HCFEI23atIlLly4RMel50vOvSji7iYaGiS5v5SsrK4mMjOQ3v/kNYWFhWpcjhGgCkydPJumzo/x6ZSpmiwWL2cyeV4ZKoOiE7jrgz58/z+zZs3nttdckSIQwmMoWHUBRsNqh2mpl/tsfkJycTFVVldalidvQ1ZPJ8ePH2bZtGytWrMDHx0frcoQQTWxAF38U6gY0mHlz2rMU5n7J8uXLqaqq4uGHH2b06NEy0MYN6SZM/vSnP1FcXExCQoLMHxHCoLoFtCDc4yv+I/zp+j6THvcOYciQIaiqytdff82GDRsoKSnhgQceIDw8nI4dO2pdtkAHYWK324mLiyM4OJinn35a63KEEE7W2lTNxAGd/u3PFUWhV69e9OrVC6hde2/37t2cO3eO1q1bM2bMGHr16iU3mxpx6zApLS0lMjKSF198kaCgIK3LEUK4QENHmHbs2JFp06YBUFJSQkpKCn/+85/x8vJixIgRhIWFYTabnVmquIHbhsnZs2dZu3YtMTEx+PvLRDAhxE+75557+N3vfgdAVVUVqampREVFoaoqYWFhjBgxQvpZncwtw+STTz7h0KFDJCYmyh7tQjQzjW2m8vb2ZvTo0YwePRq73c6xY8dISEigsrKSXr16MWbMGOnAdwK3ChNVVXn33Xfx9fUlJiZG63KEEDpnNpsZPHgwgwcPRlVVTp8+Xd+B36FDByIiIujUqbZ/RlYyaBy3CZPq6mqioqIYO3YsQ4cO1bocIYTBKIpCUFBQff/r+fPnSUpKoqCgAIdfW3ZWPYSiKCiKIpMl74JbhMnFixdZunQpc+fOrb9LEEI0T65alv7+++9n6tSpAPzxi39g/3sONaqCj0ft9t4SJndG0zDJKy5n+xdZ5B75G6vi4/Hz89OyHCFEM/VI0P0kpH6LRUVWf75LmoVJXnE5o9f8LzabDc8Wv6Lwuko3yRIhmj0t5oncusWwPJXcOc3CJC3/CjU2G3bMePywqZD8BwrRvNntdkwmbZYMvHmLYXGnNFvoMbRLGxRVNhUSQvxLdXU13t7eWpch7oJmTyY1l88ztXspD/R9RB4rhRBA7fYSEib6pFmYJCcn84c//IG2bdtqVYIQws1UVVXJTHWd0qyZ6/LlyxIkQoibVFVVyZOJTmkSJkVFRQQEBGhxaSGEG5Mw0S9NwiQ5OZmxY8dqcWkhhBuTPhP90iRMcnJyCAwM1OLSQgg3Jk8m+uXyMJE7DyH0K6+4nK1p35FXXO6U8+dfuc6xYrPTzi+cx+Wjufbv38/IkSNdfVkhRCPVrVpRY7OhAOEeX9HaVH3b16mqWr+Aoslkqv/1rV+lDi+2lnbFYrHw538clMUWdcalYZJXXM7mw3nEvjbMlZcVQjSB//nf7PpVK3w8zPxH+NM/ur3uj1FVtf7L4XDc9Pu6r79kXsCUcoZqO/iYZFUMvXFZM1decTlj1x0kTe1CxPrD8hgrhI5kZmZSkPk5Xp6ed7VqRd1TidlsxsPDA09PT7y8vPD29sbHxwdfX1+GPngfigJeZkVWxdAhlz2ZpOVfQVVV7JhRVVXuOoTQiczMTHbs2MHq2CV8e6nCaYshdgtowf/pdAWfzr0Z1T9QPh90xmVhMqCLP4qi4GVWsFqt9G4vSwQL4e7qgmTJkiUoiuL0xRBbUklE8H20lyDRHZc1c9Ut8bzkiYfZPOlh3omLpKSkxFWXF0LcoczMTHbu3FkfJK5QXV2Np6enS64lmpZLhwZ3C2jBxAGdCHu4O7GxsSxatIjz58+7sgQhRAPUPZHExMS4dH8Rq9WKl5eXy64nmo5ma3O1adOGhIQEVqxYwZkzZ7QqQwhxi4yMDJc/kdSRJxP90ixMAHx8fFixYgWbN2/m6NGjWpYihKA2SHbt2uXyJ5I6VqsVDw8Pl19XNJ6mYQJgNptZunQpBw4cIDk5WetyhGi20tPTNQ2SOlpeW9w9zcMEan943njjDS5evMimTZu0LkeIZic9PZ2kpCQJEnHX3CJM6kyZMoWWLVuyatUqVFXVuhwhmgV3CRKhb24VJgDjxo0jJCSE6OhoHA6H1uUIYWjp6ens3r3bbYKk1OHl1IUkhfO4XZgADBs2jAkTJvDGG29QXX37heSEEHeuLkiio6PdIkjyisvZXdOL6N1fM3bdQQkUnXHLMAHo3bs3r776KrNmzaKsrEzrcoQwlLS0NPbs2eM2QQK1Sy6hKFTW2FHVH34vdMNtwwSgc+fOxMTEMG/ePC5evKh1OUIYQlpaGsnJyURFRblNkEDtkkueHh54KA5qaqz0vb+l1iWJO+DWYQLwi1/8goSEBOLi4sjJydG6HCF07fjx4+zZs8ftggT+teRS7PhgNvxXd9a+tZivvvpK67JEAyl3MmoqNDRUTU9Pd2I5P62mpobFixczYcIE/Ds/5LSVS4UwquPHj5OSkuKWQfJjbDYba9aswdPTk2nTpmEyuf29ryEpipKhqmrobY/TS5hA7QY7895MZGflQ5jMtXsqyG5sQtye3oLkRllZWXz44YfMnj2bzp07a11Os9PQMNFV1CuKQshjT6KCdNIJ0UDHjx9n7969ugwSgH79+pGQkMBHH33ERx99JHPQ3JSuwgRqO+ksFvNd7fYmRHOSV1zOsm1fsCU5lcjISF0GSR1vb28WL15M586def311ykqKtK6JHELXTVz1ckrLpc+EyF+QnV1NZ8cyeb1T4pwOBx4eXkZqjm4rKyMuLg4wsLCiIiI0Locw2toM5fLdlpsSs7e7U0IvaiqquLLL78kIyODCxcuAODp6Un5vX0wmy3UqCZsNruhtslu1aoVcXFx7Nq1i/nz5zN//nxatWqldVnNni7DRIjmqLKykpMnT5KRkVE/78rLy4s+ffoQERFBhw4d6o/NKy4nad1BfDzAZqsh5/DfUENf0HVT162eeOIJwsLCiIqKYvz48QwbNkzrkpo1XTZzCWF0169f58SJE2RkZNT3D3h7exMcHExISAjt27e/7TlubA4+dzqTvXv3Eh0dbbidDFVVZdOmTeTn5zNnzhy8vb0b/FppMr89Qw4NFsKIKioqyM7OJiMjg0uXLgG1G8cFBwfTv39/7r333ia5Tn5+PgkJCURFRdGuXbsmOac7yc/PZ+XKlUyZMoW+ffve9vi84nLGrD2Iw2HHbDYbql+pKUmYCOGGrl27Vh8cKAlCeQAAA2dJREFUV65cQVVV/Pz86Nu3LyEhIU7/kL927RqLFy/m2WefJTg42KnX0oLD4WD9+vVYrVZeffVVLJafbsnfkvYdC/8nG7tSOzo0OjyIiQM6ubBafTB0B7wQelBWVkZWVhaZmZlcuVI7H6pFixb069ePSZMm0bZtW5fX1LJlSxITE4mPjycvL4/x48e7vAZnMplMvPLKK5w6dYoZM2YwY8YMevTo8aPHnv5iNxZLFzxNMs2gKciTiRBNoLS0lMzMTDIzMykpKQFqRx3169ePkJAQ/P3d74Nq69atFBQUMGvWLEN1zNexWq2sXLmSgIAApkyZctP3mJSUREVFBYNGhkufyW1IM5cQTnL16tX64KjbHqF169aEhITQr18/2rRpo3GFDZeWlsaWLVtYunQpvr6+WpfjFEeOHGHLli3MmzePSktL/nrwJEVfHSZ+0WytS9MFCRMhmsDly5fJzMwkKyuLa9euAdCmTRtCQkLo27cv99xzj8YVNt6FCxeIjY1lwYIFPPDAA1qX4xQVFRUsiFtFiqOPISdyOpP0mQhxhy5dukRGRgZZWVlUVFQA4O/vT0hICC+99JJhJ8Z16NCBlStXEhkZSdhj46hp3dFwzT5+fn4MfmIyf9v1JTWqqX5dPyN9j1qTMBGG92NzCYqKisjIyCA7O5vr168DtXvn9O/fn5dffpmWLZvXxkw+Pj68NCeSxxM/RzGVYLEYb6jsgC7+mM1mfExIh7sTSJgIQ8srLmfsuoPY7XbsdjtjzF/SSqkiICCA/v378+qrr+Ln56d1mW4hPf8qFg8PKmvsmA145163+ZZ0uDuHhIkwtLT8K6gqVNvBx8ODweGTZS7BTxjQxR9FwdArcsu6fs4jYSIMrTl8QDYVuXMXjSFhIgxNPiDvjNy5i7slYSIMTz4ghXA+3e20KIQQwv1ImAghhGg0CRMhhBCNJmEihBCi0SRMhBBCNJqEiRBCiEaTMBFCCNFoEiZCCCEaTcJECCFEo0mYCCGEaDQJEyGEEI0mYSKEEKLRJEyEEEI0mqKqasMPVpRi4J/OK0cIIYSb6ayqasDtDrqjMBFCCCF+jDRzCSGEaDQJEyGEEI0mYSKEEKLRJEyEEEI0moSJEEKIRpMwEUII0WgSJkIIIRpNwkQIIUSjSZgIIYRotP8PLiXOf4reJR4AAAAASUVORK5CYII=\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 -}