def test_evaluate_node_fractional(self): bb = BranchAndBound(small_branch, Node=PCBDFSNode, pseudo_costs={}, strong_branch_iters=5) bb._evaluate_node(bb.root_node) # check attributes self.assertFalse(bb._best_solution, 'best solution should not change') self.assertTrue(bb.global_upper_bound == float('inf'), 'shouldnt change') self.assertTrue(bb.global_lower_bound > -float('inf'), 'should change') self.assertTrue(bb._node_queue.qsize() == 2, 'should branch and add two nodes') self.assertTrue(bb._kwargs['pseudo_costs'], 'something should be set') self.assertTrue(bb._kwargs['strong_branch_iters'], 'something should be set') self.assertTrue(bb.evaluated_nodes == 1, 'only one node should be evaluated') # check function calls - recycle object since it has attrs already set with patch.object(bb, '_process_rtn') as pr, \ patch.object(bb, '_process_branch_rtn') as pbr, \ patch.object(bb.root_node, 'bound') as bd, \ patch.object(bb.root_node, 'branch') as bh: bb._evaluate_node(bb.root_node) self.assertTrue(pr.call_count == 1) # direct calls self.assertTrue(pbr.call_count == 1) self.assertTrue(0 == pbr.call_args.args[0], 'root node id should be first call arg') self.assertTrue(bd.call_count == 1) self.assertTrue(bh.call_count == 1)
def test_evaluate_node_infeasible(self): bb = BranchAndBound(infeasible) bb._evaluate_node(bb.root_node) # check attributes self.assertTrue(bb._node_queue.empty(), 'inf model should create no nodes') self.assertFalse(bb._best_solution, 'best solution should not change') self.assertTrue(bb.global_upper_bound == float('inf'), 'shouldnt change') self.assertTrue(bb.global_lower_bound == float('inf'), 'shouldnt change') self.assertTrue(bb.evaluated_nodes == 1, 'only one node should be evaluated') # check function calls - recycle object since it has attrs already set with patch.object(bb, '_process_rtn') as pr, \ patch.object(bb, '_process_branch_rtn') as pbr, \ patch.object(bb.root_node, 'bound') as bd, \ patch.object(bb.root_node, 'branch') as bh: bb._evaluate_node(bb.root_node) self.assertTrue(pr.call_count == 1) self.assertTrue(pbr.call_count == 0) self.assertTrue(bd.call_count == 1) self.assertTrue(bh.call_count == 0)
def test_evaluate_node_unbounded(self): bb = BranchAndBound(unbounded) bb._evaluate_node(bb.root_node) # check attributes self.assertTrue(bb._unbounded) self.assertTrue(bb.evaluated_nodes == 1, 'only one node should be evaluated')
def test_evaluate_node_properly_prunes(self): bb = BranchAndBound(no_branch) bb._global_upper_bound = -2 called_node = BaseNode(bb.model.lp, bb.model.integerIndices, -4) pruned_node = BaseNode(bb.model.lp, bb.model.integerIndices, 0) with patch.object(called_node, 'bound') as cnb, \ patch.object(pruned_node, 'bound') as pnb: cnb.return_value = {} pnb.return_value = {} bb._node_queue.put(called_node) bb._node_queue.put(pruned_node) bb._evaluate_node(bb._node_queue.get()) bb._evaluate_node(bb._node_queue.get()) self.assertTrue(cnb.call_count == 1, 'first node should run') self.assertFalse(pnb.call_count, 'second node should get pruned') self.assertTrue(bb._node_queue.empty())
def test_evaluate_node_integer(self): bb = BranchAndBound(no_branch) bb._evaluate_node(bb._root_node) # check attributes self.assertTrue(all(bb._best_solution == [1, 1, 0])) self.assertTrue(bb._global_upper_bound == -2) self.assertTrue(bb._node_queue.empty(), 'immediately optimal model should create no nodes') # check function calls - recycle object since it has attrs already set with patch.object(bb, '_process_rtn') as pr, \ patch.object(bb, '_process_branch_rtn') as pbr, \ patch.object(bb._root_node, 'bound') as bd, \ patch.object(bb._root_node, 'branch') as bh: bb._evaluate_node(bb._root_node) self.assertTrue(pr.call_count == 1) self.assertTrue(pbr.call_count == 0) self.assertTrue(bd.call_count == 1) self.assertTrue(bh.call_count == 0)
def test_evaluate_node_fractional(self): bb = BranchAndBound(small_branch, Node=PCBDFSNode) bb._evaluate_node(bb._root_node) # check attributes self.assertFalse(bb._best_solution, 'best solution should not change') self.assertTrue(bb._global_upper_bound == float('inf'), 'shouldnt change') self.assertTrue(bb._node_queue.qsize() == 2, 'should branch and add two nodes') self.assertTrue(bb._pseudo_costs, 'something should be set') # check function calls - recycle object since it has attrs already set with patch.object(bb, '_process_rtn') as pr, \ patch.object(bb, '_process_branch_rtn') as pbr, \ patch.object(bb._root_node, 'bound') as bd, \ patch.object(bb._root_node, 'branch') as bh: bb._evaluate_node(bb._root_node) self.assertTrue(pr.call_count == 1) # direct calls self.assertTrue(pbr.call_count == 1) self.assertTrue(bd.call_count == 1) self.assertTrue(bh.call_count == 1)
def test_evaluate_node_unbounded(self): bb = BranchAndBound(unbounded) bb._evaluate_node(bb._root_node) # check attributes self.assertTrue(bb._unbounded)