def solve(self, graph: Graph, **kwargs): self._build_model(graph) solver = cp_model.CpSolver() for param in self.params: setattr(solver.parameters, param, self.params[param]) if "time_limit" in kwargs: solver.parameters.max_time_in_seconds = kwargs["time_limit"] status = solver.Solve(self.model) if status in [cp_model.FEASIBLE, cp_model.OPTIMAL]: obj_val = solver.ObjectiveValue() values = {tuple(self.abstract_graph.vertices[key]): solver.Value(self.vertices[key]) for key in self.vertices} order = calculate_order_from_times(values, self.graph) sol = AngularGraphSolution( graph, solver.UserTime(), self.__class__.__name__, self.solution_type, is_optimal=(status == cp_model.OPTIMAL), order=order, ) else: sol = AngularGraphSolution( graph, solver.UserTime(), self.__class__.__name__, self.solution_type, is_optimal=(status == cp_model.OPTIMAL), error_message="No feasable solution found", ) return sol
def solve(self, graph: Graph, **kwargs): start_time = time.time() times = None error_message = None try: # Split edges into log n subgraphs along the x-axis n = graph.vert_amount split_array = np.zeros((math.ceil(math.log2(n)), n)) self._calculate_split(split_array, 0, 0, n) # Calculate subgraphs used_edges = set() argsorted = np.argsort(graph.vertices[:, 0]) solutions = [] self._solve_subgraphs(split_array, argsorted, graph, used_edges, solutions) times = self._calculate_order(solutions, graph) if len(times) != graph.edge_amount: times = None raise Exception("Edge order does not contain all edges!") except Exception as e: error_message = str(e) raise e return AngularGraphSolution(graph, time.time() - start_time, self.__class__.__name__, self.sub_solver.solution_type, times=times, error_message=error_message)
def __call__(self, gen_algo: GeneticAlgorithm): data = [] for genome in gen_algo.genomes: arg_sorted = np.argsort(genome.order_numbers) order = self.graph.edges[arg_sorted].tolist() times, head_sum = calculate_times(self.graph.edges[arg_sorted], angles=self.graph.costs, return_angle_sum=True) min_sum = sum(head_sum) local_min_sum = max(head_sum) sol = AngularGraphSolution(self.graph, 0, gen_algo.solver, gen_algo.solution_type, is_optimal=False, order=order, error_message=None) data.append({ "Graph": self.graph.name, "Generation": gen_algo.generation, "solution_type": sol.solution_type, "solver": sol.solver, "min_sum": sol.min_sum, "local_min_sum": sol.local_min_sum, "makespan": sol.makespan }) assert math.isclose(genome.solution, -sol.local_min_sum) or math.isclose( genome.solution, -sol.min_sum) self.dataFrame = self.dataFrame.append(pd.DataFrame(data), ignore_index=True) update_callback(gen_algo)
def _get_random_sol(self, graph: Graph) -> AngularGraphSolution: order = np.random.permutation(graph.edges).tolist() sol = AngularGraphSolution(graph, 0, self.__class__.__name__, self.solution_type, is_optimal=False, order=order) return sol
def build_ip_and_optimize(self, graph: Graph, start_solution: Optional[dict] = None, callbacks: Optional[Union[Multidict, dict]] = None, time_limit=None): error_message = None runtime = 0 is_optimal = False times = None try: self.graph = graph self.model = gurobipy.Model() self.model.setParam("LazyConstraints", 1) for param in self.params: self.model.setParam(param, self.params[param]) # Override general time limit, if one is provided if time_limit: self.model.setParam("TimeLimit", time_limit) times_first, times_reverse = self._add_times_variables() self.edges, self.angles = self._add_hamilton_paths() self._add_times_equals_constraints(times_first, times_reverse) self.times = gurobipy.tupledict() self.times.update(times_first) self.times.update(times_reverse) self._add_taken_edges_constraints() self._set_objective() self._add_callbacks(callbacks) self._add_pre_solution(graph, start_solution) self.model.update() self.model.optimize(callback_rerouter) runtime = self.model.Runtime is_optimal = self.model.Status == gurobipy.GRB.OPTIMAL times = {t: self.times[t].x for t in self.times} except Exception as e: if self.model.Status != gurobipy.GRB.TIME_LIMIT: error_message = str(e) if is_debug_env(): raise e sol = AngularGraphSolution(self.graph, runtime, times=times, solution_type=self.solution_type, is_optimal=is_optimal, solver=self.__class__.__name__, error_message=error_message) return sol
def solve(self, graph: Graph, **kwargs): # count how many vertices have largest angle north or south # Maybe choose which set get which starting position accordingly order = None start_time = time.time() error_message = None try: colors = kwargs.pop("colors", None) if colors is None: colors = self._calc_subsets(graph) # Make sure V_1 and V_2 are bipartite partitions assert len(colors) == graph.vert_amount assert np.alltrue([colors[i] != colors[j] for i, j in graph.edges]) sectors_V = { i: get_vertex_sectors(graph.vertices[i], graph.vertices[np.nonzero( graph.ad_matrix[i])], start_north=bool(colors[i])) for i in range(graph.vert_amount) } tripel_edges, abs_graph = convert_graph_to_angular_abstract_graph( graph, simple_graph=False, return_tripel_edges=True) edge_vert = {i: {} for i in range(graph.vert_amount)} for edge in tripel_edges: edge_vert[edge[0]][edge[1:]] = tripel_edges[edge] used_edges = [] for vertex_key in sectors_V: sectors_info = sectors_V[vertex_key] if len(sectors_info) == 1: continue non_zeros = np.nonzero(graph.ad_matrix[vertex_key])[0] for from_vert, to_vert, angle in sectors_info[:-1]: used_edges.append( edge_vert[vertex_key][non_zeros[from_vert], non_zeros[to_vert]]) dep_graph = get_dep_graph(used_edges, abs_graph) order = [ tuple(abs_graph.vertices[i]) for i in calculate_order(dep_graph, calculate_circle_dep=True) ] except NotImplementedError as e: error_message = str(e) raise e sol = AngularGraphSolution(graph, time.time() - start_time, self.__class__.__name__, self.solution_type, is_optimal=False, error_message=error_message, order=order) return sol
def solve(self, graph: Graph, **kwargs): start_time = time.time() times = None error_message = None try: coloring = self.coloring_solver(graph) max_color = max(coloring) index_colorings = [] log_max_color = math.ceil(math.log2(max_color)) color_bit_vector = np.array([[(color >> (log_max_color - 1 - i)) & 1 for i in range(log_max_color)] for color in range(max_color)]) for vec in color_bit_vector.T: # Get indices of the vertices where in one of the sets to_color = np.arange(len(vec))[vec == 1] isin = np.isin(coloring, to_color) both_sets_indices = (*np.where(isin == 0), *np.where(isin == 1)) index_colorings.append(both_sets_indices) solutions = [] used_edges = set() for set_one, set_two in index_colorings: subgraph = graph.get_bipartite_subgraph( set_one, set_two, forbidden_edges=used_edges) if subgraph.edge_amount > 0: sol = self.sub_solver.solve( subgraph, colors=[ int(i in set_one) for i in range(graph.vert_amount) ]) solutions.append(sol) # If wanted collect the already used edges to maybe get a better solution if self.no_used_edges: used_edges.update({(u) for u in product(set_one, set_two)}) times = self._calculate_order(solutions, graph) if len(times) != graph.edge_amount: times = None raise Exception("Edge order does not contain all edges!") except Exception as e: error_message = str(e) raise e return AngularGraphSolution(graph, time.time() - start_time, self.__class__.__name__, self.sub_solver.solution_type, times=times, error_message=error_message)
def _calc_solution(self, graph, orientations, n, k, start_time): dep_graph = self._calculate_dependecy_graph(graph, orientations) order = self._calculate_order(dep_graph) times = calculate_times(order, graph) obj_val = (n - 2) * 180 + (360 / n) * k sol = AngularGraphSolution(graph, time.time() - start_time, self.__class__.__name__, "min_sum", times=times, obj_val=obj_val, sweep_order=order) return sol
def solve(self, graph: Graph, **kwargs): self._initiate_variables(graph, kwargs.pop("upper_bound", None)) best_order = self._start_solves(graph) print("Searched nodes:", self.searched_nodes, "of possible", self.possible_nodes_amount, "(", self.searched_nodes / self.possible_nodes_amount, "%)") sol = AngularGraphSolution( graph, time.time() - self.start_time, self.__class__.__name__, self.solution_type, is_optimal=self.start_time + self.max_time > time.time(), order=best_order) return sol
def solve(self, graph: Graph, **kwargs): self.model = cp_model.CpModel() self.graph = graph time = 0 is_optimal = False times_dict = None error_message = None try: arcs, self.degrees = self._calculate_degrees() time, diffs, absolutes, self.max_time = self._add_variables(arcs) self._add_constraints(arcs, self.degrees, time, diffs, absolutes, self.max_time) #self._add_initial_heading(time, initial_heading) #self._add_pre_solution(time, start_solution) self._setObj() solver = cp_model.CpSolver() for param in self.params: val = self.params[param] setattr(solver.parameters, param, val) if "time_limit" in kwargs: solver.parameters.max_time_in_seconds = kwargs["time_limit"] status = solver.Solve(self.model) if status in [cp_model.FEASIBLE, cp_model.OPTIMAL]: values = np.array([solver.Value(time[key]) for key in time]) times = np.degrees((values / self.multiplier) * np.pi) times_dict = { key: value for key, value in zip(time.keys(), times) } is_optimal = (status == cp_model.OPTIMAL) time = solver.UserTime() except Exception as e: error_message = str(e) sol = AngularGraphSolution(graph, time, self.__class__.__name__, self.solution_type, is_optimal=is_optimal, times=times_dict, error_message=error_message) return sol
def solve(self, graph: Graph, no_sol_return=None, **kwargs): if no_sol_return is None: no_sol_return = self.no_sol_return if self.no_sol_return is not None else False start_time = time.time() # Process kwargs upper_bound = kwargs.pop("ub", None) order = kwargs.pop("presolved", []) order = order.copy() headings = kwargs.pop("headings", [[] for head in graph.vertices]) assert isinstance(headings, list) headings = headings.copy() for i, heading in enumerate(headings): headings[i] = heading.copy() remaining_edges = kwargs.pop("remaining", graph.edges) if isinstance(remaining_edges, np.ndarray): remaining_edges = remaining_edges.tolist() remaining_edges = remaining_edges.copy() # If one is empty, the other also needs to be emtpy assert order or len(remaining_edges) == graph.edge_amount assert len(remaining_edges) != graph.edge_amount or not order angles = graph.costs if angles is None: angles = get_graph_angles(graph) overall_cost = self._calc_pre_cost(headings, angles) while remaining_edges and (upper_bound is None or upper_bound > overall_cost): candidate_edge, candidate_cost = self._get_candidate( order, remaining_edges, headings, angles) self._set_new_headings(candidate_edge, headings) to_remove = self._get_edge(remaining_edges, candidate_edge) remaining_edges.remove(to_remove) order.append(to_remove) overall_cost += candidate_cost if no_sol_return: return order, overall_cost sol = AngularGraphSolution(graph, time.time() - start_time, self.__class__.__name__, self.solution_type, is_optimal=False, order=order) return sol
def solve(self, graph: Graph, **kwargs): # Sort'em hull = ConvexHull(graph.vertices) # Indices are in counter clockwise order, therefore reverse them indices = [vertex for vertex in reversed(hull.vertices)] length = len(indices) assert length == graph.vert_amount k = graph.ad_matrix[0].sum() / 2 assert k.is_integer() k = int(k) neighbors = { indices[i]: tuple(indices[int(j % length)] for j in range(i - k, i + k + 1) if i != j) for i in range(length) } # Just check if every node has 2k neighbors for index in indices: #neighbors = tuple(indices[int(j % length)] for j in range(i-k, i+k+1) if i != j) assert graph.ad_matrix[index, neighbors[index]].sum() == 2 * k tripel_edges, abs_graph = convert_graph_to_angular_abstract_graph( graph, simple_graph=False, return_tripel_edges=True) edge_vert = {i: {} for i in range(length)} for edge in tripel_edges: edge_vert[edge[0]][edge[1:]] = tripel_edges[edge] #edge_vert[edge[0]][tuple(reversed(edge[1:]))] = tripel_edges[edge] taken_edges = [] # Phase one self._phase_one(indices, k, neighbors, taken_edges, edge_vert) # Phase two split_vertex_index = round(length / 2) self._phase_two(split_vertex_index, k, indices, neighbors, taken_edges, edge_vert, length) # Clockwise part self._phase_three(k, indices, split_vertex_index, neighbors, taken_edges, edge_vert) dep_graph = get_dep_graph(taken_edges, abs_graph) order = calculate_order(dep_graph, calculate_circle_dep=True) returned_order = [tuple(abs_graph.vertices[i]) for i in order] return AngularGraphSolution(graph, 0, self.__class__.__name__, 'MinSum', False, order=reversed(returned_order))
def solve(self, graph: Graph, **kwargs): # count how many vertices have largest angle north or south # Maybe choose which set get which starting position accordingly order = None start_time = time.time() error_message = None try: colors = kwargs.pop("colors", None) if colors is None: colors = self._calc_subsets(graph) colors = self._check_bipartite(colors, graph) sectors_v = { i: get_vertex_sectors(graph.vertices[i], graph.vertices[np.nonzero( graph.ad_matrix[i])], start_north=bool(colors[i])) for i in range(graph.vert_amount) } edge_vert, abs_graph = self._create_abs_graph_and_edge_translation( graph) used_edges = self._calculated_used_edges(sectors_v, graph, edge_vert) dep_graph = get_dep_graph(used_edges, abs_graph) order = [ tuple(abs_graph.vertices[i]) for i in calculate_order(dep_graph, calculate_circle_dep=True) ] except NotImplementedError as e: error_message = str(e) raise e # For small instances it could happen that two vertices have connections only to each other. # These edges will not be scheduled. Since they do not depend on any other edge, we just add them at the end. order = self._add_single_edges(order, graph) sol = AngularGraphSolution(graph, time.time() - start_time, self.__class__.__name__, self.solution_type, is_optimal=False, error_message=error_message, order=order) return sol
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, start_solution=None, **kwargs): self.time_limit = float(kwargs.pop("time_limit", self.max_time)) start_time = time.time() # graph.costs = get_graph_angles(graph) solution = self.sub_solver( graph) if start_solution is None else start_solution angles = None if not isinstance(solution, AngularGraphSolution): angles = get_graph_angles(graph) best_order, best_cost = self._get_cost(solution, angles) with concurrent.futures.ThreadPoolExecutor( max_workers=cpu_count()) as executor: try: error_message = None futures = [ executor.submit(self._inner_solve, graph, best_order) for swap in range(cpu_count()) ] timeout = self.time_limit - (time.time() - start_time) + 10 concurrent.futures.wait(futures, timeout=timeout) except TimeoutError as time_error: error_message = str(time_error) for future in futures: if future.done(): order, cost = future.result() if cost < best_cost: best_cost = cost best_order = order if isinstance(best_order, np.ndarray): best_order = best_order.tolist() sol = AngularGraphSolution(graph, time.time() - start_time, self.__class__.__name__, self.solution_type, is_optimal=False, order=best_order, error_message=error_message) 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 solve(self, graph: Graph, **kwargs): # count how many vertices have largest angle north or south # Maybe choose which set get which starting position accordingly order = None start_time = time.time() error_message = None try: colors = kwargs.pop("colors", None) if colors is None: colors = self._calc_subsets(graph) colors = self._check_bipartite(colors, graph) force_strategy = kwargs.pop("strategy", None) debug = kwargs.pop("debug", False) # MLSSC (LocalMinSum) lower bound is exactly the value for the cone described in the paper. mlssc_lb = max(get_lower_bounds(graph)) if mlssc_lb >= 90 or force_strategy == 1: # If we have a LB >= 90, we can use the same algorithm as before return super().solve(graph, colors=colors) else: # LB < 90 needs another strategy with the sector splits. See paper for more details if mlssc_lb > 0: s = math.floor( 180 / mlssc_lb) # The minium amount of lines where cone > lb cone = np.radians(360 / (2 * s)) ad_angles_v = { i: np.array([ i if i > 0 else 2 * np.pi + i for i in np.arctan2(*(graph.vertices[np.nonzero( graph.ad_matrix[i])] - graph.vertices[i]).T) ]) for i in range(graph.vert_amount) } sectors_v = {i: {} for i in range(graph.vert_amount)} for key in ad_angles_v: angles = ad_angles_v[key] % (2 * np.pi) non_zeros = np.nonzero(graph.ad_matrix[key])[0] argsorted = np.argsort(angles) for i in argsorted: angle = angles[i] current_sector = math.floor(angle / cone) % ( 2 * s ) # if colors[i] else (math.ceil(angle/cone)-1) % (2*s) if current_sector not in sectors_v[key]: sectors_v[key][current_sector] = [non_zeros[i]] else: sectors_v[key][current_sector].append( non_zeros[i]) # Check if every vertex has at most two sectors for key in sectors_v: assert len( sectors_v[key] ) <= 2, f"Sector build is wrong! Vertex index {key} has {len(sectors_v[key])} sectors" # Give sectors directions sector_directions_v = { i: { j: 1 - j % 2 if (s % 2 and colors[i]) else j % 2 for j in sectors_v[i] } for i in range(graph.vert_amount) } edge_vert, abs_graph = self._create_abs_graph_and_edge_translation( graph) used_edges = [] sector_orders = {} for key in sectors_v: sector_order = [-1, -1] for j in sector_directions_v[key]: #if s%2 == 0: # sector_order[j%2] = j #else: inner_key = 1 - j % 2 if ( s % 2 and colors[key]) else j % 2 sector_order[inner_key] = j sector_orders[key] = sector_order for key in sector_orders: sector_order = sector_orders[key] from_vert = None for o in sector_order: if o == -1: continue sectors_info = sectors_v[key][o] non_zeros = np.nonzero(graph.ad_matrix[key])[0] it = iter(sectors_info) if sector_directions_v[ key][o] == 0 else reversed(sectors_info) for to_vert in it: if from_vert is not None: used_edges.append(edge_vert[key][from_vert, to_vert]) if debug: print("Used edge:", key, from_vert, to_vert) from_vert = to_vert dep_graph = get_dep_graph(used_edges, abs_graph) try: order = [ tuple(abs_graph.vertices[i]) for i in calculate_order(dep_graph, calculate_circle_dep=True) ] except CircularDependencyException as c_e: if debug: translated_cycle = [ abs_graph.vertices[i.value].tolist() for i in c_e.circle_nodes ] print("Cycle:", translated_cycle) raise c_e except NotImplementedError as e: error_message = str(e) raise e order = self._add_single_edges(order, graph) sol = AngularGraphSolution(graph, time.time() - start_time, self.__class__.__name__, self.solution_type, is_optimal=False, error_message=error_message, order=order) assert sol.makespan <= mlssc_lb * 4.5 return sol
def _decode_sol(self, sol): return AngularGraphSolution(sol["graph"], times=sol["order"], runtime=sol["runtime"], name=sol["name"])
def solve(self, graph: Graph, start_solution=None, **kwargs): time_limit = float(kwargs.pop("time_limit", self.time_limit)) start_time = time.time() if graph.costs is None: angles = get_graph_angles(graph) graph.costs = angles else: angles = [i.copy() for i in graph.costs] solution = self.sub_solver( graph) if start_solution is None else start_solution improvement = True # solution can be AngularGraphSolution or simple edge order best_order = np.array(solution.order) if isinstance( solution, AngularGraphSolution) else np.array(solution) best_cost = self._get_cost(solution, angles) with concurrent.futures.ThreadPoolExecutor( max_workers=cpu_count()) as executor: try: error_message = None with tqdm.tqdm( total=self.max_iterations, desc= f"Iterating local neighborhood. Best Sol: {best_cost}" ) as progressbar: iteration = 0 while (self.max_iterations is None or iteration < self.max_iterations) and\ (time_limit or time.time() - start_time < time_limit) and\ (improvement): improvement = False candidate_order = None candidate_cost = None futures = [ executor.submit(self._inner_solve, [i.copy() for i in angles], i, best_order, best_cost, time_limit, start_time) for i in range(graph.edge_amount) ] timeout = time_limit - (time.time() - start_time) + 10 concurrent.futures.wait(futures, timeout=timeout) for future in futures: if future.done(): order, cost = future.result() if candidate_cost is None or cost < candidate_cost: candidate_cost = cost candidate_order = order if candidate_cost is not None and candidate_cost < best_cost: improvement = True best_cost = candidate_cost best_order = candidate_order progressbar.set_description( f"Iterating local neighborhood. Best Sol: {best_cost}" ) if not improvement: break progressbar.update() iteration += 1 except concurrent.futures.TimeoutError as time_error: error_message = str(time_error) + " in iteration " + str( iteration) sol = AngularGraphSolution(graph, time.time() - start_time, self.__class__.__name__, self.solution_type, is_optimal=False, order=best_order.tolist(), error_message=error_message) return sol
def solve(self, graph: Graph, **kwargs): if graph.costs is None: graph.costs = get_graph_angles(graph) error_message = None self.time_limit = kwargs.pop("time_limit", self.max_time) self.graph = graph try: self.start_time = time.time() genomes = np.zeros(self.pop_size, dtype=object) genomes[:] = [ EdgeOrderGraphGenome(graph, skip_graph_calc=True) for i in range(self.pop_size) ] with concurrent.futures.ThreadPoolExecutor( max_workers=cpu_count()) as executor: self.executor = executor if self.greedy_start: slicings = self._get_slicing(genomes) futures = [ executor.submit( _greedy_order, [ genome.order_numbers for genome in genomes[slicing] ], self.graph, self.sub_solvers[np.random.randint( 0, len(self.sub_solvers))] #self._greedy_order, genomes[slicing],\ #self.sub_solvers[np.random.randint(0, len(self.sub_solvers))] ) for slicing in slicings ] timeout_time = self.time_limit - (time.time() - self.start_time) concurrent.futures.wait(futures, timeout=timeout_time) for future in futures: future.exception() # Start solver genetic_algorithm = GeneticAlgorithm( genomes=genomes, selection=self.selection, mutation=self._mutation, fitness=self._fitness, crossover=self.crossover, callback=self.callback, termCon=self.termination_condition, elitism=self.elitism, mutationChance=self.mutation_chance_genome, mutationChanceGene=self.mutation_chance_gene) last_gen = genetic_algorithm.evolve() except concurrent.futures.TimeoutError as time_error: error_message = str(time_error) last_gen = genetic_algorithm.genomes finally: self.executor = None self.graph = None max_index = np.argmax([gen.solution for gen in last_gen]) arg_sorted = np.argsort(last_gen[max_index].order_numbers) order = graph.edges[arg_sorted].tolist() sol = AngularGraphSolution(graph, time.time() - self.start_time, self.__class__.__name__, self.solution_type, is_optimal=False, order=order, error_message=error_message) return sol
def build_ip_and_optimize( self, graph: Graph, initial_heading: Optional[Union[list, np.array]] = None, start_solution: Optional[dict] = None, callbacks: Optional[Union[Multidict, dict]] = None, **kwargs): try: error_message = None runtime = 0 is_optimal = False times = None try: self.graph = graph self.model = grb.Model() for param in self.params: self.model.setParam(param, self.params[param]) if "time_limit" in kwargs: self.model.setParam("TimeLimit", kwargs["time_limit"]) self._add_callbacks(callbacks) arcs, degrees = self._calculate_degrees() time, diffs, absolutes, max_time = self._add_variables(arcs) self._add_constraints(arcs, degrees, time, diffs, absolutes, max_time) self.model.setObjective(max_time, grb.GRB.MINIMIZE) self._add_initial_heading(time, initial_heading) self._add_pre_solution(time, graph, start_solution) self.model.update() self.model.optimize(callback_rerouter) #for v in time: #if v.x != 0 or "time" in v.varName: #print('%s %g' % (time[v].varName, time[v].x)) #for v in absolutes: # if absolutes[v].x >= 180: # print('%s %g' % (absolutes[v].varName, absolutes[v].x)) #print('%s %g' % (max_time.varName, max_time.x)) runtime = self.model.Runtime times = {t: time[t].x for t in time} is_optimal = self.model.Status == grb.GRB.OPTIMAL except Exception as e: error_message = str(e) if is_debug_env(): raise e sol = AngularGraphSolution(self.graph, runtime=runtime, solver=self.__class__.__name__, solution_type="makespan", is_optimal=is_optimal, times=times, error_message=error_message) return sol except Exception as exception: raise exception finally: self._cleanup() return None