예제 #1
0
    def test_overwrites_queue_priority(self):
        q = WorstBoundFirstPriorityQueue(minimize)
        node = Node(size=0)
        node.bound = 1
        assert node.queue_priority is None
        q.put(node._data)
        assert node.queue_priority == -1

        q = WorstBoundFirstPriorityQueue(maximize)
        node = Node(size=0)
        node.bound = 1
        assert node.queue_priority is None
        q.put(node._data)
        assert node.queue_priority == 1
예제 #2
0
    def test_overwrites_queue_priority(self):
        q = WorstBoundFirstPriorityQueue(sense=minimize, track_bound=True)
        node = Node()
        node.bound = 1
        assert node.queue_priority is None
        q.put(node)
        assert node.queue_priority == -1

        q = WorstBoundFirstPriorityQueue(sense=maximize, track_bound=True)
        node = Node()
        node.bound = 1
        assert node.queue_priority is None
        q.put(node)
        assert node.queue_priority == 1
예제 #3
0
 def test_usage_maximize(self):
     q = WorstBoundFirstPriorityQueue(maximize)
     assert q.size() == 0
     assert q.bound() is None
     assert len(list(q.items())) == 0
     assert q.get() is None
     items = []
     for i in range(1, 11):
         node = Node(size=0)
         node.bound = -i
         assert node.queue_priority is None
         cnt_ = q.put(node._data)
         assert cnt_ == i - 1
         assert node.queue_priority == node.bound
         items.append(node._data)
         assert q.size() == i
         assert q.bound() == -1
         _check_items(q, items)
     assert q.size() == 10
     assert q.bound() == -1
     removed = q.filter(lambda data: \
                        Node._extract_bound(data) <= -5)
     assert q.size() == 6
     assert len(removed) == 4
     for data in removed:
         assert Node._extract_bound(data) > -5
     assert q.bound() == -5
     for i in range(5, 11):
         node = Node(data_=q.get())
         assert node.bound == -i
         assert node.queue_priority == node.bound
         if i != 10:
             assert q.bound() == -i - 1
         else:
             assert q.bound() is None
     assert q.size() == 0
     node = Node(size=0)
     node.bound = 1
     assert node.queue_priority is None
     cnt_, data = q.put_get(node._data)
     assert cnt_ == 10
     assert data is node._data
     assert node.queue_priority == 1
     node.bound = 2
     cnt_ = q.put(node._data)
     assert node.queue_priority == 2
     assert cnt_ == 11
     node2 = Node(size=0)
     node2.bound = 3
     assert node2.queue_priority is None
     cnt_, data = q.put_get(node2._data)
     assert cnt_ == 12
     assert data is node2._data
     assert node2.queue_priority == 3
     node2.bound = 1
     cnt_, data = q.put_get(node2._data)
     assert node2.queue_priority == 1
     assert cnt_ == 13
     assert data is node._data
     assert q.size() == 1
예제 #4
0
 def test_usage_maximize(self):
     q = WorstBoundFirstPriorityQueue(sense=maximize, track_bound=True)
     assert q.size() == 0
     assert q.bound() is None
     assert len(list(q.items())) == 0
     assert q.get() is None
     items = []
     for i in range(1, 11):
         node = Node()
         node.bound = -i
         assert node.queue_priority is None
         cnt_ = q.put(node)
         assert cnt_ == i - 1
         assert node.queue_priority == node.bound
         items.append(node)
         assert q.size() == i
         assert q.bound() == -1
         _check_items(q, items)
     assert q.size() == 10
     assert q.bound() == -1
     removed = q.filter(lambda n_: n_.bound <= -5)
     assert q.size() == 6
     assert len(removed) == 4
     for node_ in removed:
         assert node_.bound > -5
     assert q.bound() == -5
     for i in range(5, 11):
         node = q.get()
         assert node.bound == -i
         assert node.queue_priority == node.bound
         if i != 10:
             assert q.bound() == -i - 1
         else:
             assert q.bound() is None
     assert q.size() == 0
     node = Node()
     node.bound = 1
     assert node.queue_priority is None
     cnt_ = q.put(node)
     node_ = q.get()
     assert cnt_ == 10
     assert node_ is node
     assert node.queue_priority == 1
     node.bound = 2
     cnt_ = q.put(node)
     assert node.queue_priority == 2
     assert cnt_ == 11
     node2 = Node()
     node2.bound = 3
     assert node2.queue_priority is None
     cnt_ = q.put(node2)
     node_ = q.get()
     assert cnt_ == 12
     assert node_ is node2
     assert node2.queue_priority == 3
     node2.bound = 1
     cnt_ = q.put(node2)
     node_ = q.get()
     assert node2.queue_priority == 1
     assert cnt_ == 13
     assert node_ is node
     assert q.size() == 1
