Пример #1
0
    def listen(self, root=0):
        """Listen for requests to run range reduction. All
        processes within the communicator, except for the
        root process, should call this method.

        Parameters
        ----------
        root : int
            The rank of the process acting as the
            root. The root process should not call this
            function.
        """
        assert self._comm.size > 1
        assert self._comm.rank != root
        orig = Node()
        self.save_state(orig)
        node = Node()
        try:
            data = array.array('d', [0]) * 3
            self._comm.Bcast([data, mpi4py.MPI.DOUBLE], root=root)
            again = bool(data[0])
            self._best_objective = float(data[1])
            while again:
                node.state = self._comm.bcast(node.state, root=root)
                self.load_state(node)
                self._tighten_bounds()
                self._comm.Bcast([data, mpi4py.MPI.DOUBLE], root=root)
                again = bool(data[0])
                self._best_objective = float(data[1])
        finally:
            self.load_state(orig)
Пример #2
0
def _logging_redirect_check(comm):
    opt = Solver(comm=comm)
    p = DummyProblem()
    log = logging.Logger(None, level=logging.WARNING)
    log.addHandler(_RedirectHandler(opt._disp))
    if opt.is_dispatcher:
        assert (comm is None) or (comm.rank == 0)
        root = Node()
        p.save_state(root)
        root.objective = p.infeasible_objective()
        root.bound = p.unbounded_objective()
        initialize_queue = DispatcherQueueData(nodes=[root],
                                               worst_terminal_bound=None,
                                               sense=p.sense())
        out = StringIO()
        formatter = logging.Formatter("[%(levelname)s] %(message)s")
        opt._disp.initialize(
            p.infeasible_objective(),
            None,
            initialize_queue,
            "bound",
            ConvergenceChecker(p.sense()),
            None,
            None,
            None,
            True,
            get_simple_logger(console=True,
                              stream=out,
                              level=logging.DEBUG,
                              formatter=formatter),
            0.0,
            True,
        )
        log.debug("0: debug")
        log.info("0: info")
        log.warning("0: warning")
        log.error("0: error")
        log.critical("0: critical")
        if (comm is not None) and (comm.size > 1):
            opt._disp.serve()
    else:
        assert comm is not None
        if comm.size > 1:
            for i in range(1, comm.size):
                if comm.rank == i:
                    log.debug(str(comm.rank) + ": debug")
                    log.info(str(comm.rank) + ": info")
                    log.warning(str(comm.rank) + ": warning")
                    log.error(str(comm.rank) + ": error")
                    log.critical(str(comm.rank) + ": critical")
                opt.worker_comm.Barrier()
            if opt.worker_comm.rank == 0:
                opt._disp.stop_listen()
    if comm is not None:
        comm.Barrier()
    if opt.is_dispatcher:
        assert ("\n".join(
            out.getvalue().splitlines()[7:])) == _get_logging_baseline(
                comm.size if comm is not None else 1)
Пример #3
0
 def put_get(self, item):
     bound = Node._extract_bound(item)
     if self._sense == minimize:
         priority = -bound
     else:
         priority = bound
     Node._insert_queue_priority(item, priority)
     return self._queue.put_get(item, priority)
Пример #4
0
def _new_child(node):
    child = Node()
    child.objective = node.objective
    child.bound = node.bound
    child.tree_depth = node.tree_depth + 1
    assert child.queue_priority is None
    assert child.state is None
    return child
Пример #5
0
 def put_get(self, item):
     objective = Node._extract_objective(item)
     if self._sense == minimize:
         priority = -objective
     else:
         priority = objective
     Node._insert_queue_priority(item, priority)
     return super(BestObjectiveFirstPriorityQueue, self).put_get(item)
Пример #6
0
 def _get_gap(self, item):
     objective = Node._extract_objective(item)
     bound = Node._extract_bound(item)
     if self._sense == minimize:
         gap = objective - bound
     else:
         gap = bound - objective
     assert not math.isnan(gap)
     return gap
Пример #7
0
 def test_bad_best_options(self):
     node = Node()
     node.objective = None
     with pytest.raises(ValueError):
         solve(DummyProblem(), comm=None, best_node=node)
     node.objective = nan
     with pytest.raises(ValueError):
         solve(DummyProblem(), comm=None, best_node=node)
     node.objective = 0
     solve(DummyProblem(), comm=None, best_node=node)
