Example #1
0
 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
Example #2
0
 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
Example #3
0
 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]
Example #4
0
 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
Example #5
0
 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
Example #6
0
    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
Example #7
0
 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
Example #8
0
    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
Example #9
0
 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
Example #10
0
 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
Example #11
0
    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
Example #12
0
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
Example #13
0
 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
Example #14
0
    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
Example #15
0
    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
Example #16
0
    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
Example #17
0
 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
Example #18
0
 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
Example #19
0
    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
Example #20
0
    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
Example #21
0
 def branch(self):
     yield pybnb.Node()
     yield pybnb.Node()
     yield pybnb.Node()
     yield pybnb.Node()
     yield pybnb.Node()
Example #22
0
    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