def branch(self): child = pybnb.Node() child.state = (self._xL, self._xM, self._fL_cached, self._fM_cached) yield child child = pybnb.Node() child.state = (self._xM, self._xU, self._fM_cached, self._fU_cached) yield child
def branch(self): # note that the branch method should never be called # with a path of length N as the objective and bound # converge exactly in that case. assert len(self._path) < self._N assert self._cost is not None u = self._path[-1] candidates = numpy.flatnonzero(self._dist[u, :] != numpy.inf).tolist() if len(candidates) == 0: # this path is infeasible, so return a dummy # child to indicate that child = pybnb.Node() child.bound = pybnb.inf child.objective = pybnb.inf yield child else: for v in candidates: child = pybnb.Node() child.state = ( self._path + [v], self._dist.copy(), self._cost + self._dist[u][v], None, ) yield child
def branch(self): if self._last_bound_was_feasible: return () xL, xU = self._model.x.bounds yL, yU = self._model.y.bounds xdist = float(xU - xL) ydist = float(yU - yL) branch_var = None if xdist > ydist: branch_var = self._model.x L = xL U = xU else: branch_var = self._model.y L = yL U = yU # branch mid = 0.5 * (L + U) left = pybnb.Node() branch_var.bounds = (L, mid) self.save_state(left) right = pybnb.Node() branch_var.bounds = (mid, U) self.save_state(right) # reset the variable bounds branch_var.bounds = (L, U) return [left, right]
def branch(self): child = pybnb.Node() child.state = (self._L, self._M, self._L1D, self._U1D, self._fT) yield child child = pybnb.Node() child.state = (self._M, self._U, self._L1D, self._U1D, self._fT) yield child
def branch(self): xL, xU = self._xL, self._xU xM = 0.5 * (xL + xU) child = pybnb.Node() child.state = (xL, xM) yield child child = pybnb.Node() child.state = (xM, xU) yield child
def _branch_x(self): N = range(len(self.W)) orig_bounds = pmo.ComponentMap() orig_bounds.update((yi, yi.bounds) for yi in self.model.y.components()) orig_bounds.update((xij, xij.bounds) for xij in self.model.x.components()) # do some simple preprocessing to reduce # the branch space for i in N: assert self.model.y[i].lb <= self.model.y[i].ub assert self.model.y[i].lb in (0,1) assert self.model.y[i].ub in (0,1) if self.model.y[i].ub == 0: for j in N: assert self.model.x[i,j].lb == 0 self.model.x[i,j].ub = 0 unassigned_items = [] for j in N: assigned = sum(self.model.x[i,j].lb for i in N) if assigned == 0: unassigned_items.append(j) else: assert assigned == 1 for i in N: if self.model.x[i,j].lb == 0: self.model.x[i,j].ub = 0 # find an item that is not already fixed into a bin bv = None for j in unassigned_items: for i in N: if (self.model.x[i,j].lb == 0) and \ (self.model.x[i,j].ub == 1): bv = self.model.x[i,j] break if bv is not None: break else: #pragma:nocover return () assert bv is not None children = [pybnb.Node(), pybnb.Node()] bv.lb = bv.ub = 1 self.save_state(children[0]) bv.lb = bv.ub = 0 self.save_state(children[1]) # reset bounds for var in orig_bounds: var.bounds = orig_bounds[var] return children
def branch(self): xL, xU = self._xL, self._xU if (xU - xL) <= self._branching_abstol: return mid = 0.5 * (xL + xU) child = pybnb.Node() child.state = (xL, mid) yield child child = pybnb.Node() child.state = (mid, xU) yield child
def _branch_y(self): N = range(len(self.W)) for i in N: yi = self.model.y[i] assert yi.lb in (0,1), \ str(yi.name)+" "+str(yi.bounds) assert yi.ub in (0,1), \ str(yi.name)+" "+str(yi.bounds) if yi.lb == 0: if yi.ub == 1: break else: assert yi.ub == 0 else: assert yi.lb == 1 assert yi.lb == yi.ub else: # there is no branching left to do return () for k in range(i,len(self.W)): assert self.model.y[k].lb == 0 assert self.model.y[k].ub in (0,1) orig_bounds = pmo.ComponentMap() orig_bounds.update((yi, yi.bounds) for yi in self.model.y.components()) orig_bounds.update((xij, xij.bounds) for xij in self.model.x.components()) children = [pybnb.Node(), pybnb.Node()] # first branch: fix this bin on self.model.y[i].lb = self.model.y[i].ub = 1 self.save_state(children[0]) # second branch: fix this bin off, as well as all # bins following it for k in range(i,len(self.W)): self.model.y[k].lb = self.model.y[k].ub = 0 for j in N: assert self.model.x[k,j].lb == 0 self.model.x[k,j].ub = 0 self.save_state(children[1]) # reset bounds for var in orig_bounds: var.bounds = orig_bounds[var] return children
def branch(self): i = self._heap_index assert 0 <= i <= self._max_heap_index left_index = 2 * i + 1 if left_index <= self._max_heap_index: child = pybnb.Node() child.state = left_index yield child right_index = 2 * i + 2 if right_index <= self._max_heap_index: child = pybnb.Node() child.state = right_index yield child
def branch(self): i = self._heap_idx assert i >= 0 assert i < len(self._bound_bheap) left_idx = 2 * i + 1 if (left_idx < len(self._bound_bheap)) and \ (self._bound_bheap[left_idx] is not None): child = pybnb.Node() child.state = left_idx yield child right_idx = 2 * i + 2 if (right_idx < len(self._bound_bheap)) and \ (self._bound_bheap[right_idx] is not None): child = pybnb.Node() child.state = right_idx yield child
def branch(self): for i in [ OperacoesPossiveis.SWAP, OperacoesPossiveis.DELETE, OperacoesPossiveis.NOP, OperacoesPossiveis.BACK_POS ]: if (self.lst.custo_total) <= self.max_operacoes: p = len(self.lst.movimentos) lst_cp = deepcopy(self.lst) if lst_cp.adiciona_movimento(i): child = pybnb.Node() if (lst_cp.is_finished()): if lst_cp.is_same() == False: lst_cp.penaliza() if self.custo > lst_cp.custo_total: lista_ops = Singleton() if lista_ops.lst == None: lista_ops.lst = lst_cp elif lst_cp.custo_total < lista_ops.lst.custo_total: lista_ops.lst = lst_cp child.state = (lst_cp, self._xL, self._xU, self.custo) yield child else: lst_cp.movimentos.clear() lst_cp.movimentos = None lst_cp = None else: pass
def run_solve_loop(dist, problem, solver): """Solves the TSP using a combination of branch-and-bound and local heuristics.""" # The solve loop below does the following: # (1) Solve the tsp problem using a nested # branch-and-bound strategy until any improvement # to the previous best cost is made (objective_stop) # (2) If the solution status from (1) is feasible, run # the 2-opt heuristic to attempt to improve the # solution. For any other solution status (e.g., # optimal, infeasible), exit the solve loop. # (3) Go to step (1), initializing the solve with the # remaining queue items from the previous solve # (initialize_queue), a potentially new best node # created with the solution returned from the 2-opt # heuristic (best_node), and a new objective_stop # value of one less than the current best cost (so # we can go to step (2) if a new solution is # found). objective_stop = pybnb.inf queue = None best_node = None while 1: results = solver.solve( pybnb.futures.NestedSolver(problem, queue_strategy="depth", track_bound=False, time_limit=1), queue_strategy="depth", initialize_queue=queue, best_node=best_node, objective_stop=objective_stop, ) if (results.solution_status == "feasible") and ( results.termination_condition != "interrupted"): assert results.best_node is not None assert results.tour is not None cost, route = run_2opt(dist, results.tour["cost"], results.tour["route"]) if cost < results.tour["cost"]: if solver.is_dispatcher: print("Local heuristic improved best tour:") print(" - cost: " + str(cost)) print(" - route: " + str(route)) best_node = pybnb.Node() best_node.objective = cost best_node.state = (route[:-1], ) objective_stop = cost - 1 queue = solver.save_dispatcher_queue() else: if solver.is_dispatcher: print("Terminating the solve loop.") print("Final solution status: " + str(results.solution_status)) print("") break return results
def branch(self): if (self._bound > self.solution) and (self.last_node > self.node + 1): self.stash.append([self.node + 1, False]) self.stash.append([self.node + 1, True]) self.node, self.value = self.stash.pop() self.partition[str(self.node)] = self.value node = pybnb.Node() node.state = self.partition yield node
def branch(self): i, j = self.path[-1] if (i == self.m - 1) and (j < self.n - 1): child = pybnb.Node() child.state = self.path + [(i, j + 1)] yield child elif (i < self.m - 1) and (j == self.n - 1): child = pybnb.Node() child.state = self.path + [(i + 1, j)] yield child elif (i < self.m - 1) and (j < self.n - 1): nodes_update = [(i + 1, j + 1), (i, j + 1), (i + 1, j)] for v in nodes_update: child = pybnb.Node() child.state = self.path + [v] yield child
def branch(self): i, j = self.path[-1] # branching randomization if self.allow_randomization: k = np.random.randint(self.min_step, self.max_step) else: k = 1 if (i == self.m - 1) and (j < self.n - 1): if j + k >= self.n - 1: k = 1 child = pybnb.Node() child.state = self.path + [(i, j + k)] yield child elif (i < self.m - 1) and (j == self.n - 1): if i + k >= self.m - 1: k = 1 child = pybnb.Node() child.state = self.path + [(i + k, j)] yield child elif (i < self.m - 1) and (j < self.n - 1): if i + k >= self.m - 1: k_i = 1 else: k_i = k if j + k >= self.n - 1: k_j = 1 else: k_j = k nodes_update = [(i + k_i, j + k_j), (i, j + k_j), (i + k_i, j)] for v in nodes_update: child = pybnb.Node() child.state = self.path + [v] yield child
def branch(self): i, j = self.path[-1] if (i == self.m - 1) and (j < self.n - 1): child = pybnb.Node() child.state = self.path + [(i, j + 1)] # record edges and nodes if self.record_path: self.nodes.append(tuple(child.state)) self.edges.append((tuple(self.path), tuple(child.state))) yield child elif (i < self.m - 1) and (j == self.n - 1): child = pybnb.Node() child.state = self.path + [(i + 1, j)] # record edges and nodes if self.record_path: self.nodes.append(tuple(child.state)) self.edges.append((tuple(self.path), tuple(child.state))) yield child elif (i < self.m - 1) and (j < self.n - 1): nodes_update = [(i + 1, j + 1), (i, j + 1), (i + 1, j)] for v in nodes_update: child = pybnb.Node() child.state = self.path + [v] # record edges and nodes if self.record_path: self.nodes.append(tuple(child.state)) self.edges.append((tuple(self.path), tuple(child.state))) yield child
def branch(self): # note that the branch method should never be called # with a path of length N as the objective and bound # converge exactly in that case. assert len(self._path) < self._N u = self._path[-1] visited = set(self._path) for v in range(self._N): # dist[u][v] == inf means no edge if (self._dist[u][v] != pybnb.inf) and (v not in visited): assert self._dist[u][v] != 0 child = pybnb.Node() child.state = (self._path + [v], ) yield child
def branch(self): assert len(self._choices) < self._n for level in range(self._level, self._n): i = self._sorted_order[level] child_weight = self._weight + self._w[i] if child_weight <= self._W: child_value = self._value + self._v[i] child = pybnb.Node() # we know the child objective value, so # assign it to the child node rather than # letting it inherit the parent objective # value (this may be useful for queue # prioritization) child.objective = child_value child.state = (child_weight, child_value, level + 1, self._choices + [i]) yield child
def get_init_node(self): # def twosat_solver(matrix, cluster_rows=False, cluster_cols=False, only_descendant_rows=False, # na_value=None, leave_nas_if_zero=False, return_lb=False, heuristic_setting=None, # n_levels=2, eps=0, compact_formulation=True): # pass node = pybnb.Node() solution, model_time, opt_time, lb = twosat_solver( self.matrix, cluster_rows=self.cluster_rows, cluster_cols=self.cluster_cols, only_descendant_rows=self.only_descendant_rows, na_value=self.na_value, leave_nas_if_zero=True, return_lb=True, heuristic_setting=None, n_levels=self.n_levels, eps=self.eps, compact_formulation=self.compact_formulation, ) self._times["model_preparation_time"] += model_time self._times["optimization_time"] += opt_time nodedelta = sp.lil_matrix( np.logical_and(solution == 1, self.matrix == 0)) node_na_delta = sp.lil_matrix( np.logical_and(solution == 1, self.matrix == self.na_value)) node.state = ( nodedelta, True, None, nodedelta.count_nonzero(), self.get_state(), node_na_delta, ) node.queue_priority = self.get_priority(till_here=-1, this_step=-1, after_here=-1, icf=True) self.next_lb = lb return node
def test_RangeReductionProblem(self): class Junk(PyomoProblem): def __init__(self): self._pyomo_model = pmo.block() self._pyomo_model.x = pmo.variable() self._pyomo_model.c = pmo.constraint() self._pyomo_model.o = pmo.objective() self._pyomo_model_objective = self._pyomo_model.o super(Junk, self).__init__() @property def pyomo_model(self): return self._pyomo_model @property def pyomo_model_objective(self): return self._pyomo_model_objective junk = Junk() assert junk.pyomo_model_objective is junk.pyomo_model.o assert junk.pyomo_object_to_cid[junk.pyomo_model] == () assert junk.pyomo_object_to_cid[junk.pyomo_model.x] == ("x", ) assert junk.pyomo_object_to_cid[junk.pyomo_model.c] == ("c", ) assert junk.pyomo_object_to_cid[junk.pyomo_model.o] == ("o", ) assert junk.cid_to_pyomo_object[()] is junk.pyomo_model assert junk.cid_to_pyomo_object[("x", )] is junk.pyomo_model.x assert junk.cid_to_pyomo_object[("c", )] is junk.pyomo_model.c assert junk.cid_to_pyomo_object[("o", )] is junk.pyomo_model.o junk.pyomo_model.r = pmo.constraint() junk.update_pyomo_object_cids() assert junk.pyomo_object_to_cid[junk.pyomo_model.r] == ("r", ) assert junk.cid_to_pyomo_object[("r", )] is junk.pyomo_model.r rr_junk = RangeReductionProblem(junk) assert rr_junk._best_objective == pybnb.inf node_ = pybnb.Node() node_.objective = 1 rr_junk.notify_new_best_node(node_, False) assert rr_junk._best_objective == 1 node_.objective = 2 rr_junk.notify_new_best_node(node_, False) assert rr_junk._best_objective == 2
def branch(self): yield pybnb.Node() yield pybnb.Node() yield pybnb.Node() yield pybnb.Node() yield pybnb.Node()
def branch(self): if self.icf: return need_for_new_nodes = True if self.node_to_add is not None: newnode = self.node_to_add self.node_to_add = None if (newnode.state[0].count_nonzero() == self.bound_value ): # current_obj == lb => no need to explore need_for_new_nodes = False assert ( newnode.queue_priority is not None ), "Right before adding a node its priority in the queue is not set!" yield newnode if need_for_new_nodes: p, q = self.colPair nf01 = None current_matrix = self.get_current_matrix() for col, colp in [(q, p), (p, q)]: node = pybnb.Node() nodedelta = copy.deepcopy(self.delta) node_na_delta = copy.deepcopy(self.delta_na) col1 = np.array(current_matrix[:, col], dtype=np.int8).reshape(-1) col2 = np.array(current_matrix[:, colp], dtype=np.int8).reshape(-1) rows01 = np.nonzero(np.logical_and(col1 == 0, col2 == 1))[0] rows21 = np.nonzero( np.logical_and(col1 == self.na_value, col2 == 1))[0] if len(rows01) + len( rows21) == 0: # nothing has changed! Dont add new node continue nodedelta[rows01, col] = 1 nf01 = nodedelta.count_nonzero() if self.has_na: node_na_delta[rows21, col] = 1 new_bound = self.boundingAlg.get_bound( nodedelta, node_na_delta) else: new_bound = self.boundingAlg.get_bound(nodedelta) node_icf, nodecol_pair = None, None extra_info = self.boundingAlg.get_extra_info() if extra_info is not None: if "icf" in extra_info: node_icf = extra_info["icf"] if "one_pair_of_columns" in extra_info: nodecol_pair = extra_info["one_pair_of_columns"] if node_icf is None: x = get_effective_matrix(self.I, nodedelta, node_na_delta) ( node_icf, nodecol_pair, ) = is_conflict_free_gusfield_and_get_two_columns_in_coflicts( x, self.na_value) node_bound_value = max(self.bound_value, new_bound) node.state = ( nodedelta, node_icf, nodecol_pair, node_bound_value, self.boundingAlg.get_state(), node_na_delta, ) node.queue_priority = self.boundingAlg.get_priority( till_here=nf01 - len(rows01), this_step=len(rows01), after_here=new_bound - nf01, icf=node_icf, ) assert ( node.queue_priority is not None ), "Right before adding a node its priority in the queue is not set!" yield node