Пример #8
0
    def test_overwrites_queue_priority(self):
        q = BestObjectiveFirstPriorityQueue(sense=minimize,
                                            track_bound=True)
        node = Node()
        node.tree_depth = 0
        node.bound = -1
        assert node.queue_priority is None
        node.objective = 1
        assert q.put(node) == 0
        assert node.objective == 1
        assert node.queue_priority == -1
        child = _new_child(node)
        assert child.objective == 1
        child.objective = 0
        assert child.queue_priority is None
        cnt = q.put(child)
        node_ = q.get()
        assert child.queue_priority == 0
        assert cnt == 1
        assert node_ is child
        child.objective = 2
        cnt = q.put(child)
        node_ = q.get()
        assert child.queue_priority == -2
        assert cnt == 2
        assert node_ is node
        assert q.bound() == -1

        q = BestObjectiveFirstPriorityQueue(sense=maximize,
                                            track_bound=True)
        node = Node()
        node.tree_depth = 0
        node.bound = 3
        assert node.queue_priority is None
        node.objective = 1
        assert q.put(node) == 0
        assert node.objective == 1
        assert node.queue_priority == 1
        child = _new_child(node)
        assert child.objective == 1
        child.objective = 2
        assert child.queue_priority is None
        cnt = q.put(child)
        node_ = q.get()
        assert child.queue_priority == 2
        assert cnt == 1
        assert node_ is child
        child.objective = 0
        cnt = q.put(child)
        node_ = q.get()
        assert child.queue_priority == 0
        assert cnt == 2
        assert node_ is node
        assert q.bound() == 3
Пример #9
0
 def test_missing_queue_priority(self):
     q = CustomPriorityQueue(sense=minimize, track_bound=True)
     node = Node()
     node.tree_depth = 0
     node.bound = 0
     assert node.queue_priority is None
     with pytest.raises(ValueError):
         q.put(node)
     node.queue_priority = 1
     q.put(node)
     child = _new_child(node)
     assert child.queue_priority is None
     with pytest.raises(ValueError):
         q.put(child)
Пример #10
0
    def test_overwrites_queue_priority(self):
        q = FIFOQueue(minimize)
        node = Node(size=0)
        node.bound = 0
        assert node.queue_priority is None
        assert q.put(node._data) == 0
        assert node.queue_priority == 0
        child = node.new_child()
        assert child.queue_priority is None
        assert q.put(child._data) == 1
        assert child.queue_priority == -1

        l1 = Node(size=0)
        l1.bound = 1
        l2 = l1.new_child()
        l3 = l2.new_child()
        q = FIFOQueue(minimize)
        cnt, data = q.put_get(l2._data)
        assert cnt == 0
        assert data is l2._data
        cnt = q.put(l2._data)
        assert cnt == 1
        cnt, data_ = q.put_get(l3._data)
        assert cnt == 2
        assert data_ is l2._data
        cnt, data_ = q.put_get(l1._data)
        assert cnt == 3
        assert data_ is l3._data
        assert q.bound() == 1
Пример #11
0
    def test_overwrites_queue_priority(self):
        q = LIFOQueue(sense=minimize, track_bound=True)
        node = Node()
        node.tree_depth = 0
        node.bound = 0
        assert node.queue_priority is None
        assert q.put(node) == 0
        assert node.queue_priority == 0
        child = _new_child(node)
        assert child.queue_priority is None
        assert q.put(child) == 1
        assert child.queue_priority == 1

        l1 = Node()
        l1.tree_depth = 0
        l1.bound = 1
        l2 = _new_child(l1)
        l3 = _new_child(l2)
        q = LIFOQueue(sense=minimize, track_bound=True)
        cnt = q.put(l2)
        node_ = q.get()
        assert cnt == 0
        assert node_ is l2
        cnt = q.put(l2)
        assert q.bound() == 1
        assert cnt == 1
        cnt = q.put(l3)
        node_ = q.get()
        assert cnt == 2
        assert node_ is l3
        node_ = q.get()
        assert node_ is l2
        assert q.bound() is None
