def _check_for_cycle(self, used_edges: grb.tupledict, model: grb.Model, lazy=True): unseen = {i for i in range(len(self.abstract_graph.vertices))} queued = set() while unseen: queued.add((None, unseen.pop())) prev = {} seen = set() while queued: edge = queued.pop() sub = used_edges.subset(edge[1], '*') seen.add(edge[1]) for key in sub: destination = key[1] if destination in unseen: try: pass#unseen.remove(destination) except KeyError: print("Double unseen event!") pass # It can happen that some nodes will be seen multiple times queued.add(key) prev[key] = edge if destination in seen: path = [key, edge] while path[-1][0] and path[-1][0] != destination: path.append(prev[path[-1]]) if path[-1][0] == destination: self.found_circles.append(path) expr = None if self.with_vertex_subtour_constr: abs_vert_on_path = [key[1] for key in path] for v_i in range(self.graph.vert_amount): if self.v_incident_edges[v_i].issuperset(abs_vert_on_path): diff = self.v_incident_edges[v_i].difference(abs_vert_on_path) incoming = self.edges.subset(diff, abs_vert_on_path) outgoing = self.edges.subset(abs_vert_on_path, diff) expr = incoming.sum() + outgoing.sum() >= 1 break if expr is None: expr = sum(self.edges[i] for i in path) <= len(path)-1 if lazy: model.cbLazy(expr) else: model.addConstr(expr) #print("Found cycle", path) return True #print("No cycle found for:", prev) return False
def _subtour_elimination(self, model: gurobipy.Model): #nodecnt = model.cbGet(gurobipy.GRB.Callback.MIPSOL_NODCNT) #obj = model.cbGet(gurobipy.GRB.Callback.MIPSOL_OBJ) #solcnt = model.cbGet(gurobipy.GRB.Callback.MIPSOL_SOLCNT) #solution = model.cbGetSolution(self.edges) # for every subsolution, try to find shortcuts for base_vertex_index, edges in self.edges.items(): edge_solution = model.cbGetSolution(edges) used_edges = { key: edge_solution[key] for key in edge_solution if edge_solution[key] > 0.1 } ad_vert = {key[1]: key for key in used_edges} visited = set() all_ad_vert = {key[1]: key for key in edge_solution} vertices_amount = len(all_ad_vert) while len(visited) < vertices_amount: current_vertices = [] vertex, edge_key = self._get_start_vertex(used_edges, visited) while vertex not in visited: visited.add(vertex) current_vertices.append(vertex) vertex = edge_key[2] try: edge_key = ad_vert[vertex] except KeyError: # Should only happen if we get to an end of a path # Therefore, just add them to also mark them as visited visited.add(vertex) current_vertices.append(vertex) # Found a subtour, need to eliminate it if len(current_vertices) < vertices_amount: not_current_vertices = [ i for i in all_ad_vert if i not in current_vertices ] model.cbLazy( edges.sum(base_vertex_index, current_vertices, not_current_vertices) + edges.sum(base_vertex_index, not_current_vertices, current_vertices) >= 1) print("Subtour found for point", base_vertex_index, "with vertices", current_vertices)
def _check_for_cycle(self, used_edges: grb.tupledict, model: grb.Model, lazy=True): unseen = {i for i in range(len(self.abstract_graph.vertices))} queued = set() while unseen: queued.add((None, unseen.pop())) prev = {} seen = set() while queued: edge = queued.pop() sub = used_edges.subset(edge[1], '*') seen.add(edge[1]) for key in sub: destination = key[1] if destination in unseen: try: pass #unseen.remove(destination) except KeyError: print("Double unseen event!") pass # It can happen that some nodes will be seen multiple times queued.add(key) prev[key] = edge if destination in seen: path = [key, edge] while path[-1][0] and path[-1][0] != destination: path.append(prev[path[-1]]) if path[-1][0] == destination: if lazy: self.found_circles.append(path) model.cbLazy( sum(self.edges[i] for i in path) <= len(path) - 1) else: self.found_circles.append(path) model.addConstr( sum(self.edges[i] for i in path) <= len(path) - 1) #print("Found cycle", path) return True #print("No cycle found for:", prev) return False
def _add_cycle_constr(self, cycle_nodes, model: grb.Model): cycle = [nodes.value for nodes in cycle_nodes] l = len(cycle) cycle_edges = [(cycle[i], cycle[((i + 1) % l)]) for i in range(l)] cycle_edges_rev = [(cycle[((i + 1) % l)], cycle[i]) for i in range(l)] #print("CYCLE EDGES:", cycle_edges) l = len(cycle_edges) - 1 try: cycle_edges_vars = grb.tupledict( {i: self.edges[i] for i in cycle_edges}) cycle_edges_rev_vars = grb.tupledict( {i: self.edges[i] for i in cycle_edges_rev}) exp = grb.LinExpr(cycle_edges_vars.sum()) exp_rev = grb.LinExpr(cycle_edges_rev_vars.sum()) model.cbLazy(exp <= l) model.cbLazy(exp_rev <= l) #model.addConstr(exp <= l) except grb.GurobiError as err: print("ERROR: Gurobi error with number:", err.errno)