def independent_set(graph, name="Independent Set"): """ Generates an independent set instance according to [1]. Parameters ---------- graph: nx.Graph Networkx undirected graph name: str Name of the generated model Returns ------- model: scip.Model A pyscipopt model of the generated instance References ---------- .. [1] https://www.princeton.edu/~aaa/Public/Teaching/ORF523/S16/ORF523_S16_Lec11_gh.pdf """ graph = nx.relabel.convert_node_labels_to_integers(graph) model = scip.Model(name) vars = { str(node): model.addVar(lb=0, ub=1, obj=1, name=str(node), vtype="B") for node in graph.nodes } for u, v in graph.edges: model.addCons(vars[str(u)] + vars[str(v)] <= 1) model.setMaximize() return model
def set_cover(costs, sets, name="Set Cover"): """ Generates basic set cover formulation. Parameters ---------- costs: list[float] Cost for covering each element sets: list[set] Set constraints for elements Returns ------- model: scip.Model A pyscipopt model of the generated instance """ model = scip.Model(name) # add variables and their cost variables = [ model.addVar(lb=0, ub=1, obj=c, name=f"v_{i}", vtype="B") for i, c in enumerate(costs) ] # add constraints for s in sets: model.addCons(scip.quicksum(variables[i] for i in s) >= 1) model.setMinimize() return model
def build_binary_model(self): self.model = scip.Model("MasterPricer") self.__build_variables__(tipo="B") self.__build_objectives__() self.__build_constraints__() self.__ensure_feasibility__() self.__build_convexity__()
def packing(n, m, costs, constraint_coefficients, limits, binary, name="Packing"): """Generates a packing instance as described in A.2 in [1]. Parameters: ---------- n: int Number of variables m: int Number of constraints costs: list[number] of size n Coefficients of objective function constraint_coefficients: list[list[number]] of dimensions (m x n) Coefficients of each variable for each constraint limits: list[number] of size m Limits of each constraint name: str Name of the model Returns ------- model: scip.Model A pyscipopt model of the generated instance References: ---------- .. [1] Tang, Y., Agrawal, S., & Faenza, Y. (2019). Reinforcement learning for integer programming: Learning to cut. arXiv preprint arXiv:1906.04859. """ model = scip.Model(name) # add variables and their cost vars = [] for i in range(n): cost = costs[i] if binary: var = model.addVar(lb=0, ub=1, obj=cost, name=f"v_{i}", vtype="B") else: var = model.addVar(lb=0, ub=None, obj=cost, name=f"v_{i}", vtype="I") vars.append(var) # add constraints for i in range(m): constraint_vars = (constraint_coefficients[i][j] * var for j, var in enumerate(vars)) model.addCons(scip.quicksum(constraint_vars) <= limits[i]) # contrary to the paper (as of 05/11/2020) as a result of correspondence of with one of the authors model.setMaximize() return model
def triangle(graph): model = scip.Model("Triangle MaxCut") edge_variables = {} for u, v in itertools.combinations(graph.nodes(), 2): edge_name = naming.undirected_edge_name(u, v) if graph.has_edge(u, v): weight = graph.get_edge_data(u, v)["weight"] else: weight = 0 edge_variables[edge_name] = model.addVar(lb=0, ub=1, obj=weight, name=edge_name, vtype="B") model.setMaximize() for i, j, k in itertools.combinations(graph.nodes(), 3): x_ij = _get_edge_variable(i, j, edge_variables) x_ik = _get_edge_variable(i, k, edge_variables) x_kj = _get_edge_variable(k, j, edge_variables) model.addCons(x_ij <= x_ik + x_kj) model.addCons(x_ij + x_ik + x_kj <= 2) return edge_variables, model
def compute_schedule(self, laps, offset=0): """Compute train schedule. Results are dumped into a file named 'model.txt'. Args: laps (int): Number of laps that trains must run. offset (float): Offset. """ # Initialise model self.model = scip.Model('Schedule') self.build_model(laps, offset) # Create objective function start, end = self.vars['start']['var'], self.vars['end']['var'] objective = self.model.setObjective(end - start, sense='minimize') # Export file # self.export_model('model.txt') # Solve # self.model.hideOutput() self.model.optimize() # Obtain results self.get_results('solution.txt')
def __init__(self, objects, stations, processing_time, **kwargs): # list of objects self.objects = objects # list of stations self.stations = stations # processing time dict self.processing_time = processing_time # maximal flow time self.max_flow_time = kwargs.get('max_flow_time', 480) # verbose mode self.verbose = kwargs.get('verbose', False) # init model self.model = pyscipopt.Model() # init variables self.start_time = self.init_start_time_var() self.end_time = self.init_end_time_var() self.delta = self.init_delta_var() # constraints self.add_last_station_cons() self.add_objects_order_cons() self.add_stations_cons() # objective function self.set_objective() # run optimization self.optimize()
def shuffle(model, seed, cons=True, vars=True): """ Shuffles a MIP instance's rows & columns Parameters ---------- model: scip.Model A pyscipopt model of the to be shuffled instance seed: int Used in shuffling (must be bigger than 0) cons: bool Whether the columns should be shuffled vars: bool Whether the rows should be shuffled Returns ------- model: scip.Model A pyscipopt model of the shuffled instance """ # The following line of code does not correctly set the name! Leave commented until it's clear why. # shuffled = scip.Model(sourceModel=model, problemName=model.getProbName(), origcopy=True) assert seed > 0 shuffled = scip.Model() with tempfile.NamedTemporaryFile(suffix=".mps") as temp: model.writeProblem(temp.name) shuffled.setParam("randomization/permutationseed", seed) shuffled.setParam("randomization/permuteconss", cons) shuffled.setParam("randomization/permutevars", vars) shuffled.readProblem(temp.name) shuffled.setProbName(model.getProbName()) return shuffled
def assignment(graph, color_upperbound, name="Assignment Graph Coloring", with_variables=False): """ Generates a graph coloring ILP formulation (ASS-S) as described in [1]. Parameters ---------- graph: networkx graph Input graph color_upperbound: int Maximum number of colors to use name: str Name of the model with_variables: bool return variables with the generated model (used to extend model) Returns ------- model: scip.Model pyscipopt model of the generated instance References ---------- .. [1] A.Jabrayilov, P.Mutzel "New Integer Linear Programming Models for the Vertex Coloring Problem" """ model = scip.Model(name) graph = nx.convert_node_labels_to_integers(graph, first_label=0) colors = range(color_upperbound) # add variables and their cost x = {(vertex, color): model.addVar(lb=0, ub=1, obj=0, name=f"x_{vertex}_{color}", vtype="B") for vertex, color in itertools.product(graph.nodes, colors)} w = { color: model.addVar(lb=0, ub=1, obj=1, name=f"w_{color}", vtype="B") for color in colors } # add constraint (2) for v in graph.nodes: model.addCons(scip.quicksum(x[v, color] for color in colors) == 1) # add constraint (3) for u, v in graph.edges: for color in colors: model.addCons(x[u, color] + x[v, color] <= w[color]) model.setMinimize() if with_variables: return model, w, x else: return model
def get_model(): m = scip.Model() m.hideOutput() m.setIntParam('display/verblevel', 0) init_scip_params(m, seed=42) m.setIntParam('timing/clocktype', 2) m.setRealParam('limits/time', 120) m.setParam('limits/nodes', 1) return m
def load_instance(self, instance_name, with_solution=False): if not self._instance_cached(instance_name): self._download_instance(instance_name) problem_path = self._instance_path(instance_name) model = scip.Model() model.readProblem(problem_path) if with_solution: self._add_solution(model, instance_name) return model
def scip_solve(facilities, customers, time_limit=None): fac = len(facilities) cus = len(customers) model = pyscipopt.Model('FL') model.hideOutput() model.setMinimize() #model.setRealParam('limits/gap', 0.2) # x_i = 1 iff facility i is chosen x = [] # 1xN # y_ij = 1 iff customer j is assigned to facility i y = [[] for x in range(len(facilities))] # NxM for i in range(fac): x.append(model.addVar(name='x{}'.format(i), vtype='B')) for j in range(cus): y[i].append(model.addVar(name='y{},{}'.format(i, j), vtype='B')) # total demand to 1 facility <= its capacity for i in range(fac): model.addCons( pyscipopt.quicksum(customers[j].demand * y[i][j] for j in range(cus)) <= facilities[i].capacity) # exactly 1 facility per customer for j in range(cus): model.addCons(pyscipopt.quicksum(y[i][j] for i in range(fac)) == 1) # y_ij can be 1 only if x_i is 1 for i in range(fac): for j in range(cus): model.addCons(y[i][j] <= x[i]) # objective model.setObjective( pyscipopt.quicksum( # distance facility -> customer length(customers[j].location, facilities[i].location) * y[i][j] for i in range(fac) for j in range(cus)) + pyscipopt.quicksum( # setup cost facilities[i].setup_cost * x[i] for i in range(fac)), 'minimize') if time_limit is not None: model.setRealParam('limits/time', time_limit) print('SCIP starts at {}'.format(datetime.now().time())) model.optimize() val = model.getObjVal() assignment = [] for j in range(cus): for i in range(fac): sol = model.getVal(y[i][j]) if sol == 1: assignment.append(i) break return val, assignment
def representatives(graph, name="Representatives Graph Coloring"): """ Generates a graph coloring ILP formulation (REP) as described in [1]. Parameters ---------- graph: networkx graph Input graph name: str Name of the model Returns ------- model: scip.Model A pyscipopt model of the generated instance References ---------- .. [1] A.Jabrayilov, P.Mutzel "New Integer Linear Programming Models for the Vertex Coloring Problem" """ model = scip.Model(name) graph = nx.convert_node_labels_to_integers(graph, first_label=0) # add variables and their cost x = {} for (u, v) in itertools.product(graph.nodes, graph.nodes): if not graph.has_edge(u, v) or u == v: obj = 1 if u == v else 0 x[u, v] = model.addVar(lb=0, ub=1, obj=obj, name=f"x_{u}_{v}", vtype="B") # add constraint (8) for v in graph.nodes: non_adjacent_vertices = (graph.nodes - graph.neighbors(v)).union({v}) model.addCons( scip.quicksum(x[u, v] for u in non_adjacent_vertices) >= 1) # add constraint (9) for u in graph.nodes: non_adjacent_vertices = graph.nodes - graph.neighbors(u) - {u} for v, w in graph.edges: if v in non_adjacent_vertices and w in non_adjacent_vertices: model.addCons(x[u, v] + x[u, w] <= x[u, u]) model.setMinimize() return model
def hybrid_partial_ordering(graph, color_upperbound, name="Hybrid Partial Ordering Graph Coloring"): """ Generates a graph coloring ILP formulation (POP2) as described in [1]. Parameters ---------- graph: networkx graph Input graph color_upperbound: int Maximum number of colors to use name: str Name of the model Returns ------- model: scip.Model A pyscipopt model of the generated instance References ---------- .. [1] A.Jabrayilov, P.Mutzel "New Integer Linear Programming Models for the Vertex Coloring Problem" """ model = scip.Model(name) graph = nx.convert_node_labels_to_integers(graph, first_label=0) colors = list(range(color_upperbound)) # add variables and their cost x = {(vertex, color): model.addVar(lb=0, ub=1, obj=0, name=f"x_{vertex}_{color}", vtype="B") for vertex, color in itertools.product(graph.nodes, colors)} model, y, z = _partial_ordering_base_model(graph, colors, model) # add constraint (14) for v, c in itertools.product(graph.nodes, colors): model.addCons(x[v, c] == 1 - (y[c, v] + z[v, c])) # add constraint (23) for (u, v), c in itertools.product(graph.edges, colors): model.addCons(x[u, c] + x[v, c] <= 1) return model
def test_presolve(): m = scip.Model() m.hideOutput() add_instance(m) m.setIntParam('display/verblevel', 0) init_scip_params(m, seed=42) m.setIntParam('timing/clocktype', 2) m.setRealParam('limits/time', 120) m.setParam('limits/nodes', 1) print(len(m.getConss()), len(m.getVars())) m.presolve() print(len(m.getConss()), len(m.getVars(transformed=True))) print(len(m.getConss()), m.getVars(transformed=True)) m.writeProblem('/tmp/model.cip', True)
def _import_problem(self): import pyscipopt as scip # Create a problem instance. self.int = scip.Model() # Import variables. for variable in self.ext.variables.values(): self._import_variable(variable) # Import constraints. for constraint in self.ext.constraints: self._import_constraint(constraint) # Set objective. self._import_objective()
def test2(): m = get_model() m.hideOutput() add_instance(m) m.presolve() orig_vars = list( map(lambda v: v.name.lstrip('t_'), m.getVars(transformed=True))) m = scip.Model(sourceModel=m, origcopy=True) m.hideOutput() m.setIntParam('display/verblevel', 0) init_scip_params(m, seed=42) m.setIntParam('timing/clocktype', 2) m.setRealParam('limits/time', 120) m.setParam('limits/nodes', 1) c_f, e_f, v_f = get_features_from_scip_model(m) assert v_f['var_names'] == orig_vars, (orig_vars, v_f['var_names'])
def set_packing(m, n, values, nonzero_vars_for_constraint, name="Set Packing"): """ Generates a set packing formulation following [1]. Parameters ---------- m: int Number of constraints n: int Number of elements values: list[int] Value you get for packing each item nonzero_vars_for_constraint: list[list[int]] Nonzero variables list for each constraint name: str Name of the model Returns ------- model: scip.Model A pyscipopt model of the generated instance References ---------- .. [1] Yu Yang, Natashia Boland, Bistra Dilkina, Martin Savelsbergh, "Learning Generalized Strong Branching for Set Covering, Set Packing, and 0-1 Knapsack Problems", 2020. """ model = scip.Model(name) # add variables and their cost vars = [] for i in range(n): var = model.addVar(lb=0, ub=1, obj=values[i], name=f"v_{i}", vtype="B") vars.append(var) # add constraints for i in range(m): nonzero_vars = (vars[j] for j in nonzero_vars_for_constraint[i]) model.addCons(scip.quicksum(nonzero_vars) <= 1) model.setMaximize() return model
def solve(branches): model = scip.Model() x = {} for m, branch in enumerate(branches): configurations = branch.configurations for n in range(len(configurations)): x[m, n] = model.addVar(f'x[{m}, {n}]', vtype='B') # Only one configuration from each branch model.addCons( scip.quicksum(x[m, n] for n in range(len(configurations))) == 1) model.setObjective( scip.quicksum(x[m, n] * branch.configurations[n].tangling for m, branch in enumerate(branches) for n in range(len(branch.configurations))), 'minimize') #model.hideOutput() model.optimize() for m, branch in enumerate(branches): configurations = branch.configurations for n in range(len(configurations)): print(branch.configurations[n].tangling, model.getVal(x[m, n]))
def naive(graph): model = scip.Model("Naive MaxCut") node_variables = {} for v in graph.nodes(): node_variables[v] = model.addVar(lb=0, ub=1, obj=0, name=str(v), vtype="B") edge_variables = {} all_non_negative = True for u, v, d in graph.edges(data=True): edge_name = naming.undirected_edge_name(u, v) weight = d["weight"] edge_variables[edge_name] = model.addVar(lb=0, ub=1, obj=weight, name=edge_name, vtype="B") if weight < 0: all_non_negative = False model.setMaximize() for u, v, d in graph.edges(data=True): edge_name = naming.undirected_edge_name(u, v) model.addCons(node_variables[u] + node_variables[v] + edge_variables[edge_name] <= 2) model.addCons(-node_variables[u] - node_variables[v] + edge_variables[edge_name] <= 0) if not all_non_negative: model.addCons(node_variables[u] - node_variables[v] - edge_variables[edge_name] <= 0) model.addCons(-node_variables[u] + node_variables[v] - edge_variables[edge_name] <= 0) return (node_variables, edge_variables), model
def set_covering(graph, subsets, name="Set Covering Graph Coloring"): """ Generates a graph coloring ILP formulation (COV) as described in [1]. Parameters ---------- graph: networkx graph Input graph subsets: Iterable of sets Independent Sets of nodes name: str Name of the model Returns ------- model: scip.Model A pyscipopt model of the generated instance References ---------- .. [1] A.Jabrayilov, P.Mutzel "New Integer Linear Programming Models for the Vertex Coloring Problem" """ model = scip.Model(name) graph = nx.convert_node_labels_to_integers(graph, first_label=0) x = { tuple(s): model.addVar(lb=0, ub=1, obj=1, name=f"x_{s}", vtype="B") for s in subsets } for v in graph.nodes: model.addCons( scip.quicksum(x[tuple(s)] for s in subsets if v in s) >= 1) model.setMinimize() return model
def combinatorial_auction(bids, n_dummy_items, n_items, name="Combinatorial Auction"): model = scip.Model(name) # add vars bids_per_item = [[] for item in range(n_items + n_dummy_items)] x = [] for i, bid in enumerate(bids): bundle, price = bid var = model.addVar(lb=0, ub=1, obj=price, name=f"x_{i + 1}", vtype="B") x.append(var) for item in bundle: bids_per_item[item].append(i) # add constraints for item_bids in bids_per_item: if item_bids: vars = (x[i] for i in item_bids) model.addCons(scip.quicksum(vars) <= 1) model.setMaximize() return model
def clique_independent_set(graph, name="Clique Independent Set"): """ Generates an independent set instance according to [1, 4.6.4]. Parameters ---------- graph: nx.Graph Networkx undirected graph name: str Name of the generated model Returns ------- model: scip.Model A pyscipopt model of the generated instance References ---------- .. [1] David Bergman, Andre A. Cire, Willem-Jan Van Hoeve, and John Hooker. Decision diagrams for optimization. Springer, 2016. """ graph = nx.relabel.convert_node_labels_to_integers(graph) model = scip.Model(name) cliques = _get_cliques(graph) vars = { str(node): model.addVar(lb=0, ub=1, obj=1, name=str(node), vtype="B") for node in graph.nodes } for clique in cliques: model.addCons(scip.quicksum(vars[str(node)] for node in clique) <= 1) model.setMaximize() return model
def knapsack(weights, profits, capacity, name="Knapsack"): """Generates a knapsack MIP formulation. Parameters: ---------- profits: list[float] List of profits of each item weights: list[float] List of weights of each item capacity: float Capacity of knapsack Returns ------- model: scip.Model A pyscipopt model of the generated instance """ assert len(weights) == len(profits) assert capacity >= 0 assert all(w >= 0 for w in weights) assert all(p >= 0 for p in profits) model = scip.Model(name) # add variables and their cost variables = [ model.addVar(lb=0, ub=1, obj=profit, vtype="B") for profit in profits ] # add constraints model.addCons( scip.quicksum( weight * variable for weight, variable in zip(weights, variables)) <= capacity) model.setMaximize() return model
def test_scip_features(): m = scip.Model() m.hideOutput() add_instance(m) m.setIntParam('display/verblevel', 0) init_scip_params(m, seed=42) m.setIntParam('timing/clocktype', 2) m.setRealParam('limits/time', 120) m.setParam('limits/nodes', 1) m.presolve() orig_vars = list(m.getVars(transformed=True)) l = [] branchrule = SamplingAgent(seed=42, out=l) m.includeBranchrule(branchrule=branchrule, name="Sampling branching rule", desc="", priority=666666, maxdepth=1, maxbounddist=1) m.setBoolParam('branching/vanillafullstrong/integralcands', True) m.setBoolParam('branching/vanillafullstrong/scoreall', True) m.setBoolParam('branching/vanillafullstrong/collectscores', True) m.setBoolParam('branching/vanillafullstrong/donotbranch', True) m.setBoolParam('branching/vanillafullstrong/idempotent', True) # m.presolve() m.optimize() # m.constructLP() assert len(l) == 1 c_f, e_f, v_f = l[0]['state'] # assert v_f['var_names'] == orig_vars, (orig_vars, v_f['var_names']) m.freeProb()
def partial_ordering(graph, color_upperbound, name="Partial Ordering Graph Coloring"): """ Generates a graph coloring ILP formulation (POP) as described in [1]. Parameters ---------- graph: networkx graph Input graph color_upperbound: int Maximum number of colors to use name: str Name of the model Returns ------- model: scip.Model A pyscipopt model of the generated instance References ---------- .. [1] A.Jabrayilov, P.Mutzel "New Integer Linear Programming Models for the Vertex Coloring Problem" """ model = scip.Model(name) graph = nx.convert_node_labels_to_integers(graph, first_label=0) colors = list(range(color_upperbound)) model, y, z = _partial_ordering_base_model(graph, colors, model) # add constraint (20) for (u, v), c in itertools.product(graph.edges, colors[:-1]): model.addCons(y[c, u] + z[u, c] + y[c, v] + z[v, c] >= 1) return model
def staff(self): """ Produce the staffing /workforce schedule. Minimize workers needed, given the constraints Note that the problem can be essentially decompose by area as we assume that workers don't cross areas in one day (and possibly the entire week?). Step 1 [DONE]: * Routes given, just assign the number of workers depending on how much waste we expect? * In fact, one could consider each area to be a route and it will give a number of people assigned to an area, assuming they can then determine and divide the routes among themselves. * Alternatively, could determine the routes by just clustering toilets, putting together toilets so that we just about fill up Worker's carry limit per route * Constraints on waste lifted/carried (assume the crew leader can lift and then each of the workers) * Use one worker at most 5 days a week? z_crd: collector c assigned to route r available on day d. A limited number of workers? gamma_td: toilet t should be collected on day d gamma_rd: route r should be collected on day d. gamma_rd = max_t gamma_td * chi_rt. If a route coincides with an area, then can have gamma_rd = 1 (assuming every area has some toilets to be collected?) lambda_rd: Collector lower bound per route... normally 2, 3 for handcarts chi_rt: toilet t lies on route r w_rd: weight (predicted) on route r on day d. w_rd = sum_t chi_rt * w_td W: weight limit per worker per day min_{z_crd} sum z_crd sum_rd z_crd <= 5 forall c sum_c z_crd >= 2*gamma_rd forall r,d #Assign 2+ workers if a route is to be collected. Needs to have at least 2, we know... for the wheelbarrow routes, need to have at least three? sum_c z_crd * W >= w_rd forall r, d Step 2: * Upper bound on workers and a penalty for uncollectable toilets (flexible workforce vs toilet overflows) * Extra constraints on worker unavailability Step 3: #TODO * "Routing" within areas. Consider just aerial distances between toilets. The thing is, we could consolidate some routes when we only collect occasionally. * Collection window constraints (because the waste accumulates when?) * Constraints on the distance traveled by a worker Step 4: Other constraints/objectives * Training (have workers rotate through different areas) """ if self.schedule is None or self.waste is None: self.log.warning( "The staffing routine has not received scheduling or waste prediction data. The workforce schedule will not be created." ) return ([None, None, None]) self.preprocess() s = scip.Model("Staffing") s.hideOutput() s.setMinimize() #Vars: z_crd: collector c assigned to route r for day d assign_vars = {} for c in range(0, self.parameters['N']): for i_r, r in enumerate(self.routes): for d in self.next_days: v_name = 'z' + str(c) + str(i_r) + str(d) #This also handles the objective function... assign_vars[c, r, d] = s.addVar(v_name, vtype='B', obj=1.0) #Constraints for c in range(0, self.parameters['N']): #1) Collector workday limits w_name = 'Worker_' + str(c) coeffs_worker = { assign_vars[(c, r, d)]: 1 for d in self.next_days for i_r, r in enumerate(self.routes) } s.addCons(coeffs=coeffs_worker, rhs=self.parameters['D'], name=w_name) for d in self.next_days: for i_r, r in enumerate(self.routes): #2) Collector weight limits on routes. For each route: assign 2+ workers and also more than the predicted weight per the route #3) Assign n+ workers on the route route_weight_name = 'Route_Weight_' + str(i_r) + "_" + str(d) route_collector_minimum_name = 'Route_Minimum_' + str( i_r) + "_" + str(d) coeffs_weight = { assign_vars[(c, r, d)]: 1 for c in range(0, self.parameters['N']) } #sum_c z_crd >= w_rd / W coeffs_collectors = { assign_vars[(c, r, d)]: 1 for c in range(0, self.parameters['N']) } weight_limit = self.is_the_route_collected_on_day[ d, r] * self.route_waste[d, r] / self.parameters['W'] collect_limit = self.is_the_route_collected_on_day[ d, r] * self.parameters['NR'] s.addCons(coeffs=coeffs_weight, lhs=weight_limit, rhs=None, name=route_weight_name) s.addCons(coeffs=coeffs_collectors, lhs=collect_limit, rhs=None, name=route_collector_minimum_name) #Write down the formulation to make sure it was formulated correctly. #s.writeProblem() #Objective function #Done: See in Vars s.optimize() vars = s.getVars() #for v in vars[0:50]: # print(s.getVal(v)) roster = self.createRoster(s, assign_vars) self.log.debug(s.printStatistics()) return (roster, s, assign_vars)
# Dict {method_name:[list_of_primal_integral]} # agg_integral_stats = {'internal':[],'MCTS_vanilla':[], 'MCTS_hot_start':[]} agg_integral_stats = {x['type']: [] for x in branching_policies} # Same, but each containing the raw info (nb lp solves and feas solutions) raw_stats = { 'internal': [], 'MCTS_coef_diving': [], 'MCTS_coef_diving': [] } for instance in instances: for policy in branching_policies: brancher = PolicyBranching(policy) # Model will be initialized m = scip.Model() # print(a) m.setIntParam('display/verblevel', 0) m.readProblem(f"{instance['path']}") m.includeEventhdlr(SolvingStatsRecorder(brancher.solving_stats), "SolvingStatsRecorder", "") # AGGRESSIVE MODE FOR INTERNAL BRANCHING if policy['type'] == 'internal': utilities.init_scip_params(m, seed=seed, heuristics='agg',
def run_episode(self, instance, name, policy, scip_seed, cutoff_value, scip_limits, scip_params, verbose, brancher_name='SCIPEvalBrancher'): """ :param instance: str, pathway to instance.mps.gz :param name: str, name of the instance (w/o extension) :param policy: str, SCIP branching rule to be used :param scip_seed: int, SCIP solver seed :param cutoff_value: float, cutoff :param scip_limits: dict, specifying SCIP parameter limits :param scip_params: dict, specifying SCIP parameter setting :param verbose: bool, verbosity :param brancher_name: str, name of the brancher to be defined :return: exp_dict: dict, containing basic statistics on the experiment (run) """ print("\nRunning SCIP evaluation on instance {}".format(name)) m = scip.Model() # set static solver setting (scip seed and cutoff are set below) utilities.init_params(m, scip_limits, scip_params) # set scip parameters as needed (wrt the current episode setting) m.setBoolParam('randomization/permutevars', True) m.setIntParam('randomization/permutationseed', scip_seed) # SCIP default at 0 m.readProblem(instance) if scip_params['cutoff']: assert cutoff_value is not None m.setObjlimit(cutoff_value) brancher = SCIPEvalBrancher(model=m, policy=policy, verbose=verbose) m.includeBranchrule(brancher, name=brancher_name, desc="bla", priority=999999, maxdepth=-1, maxbounddist=1) # optimize, i.e., perform the solve t0 = time.time() t0_process = time.process_time() m.optimize() t1_process = time.process_time() t1 = time.time() print( "\tInstance {}. SCIP time: {} (wall-clock: {}). Nnodes: {}. FairNNodes: {}" .format(name, m.getSolvingTime(), t1 - t0, m.getNNodes(), m.getFairNNodes(bytes(brancher_name, 'utf-8')))) # store episode_data exp_dict = { 'name': name, 'policy': policy, 'seed': scip_seed, 'nnodes': m.getNNodes(), 'fair_nnodes': m.getFairNNodes(bytes(brancher_name, 'utf-8')), # needs bytes encoding 'nnodes_left': m.getNNodesLeft(), 'nLP_iterations': m.getNLPIterations(), 'max_depth': m.getMaxDepth(), 'status': m.getStatus(), 'gap': m.getGap(), 'primal_bound': m.getPrimalbound(), 'dual_bound': m.getDualbound(), 'primaldualintegral': m.getPrimalDualIntegral(), 'scip_solve_time': m.getSolvingTime(), 'scip_presolve_time': m.getPresolvingTime(), 'opt_time_process': t1_process - t0_process, 'opt_time_wallclock': t1 - t0, 'nnodes_list': brancher.nnodes_list, 'nnodesleft_list': brancher.nnodesleft_list, } m.freeProb() return exp_dict
def layout_paths(self): m = scip.Model()