def _general_circle_elimination(self, model: grb.Model): edges_solution = model.cbGetSolution(self.edges) used_edges = grb.tupledict({key: edges_solution[key] for key in edges_solution if not math.isclose(0, edges_solution[key], abs_tol=10**-5)}) for edge in used_edges: if used_edges[edge] < 0.7: print("Found an edge with value less than 0.7") self._check_for_cycle(used_edges, model) return # Turn used_edges into a dependency graph dep_graph = self._get_dep_graph(used_edges) try: calculate_order(dep_graph, calculate_circle_dep=True) except CircularDependencyException as dep_exception: self._add_cycle_constr(dep_exception.circle_nodes, model) # For now we try to ignore this disconnected graphs except DisconnectedDependencyGraphException as disc_exception: cycle = calculate_cycle(disc_exception.disconnected_nodes) self._add_cycle_constr(cycle, model)
def solve(self, graph: Graph, **kwargs): self.time_limit = kwargs.pop("time_limit", self.max_time) self.upper_bound = kwargs.pop("upper_bound", None) self.relax_solver.build_model(graph) self.relax_solver.set_output(False) self.abs_graph = self.relax_solver.abstract_graph self.edge_vars = self.relax_solver.edges self.max_edges = 0 for v_i in range(len(graph.vertices)): # Constraint over all vertices: least 2k-1 connections between incident edges incident_vertices = [ i for i in range(self.abs_graph.vert_amount) if np.intersect1d(self.abs_graph.vertices[i], v_i).size > 0 ] self.max_edges += (len(incident_vertices) - 1) self.solve_time_start = time.time() self.lock = asyncio.Lock() asyncio.get_event_loop().run_until_complete( self._inner_solve(self.abs_graph, {}, 0, 0, {})) status = 'OPTIMAL' if self.time_limit and time.time( ) - self.solve_time_start > self.time_limit: status = 'TIME_LIMIT' returned_order = None self.upper_bound = None if self.upper_bound_sol: dep_graph = self._get_dep_graph(self.upper_bound_sol) order = calculate_order(dep_graph, calculate_circle_dep=True) returned_order = [tuple(self.abs_graph.vertices[i]) for i in order] sol = AngularGraphSolution(graph, time.time() - self.solve_time_start, solution_type=self.solution_type, solver=self.__class__.__name__, is_optimal=status == "OPTIMAL", order=returned_order) self.upper_bound_sol = None return sol
def solve(self, graph: Graph, **kwargs): error_message = None returned_order = None is_optimal = False runtime = 0 try: self.build_model(graph) if "time_limit" in kwargs: self.model.setParam("TimeLimit", kwargs.pop("time_limit")) self.add_start_solution(graph, kwargs.pop("start_solution", None)) self._add_callbacks(kwargs.pop("callbacks", None)) if kwargs.pop("relax", False): old_edges = self.edges used_edges = None rel_model = self.model.relax() keys, self.edges = grb.multidict({key: rel_model.getVarByName(self.edges[key].VarName) for key in self.edges}) rel_model.optimize(callback_rerouter) runtime = self.model.Runtime else: circle_found = True max_runtime = self.params["TimeLimit"] while(circle_found and max_runtime > 0): self.model.optimize(callback_rerouter) max_runtime -= self.model.Runtime runtime = abs(self.params["TimeLimit"] - max_runtime) try: used_edges = grb.tupledict({key: self.edges[key] for key in self.edges if not math.isclose(0, self.edges[key].x, abs_tol=10**-6)}) circle_found = self._check_for_cycle(used_edges, self.model, lazy=False) if circle_found and max_runtime > 0: self.model.setParam("TimeLimit", max_runtime) except AttributeError as e: # Can happen if no solution was found in the time limit # If not, raise error if runtime < self.params["TimeLimit"]: raise e is_optimal = self.model.Status == grb.GRB.OPTIMAL if is_debug_env(): local_subtours = 0 for circle in self.found_circles: verts = [key[1] for key in circle] for v_i in self.v_incident_edges: if self.v_incident_edges[v_i].issuperset(verts): local_subtours += 1 break print("Overall subtours:", len(self.found_circles), "local subtours:", local_subtours,\ "in percent:", local_subtours*100/len(self.found_circles)) try: used_edges = {key: self.edges[key] for key in self.edges if not math.isclose(0, self.edges[key].x, abs_tol=10**-6)} dep_graph = self._get_dep_graph(used_edges) order = calculate_order(dep_graph, calculate_circle_dep=True) returned_order = [tuple(self.abstract_graph.vertices[i]) for i in order] except (CircularDependencyException, AttributeError) as e: # If we have a circular dependency after the time limit we just didnt managed to get a feasable solution in time # Else something went wrong and the error should be raised if runtime < self.params["TimeLimit"]: raise e except Exception as e: error_message = str(e) if is_debug_env(): raise e #times = calculate_times(returned_order, self.graph) sol = AngularGraphSolution(self.graph, runtime, solution_type=self.solution_type, solver=self.__class__.__name__, is_optimal=is_optimal, order=returned_order, error_message=error_message) return sol
def _calculate_order(self, dependency_graph: DependencyGraph) -> SolveOrder: return calculate_order(dependency_graph)