Пример #12
0
    def test_overwrites_queue_priority(self):
        q = RandomPriorityQueue(minimize)
        node = Node(size=0)
        node.bound = 0
        assert node.queue_priority is None
        assert q.put(node._data) == 0
        assert node.queue_priority is not None
        assert 0 <= node.queue_priority <= 1
        child = node.new_child()
        assert child.queue_priority is None
        assert q.put(child._data) == 1
        assert child.queue_priority is not None
        assert 0 <= child.queue_priority <= 1

        l1 = Node(size=0)
        l1.bound = 1
        l2 = l1.new_child()
        l3 = l2.new_child()
        q = RandomPriorityQueue(minimize)
        assert l2.queue_priority is None
        cnt, data = q.put_get(l2._data)
        assert data is l2._data
        assert l2.queue_priority is not None
        assert 0 <= l2.queue_priority <= 1
        assert cnt == 0
        cnt = q.put(l2._data)
        assert cnt == 1
        assert l3.queue_priority is None
        cnt, data_ = q.put_get(l3._data)
        assert cnt == 2
        assert l3.queue_priority is not None
        assert 0 <= l3.queue_priority <= 1
        assert data_ is max([l2, l3], key=lambda x_: x_.queue_priority)._data
Пример #13
0
    def test_overwrites_queue_priority(self):
        q = DepthFirstPriorityQueue(minimize)
        node = Node(size=0)
        node.bound = 0
        assert node.queue_priority is None
        assert q.put(node._data) == 0
        assert node.tree_depth == 0
        assert node.queue_priority == 0
        child = node.new_child()
        assert child.tree_depth == 1
        assert child.queue_priority is None
        assert q.put(child._data) == 1
        assert child.queue_priority == child.tree_depth

        l1 = Node(size=0)
        l1.bound = 1
        l2 = l1.new_child()
        l3 = l2.new_child()
        q = DepthFirstPriorityQueue(minimize)
        q.put(l2._data)
        cnt, data_ = q.put_get(l3._data)
        assert cnt == 1
        assert data_ is l3._data
        cnt, data_ = q.put_get(l2._data)
        assert cnt == 2
        assert data_ is l2._data
        assert q.bound() == 1
Пример #14
0
    def test_str(self):
        node = Node()
        node.objective = -1
        node.bound = -2
        node.tree_depth = 3
        node.queue_priority = (1, 2, 3)
        node.state = "a"
        assert (str(node) == """\
Node(objective=-1,
     bound=-2,
     tree_depth=3)""")
Пример #15
0
 def put(self, item):
     bound = Node._extract_bound(item)
     assert not math.isnan(bound)
     if self._queue.requires_priority:
         if not Node._has_queue_priority(item):
             raise ValueError("A node queue priority is required")
         priority = Node._extract_queue_priority(item)
         cnt = self._queue.put(item, priority)
     else:
         cnt = self._queue.put(item)
     if self._sense == maximize:
         self._sorted_by_bound.add((-bound, cnt, item))
     else:
         self._sorted_by_bound.add((bound, cnt, item))
     return cnt
Пример #16
0
 def _get_work_to_send(self, dest):
     node_data = self._get_work_item()
     bound = Node._extract_bound(node_data)
     self.last_known_bound[dest] = bound
     self.external_bounds.add(bound)
     self.has_work.add(dest)
     return node_data
Пример #17
0
 def test_init(self):
     node = Node()
     assert node.objective is None
     assert node.bound is None
     assert node.tree_depth is None
     assert node.queue_priority is None
     assert node.state is None