예제 #5
0
    def initialize(self, best_objective, initialize_queue, queue_strategy,
                   converger, node_limit, time_limit, log,
                   log_interval_seconds, log_new_incumbent):
        """Initialize the dispatcher for a new solve.

        Parameters
        ----------
        best_objective : float
            The assumed best objective to start with.
        initialize_queue : :class:`pybnb.dispatcher.DispatcherQueueData`
            The initial queue.
        queue_strategy : :class:`QueueStrategy <pybnb.common.QueueStrategy>`
            Sets the strategy for prioritizing nodes in the
            central dispatcher queue. See the
            :class:`QueueStrategy <pybnb.common.QueueStrategy>`
            enum for the list of acceptable values.
        converger : :class:`pybnb.convergence_checker.ConvergenceChecker`
            The branch-and-bound convergence checker object.
        node_limit : int or None
            An integer representing the maximum number of
            nodes to processes before beginning to terminate
            the solve. If None, no node limit will be
            enforced.
        time_limit : float or None
            The maximum amount of time to spend processing
            nodes before beginning to terminate the
            solve. If None, no time limit will be enforced.
        log : ``logging.Logger``
            A log object where solver output should be sent.
        log_interval_seconds : float
            The approximate maximum time (in seconds)
            between solver log updates. More time may pass
            between log updates if no updates have been
            received from any workers, and less time may
            pass if a new incumbent is found.
        log_new_incumbent : bool
            Controls whether updates to the best objective
            are logged immediately (overriding the log
            interval). Setting this to false can be useful
            when frequent updates to the incumbent are
            expected and the additional logging slows down
            the dispatcher.
        """
        assert (node_limit is None) or \
            ((node_limit > 0) and \
             (node_limit == int(node_limit)))
        assert (time_limit is None) or \
            (time_limit >= 0)
        self.start_time = self.clock()
        self.initialized = True
        self.log_new_incumbent = log_new_incumbent
        self.termination_condition = None
        self.converger = converger
        self.last_global_bound = self.converger.unbounded_objective
        self.best_objective = best_objective
        if queue_strategy == "bound":
            self.queue = WorstBoundFirstPriorityQueue(self.converger.sense)
        elif queue_strategy == "custom":
            self.queue = CustomPriorityQueue(self.converger.sense)
        elif queue_strategy == "objective":
            self.queue = BestObjectiveFirstPriorityQueue(self.converger.sense)
        elif queue_strategy == "fifo":
            self.queue = FIFOQueue(self.converger.sense)
        elif queue_strategy == "breadth":
            self.queue = BreadthFirstPriorityQueue(self.converger.sense)
        elif queue_strategy == "depth":
            self.queue = DepthFirstPriorityQueue(self.converger.sense)
        elif queue_strategy == "local_gap":
            self.queue = LocalGapPriorityQueue(self.converger.sense)
        elif queue_strategy == "random":
            self.queue = RandomPriorityQueue(self.converger.sense)
        else:
            raise ValueError("'queue_strategy' must be one of: %s" %
                             (str([v.value for v in QueueStrategy])))
        self.node_limit = None
        if node_limit is not None:
            self.node_limit = int(node_limit)
        self.time_limit = None
        if time_limit is not None:
            self.time_limit = float(time_limit)
        self.served_nodes_count = 0
        self.worst_terminal_bound = None
        self.next_tree_id = initialize_queue.next_tree_id
        self.journalist = None
        if (log is not None) and (not log.disabled):
            self.journalist = StatusPrinter(
                self, log, log_interval_seconds=log_interval_seconds)
        if len(initialize_queue.nodes):
            self._check_update_best_objective(
                self.converger.best_objective(
                    node.objective for node in initialize_queue.nodes))
            for node in initialize_queue.nodes:
                assert node.tree_id is not None
                self._add_work_to_queue(node._data, set_tree_id=False)