Пример #18
0
 def test_str(self):
     node = Node()
     node.objective = -1
     node.bound = -2
     node.tree_depth = 3
     node.queue_priority = (1,2,3)
     node.state = 'a'
     assert str(node) == \
         """\
Пример #19
0
    def test_overwrites_queue_priority(self):
        q = BestObjectiveFirstPriorityQueue(minimize)
        node = Node(size=0)
        node.bound = -1
        assert node.queue_priority is None
        node.objective = 1
        assert q.put(node._data) == 0
        assert node.objective == 1
        assert node.queue_priority == -1
        child = node.new_child()
        assert child.objective == 1
        child.objective = 0
        assert child.queue_priority is None
        cnt, data_ = q.put_get(child._data)
        assert child.queue_priority == 0
        assert cnt == 1
        assert data_ is child._data
        child.objective = 2
        cnt, data_ = q.put_get(child._data)
        assert child.queue_priority == -2
        assert cnt == 2
        assert data_ is node._data
        assert q.bound() == -1

        q = BestObjectiveFirstPriorityQueue(maximize)
        node = Node(size=0)
        node.bound = 3
        assert node.queue_priority is None
        node.objective = 1
        assert q.put(node._data) == 0
        assert node.objective == 1
        assert node.queue_priority == 1
        child = node.new_child()
        assert child.objective == 1
        child.objective = 2
        assert child.queue_priority is None
        cnt, data_ = q.put_get(child._data)
        assert child.queue_priority == 2
        assert cnt == 1
        assert data_ is child._data
        child.objective = 0
        cnt, data_ = q.put_get(child._data)
        assert child.queue_priority == 0
        assert cnt == 2
        assert data_ is node._data
        assert q.bound() == 3
Пример #20
0
 def test_missing_queue_priority(self):
     q = CustomPriorityQueue(minimize)
     node = Node(size=0)
     node.bound = 0
     assert node.queue_priority is None
     with pytest.raises(ValueError):
         q.put(node._data)
     with pytest.raises(ValueError):
         q.put_get(node._data)
     node.queue_priority = 1
     q.put(node._data)
     child = node.new_child()
     assert child.queue_priority is None
     with pytest.raises(ValueError):
         q.put(child._data)
     with pytest.raises(ValueError):
         q.put_get(child._data)
Пример #21
0
    def test_initialize_queue(self):
        node_limit = None
        time_limit = None
        log = get_simple_logger()
        log_interval_seconds = inf
        log_new_incumbent = True
        convergence_checker = ConvergenceChecker(minimize)

        root = Node(size=0)
        Node._insert_tree_id(root._data, 0)
        root.bound = convergence_checker.unbounded_objective
        root.objective = convergence_checker.infeasible_objective
        queue = DispatcherQueueData(nodes=[root], next_tree_id=1)

        disp = DispatcherLocal()
        disp.initialize(0, queue, 'bound', convergence_checker, node_limit,
                        time_limit, log, log_interval_seconds,
                        log_new_incumbent)
        assert disp.best_objective == 0
        disp.initialize(1, queue, 'bound', convergence_checker, node_limit,
                        time_limit, log, log_interval_seconds,
                        log_new_incumbent)
        assert disp.best_objective == 1
        root.objective = -1
        disp.initialize(1, queue, 'bound', convergence_checker, node_limit,
                        time_limit, log, log_interval_seconds,
                        log_new_incumbent)
        assert disp.best_objective == -1
Пример #22
0
 def filter(self, func):
     removed = []
     for cnt, item in self._queue.filter(func, include_counters=True):
         removed.append(item)
         bound = Node._extract_bound(item)
         if self._sense == maximize:
             self._sorted_by_bound.remove((-bound, cnt, item))
         else:
             self._sorted_by_bound.remove((bound, cnt, item))
     return removed
Пример #23
0
 def test_tree_id(self):
     node = Node()
     assert node.tree_id is None
     assert node.parent_tree_id is None
     Node._insert_tree_id(node._data, 1)
     assert node.tree_id == 1
     assert node.parent_tree_id is None
     Node._insert_parent_tree_id(node._data, 2)
     assert node.tree_id == 1
     assert node.parent_tree_id == 2
     Node._clear_tree_id(node._data)
     assert node.tree_id is None
     assert node.parent_tree_id == 2
     Node._clear_parent_tree_id(node._data)
     assert node.tree_id is None
     assert node.parent_tree_id is None
Пример #24
0
 def bound(self):
     # tell the listeners to start bounds tightening
     node = Node()
     self.save_state(node)
     continue_loop = True
     while continue_loop:
         if (self._comm is not None) and (self._comm.size > 1):
             self._notify_continue_listen(node)
         continue_loop = self.range_reduction_process_bounds(*self._tighten_bounds())
         self.save_state(node)
     return self.problem.bound()
Пример #25
0
    def put_get(self, item):
        if self._queue.size() > 0:
            cnt_next, tmp_ = self._queue.next()
            assert type(cnt_next) is int
            if self._queue.requires_priority:
                if not Node._has_queue_priority(item):
                    raise ValueError("A node queue priority is required")
                priority = Node._extract_queue_priority(item)
                cnt, item_ = self._queue.put_get(item, priority)
            else:
                cnt, item_ = self._queue.put_get(item)
            if item_ is not item:
                assert item_ is tmp_
                bound = Node._extract_bound(item)
                assert not math.isnan(bound)
                bound_ = Node._extract_bound(item_)
                assert not math.isnan(bound_)
                if self._sense == maximize:
                    self._sorted_by_bound.add((-bound, cnt, item))
                    self._sorted_by_bound.remove((-bound_, cnt_next, item_))
                else:
                    self._sorted_by_bound.add((bound, cnt, item))
                    self._sorted_by_bound.remove((bound_, cnt_next, item_))
        else:
            if self._queue.requires_priority:
                if not Node._has_queue_priority(item):
                    raise ValueError("A node queue priority is required")
                priority = Node._extract_queue_priority(item)
                cnt, item_ = self._queue.put_get(item, priority)
            else:
                cnt, item_ = self._queue.put_get(item)

        return cnt, item_
Пример #26
0
 def get(self):
     if self._queue.size() > 0:
         cnt, tmp_ = self._queue.next()
         assert type(cnt) is int
         item = self._queue.get()
         assert tmp_ is item
         bound = Node._extract_bound(item)
         if self._sense == maximize:
             self._sorted_by_bound.remove((-bound, cnt, item))
         else:
             self._sorted_by_bound.remove((bound, cnt, item))
         return item
     else:
         return None
Пример #27
0
    def test_state_update(self):
        node = Node(size=3)
        node.state[0] = 1.1
        node.state[1] = 0.0
        node.state[2] = 0.0
        assert node.state[0] == 1.1
        assert node.state[1] == 0
        assert node.state[2] == 0
        node.state[1:3] = [-1.0, 5.3]
        assert node.state[0] == 1.1
        assert node.state[1] == -1.0
        assert node.state[2] == 5.3

        state = node.state
        node.resize(4)
        with pytest.raises(ValueError):
            state[0] = 1
Пример #28
0
 def _check_update_best_objective(self, objective):
     updated = False
     if self.converger.objective_improved(objective, self.best_objective):
         updated = True
         if self.journalist is not None:
             self.journalist.new_objective(report=self.log_new_incumbent)
         self.best_objective = objective
         eligible_for_queue_ = self.converger.eligible_for_queue
         extract_bound_ = Node._extract_bound
         removed = self.queue.filter(lambda node_data_: eligible_for_queue_(
             extract_bound_(node_data_), objective))
         for node_data in removed:
             self._check_update_worst_terminal_bound(
                 Node._extract_bound(node_data))
     return updated
Пример #29
0
    def save_dispatcher_queue(self):
        """Saves the current dispatcher queue. The result can
        be used to re-initialize a solve.

        Returns
        -------
        queue_data : :class:`pybnb.dispatcher.DispatcherQueueData`
            An object storing information that can be used
            to re-initialize the dispatcher queue to its
            current state.
        """
        return DispatcherQueueData(nodes=[
            Node(data_=numpy.array(data, dtype=float))
            for data in self.queue.items()
        ],
                                   next_tree_id=self.next_tree_id)
Пример #30
0
 def test_new_child(self):
     node = Node()
     assert node.objective is None
     assert node.bound is None
     assert node.tree_depth is None
     assert node.queue_priority is None
     assert node.state is None
     node.tree_depth = 0
     node = node.new_child()
     assert node.objective is None
     assert node.bound is None
     assert node.tree_depth == 1
     assert node.queue_priority is None
     assert node.state is None
     node.objective = 1
     node.bound = -1
     node.queue_priority = 5
     node.state = "a"
     node = node.new_child()
     assert node.objective == 1
     assert node.bound == -1
     assert node.tree_depth == 2
     assert node.queue_priority is None
     assert node.state is None