38 CHECK(objective !=
nullptr);
46 if (lp->ObjectiveVariable() == objective_var_) {
59void LbTreeSearch::UpdateParentObjective(
int level) {
61 CHECK_LT(level, current_branch_.size());
62 if (level == 0)
return;
63 const NodeIndex parent_index = current_branch_[level - 1];
64 Node& parent = nodes_[parent_index];
65 const NodeIndex child_index = current_branch_[level];
66 const Node& child = nodes_[child_index];
67 if (parent.true_child == child_index) {
68 parent.UpdateTrueObjective(child.MinObjective());
70 CHECK_EQ(parent.false_child, child_index);
71 parent.UpdateFalseObjective(child.MinObjective());
75void LbTreeSearch::UpdateObjectiveFromParent(
int level) {
77 CHECK_LT(level, current_branch_.size());
78 if (level == 0)
return;
79 const NodeIndex parent_index = current_branch_[level - 1];
80 const Node& parent = nodes_[parent_index];
81 CHECK_GE(parent.MinObjective(), current_objective_lb_);
82 const NodeIndex child_index = current_branch_[level];
83 Node& child = nodes_[child_index];
84 if (parent.true_child == child_index) {
85 child.UpdateObjective(parent.true_objective);
87 CHECK_EQ(parent.false_child, child_index);
88 child.UpdateObjective(parent.false_objective);
92void LbTreeSearch::DebugDisplayTree(
NodeIndex root)
const {
94 const IntegerValue root_lb = nodes_[root].MinObjective();
95 const auto shifted_lb = [root_lb](IntegerValue lb) {
96 return std::max<int64_t>(0, (lb - root_lb).
value());
100 std::vector<NodeIndex> to_explore = {root};
101 while (!to_explore.empty()) {
103 to_explore.pop_back();
106 const Node& node = nodes_[n];
108 std::string s(level[n],
' ');
109 absl::StrAppend(&s,
"#", n.value());
111 if (node.true_child < nodes_.
size()) {
112 absl::StrAppend(&s,
" [t:#", node.true_child.value(),
" ",
113 shifted_lb(node.true_objective),
"]");
114 to_explore.push_back(node.true_child);
115 level[node.true_child] = level[n] + 1;
117 absl::StrAppend(&s,
" [t:## ", shifted_lb(node.true_objective),
"]");
119 if (node.false_child < nodes_.
size()) {
120 absl::StrAppend(&s,
" [f:#", node.false_child.value(),
" ",
121 shifted_lb(node.false_objective),
"]");
122 to_explore.push_back(node.false_child);
123 level[node.false_child] = level[n] + 1;
125 absl::StrAppend(&s,
" [f:## ", shifted_lb(node.false_objective),
"]");
129 LOG(
INFO) <<
"num_nodes: " << num_nodes;
133 const std::function<
void()>& feasible_solution_observer) {
147 int64_t restart = 100;
148 int64_t num_restart = 1;
149 const int kNumRestart = 10;
158 if (!current_branch_.empty()) {
163 CHECK_GE(current_branch_.size(), current_level);
164 for (
int i = 0; i < current_level; ++i) {
166 nodes_[current_branch_[i]].literal));
168 if (current_level < current_branch_.size()) {
169 nodes_[current_branch_[current_level]].UpdateObjective(
181 if (integer_trail_->
LowerBound(objective_var_) >
183 const std::vector<Literal> reason =
185 objective_var_, integer_trail_->
LowerBound(objective_var_)));
187 for (
const Literal l : reason) {
188 max_level = std::max<int>(
192 if (max_level < current_level) {
193 nodes_[current_branch_[max_level]].UpdateObjective(
200 for (
int level = current_branch_.size(); --level > 0;) {
201 UpdateParentObjective(level);
203 nodes_[current_branch_[0]].UpdateObjective(current_objective_lb_);
204 for (
int level = 1; level < current_branch_.size(); ++level) {
205 UpdateObjectiveFromParent(level);
209 const IntegerValue
bound = nodes_[current_branch_[0]].MinObjective();
210 if (
bound > current_objective_lb_) {
212 absl::StrCat(
"lb_tree_search #nodes:", nodes_.
size(),
213 " #rc:", num_rc_detected_),
215 current_objective_lb_ =
bound;
216 if (
VLOG_IS_ON(2)) DebugDisplayTree(current_branch_[0]);
230 if (integer_trail_->
LowerBound(objective_var_) >
232 std::vector<Literal> reason =
234 objective_var_, integer_trail_->
LowerBound(objective_var_)));
240 if (nodes_.
size() > num_restart * restart && num_restart < kNumRestart) {
242 current_branch_.clear();
258 (current_branch_.size() > 1 &&
259 nodes_[current_branch_.back()].MinObjective() >
260 current_objective_lb_)) {
261 current_branch_.pop_back();
266 std::max(0,
static_cast<int>(current_branch_.size()) - 1));
279 const int level = current_branch_.size() - 1;
281 Node& node = nodes_[current_branch_[level]];
283 current_objective_lb_, integer_trail_->
LowerBound(objective_var_)));
284 if (node.MinObjective() > current_objective_lb_) {
287 CHECK_EQ(node.MinObjective(), current_objective_lb_) << level;
298 new_lb = node.true_objective;
300 n = node.false_child;
301 new_lb = node.false_objective;
306 current_branch_.pop_back();
307 if (!current_branch_.empty()) {
308 const NodeIndex parent = current_branch_.back();
310 nodes_[parent].true_child = n;
311 nodes_[parent].UpdateTrueObjective(new_lb);
314 nodes_[parent].literal));
315 nodes_[parent].false_child = n;
316 nodes_[parent].UpdateFalseObjective(new_lb);
318 if (nodes_[parent].MinObjective() > current_objective_lb_)
break;
322 bool choose_true = node.true_objective < node.false_objective;
323 if (node.true_objective == node.false_objective) {
324 choose_true = absl::Bernoulli(*random_, 0.5);
330 n = node.false_child;
346 const IntegerValue lb = integer_trail_->
LowerBound(objective_var_);
348 node.UpdateTrueObjective(lb);
350 node.UpdateFalseObjective(lb);
352 if (lb > current_objective_lb_)
break;
355 if (n < nodes_.
size()) {
356 current_branch_.push_back(n);
380 if (integer_trail_->
LowerBound(objective_var_) > current_objective_lb_) {
385 const LiteralIndex decision =
391 feasible_solution_observer();
401 if (!current_branch_.empty()) {
402 const NodeIndex parent = current_branch_.back();
404 nodes_[parent].true_child = n;
405 nodes_[parent].UpdateTrueObjective(nodes_.
back().MinObjective());
408 nodes_[parent].false_child = n;
409 nodes_[parent].UpdateFalseObjective(nodes_.
back().MinObjective());
412 current_branch_.push_back(n);
426 if (lp_constraint_ !=
nullptr) {
435 if (++num_tests > 10)
break;
441 if (cts.empty())
continue;
443 const std::unique_ptr<IntegerSumLE>& rc = cts.back();
444 const std::pair<IntegerValue, IntegerValue>
bounds =
445 rc->ConditionalLb(integer_literal, objective_var_);
446 Node& node = nodes_[n];
447 if (
bounds.first > node.false_objective) {
449 node.UpdateFalseObjective(
bounds.first);
451 if (
bounds.second > node.true_objective) {
453 node.UpdateTrueObjective(
bounds.second);
#define CHECK_LT(val1, val2)
#define CHECK_EQ(val1, val2)
#define CHECK_GE(val1, val2)
void emplace_back(Args &&... args)
A simple class to enforce both an elapsed time limit and a deterministic time limit in the same threa...
bool LimitReached()
Returns true when the external limit is true, or the deterministic time is over the deterministic lim...
const InlinedIntegerLiteralVector & GetIntegerLiterals(Literal lit) const
bool BeforeTakingDecision()
bool TakeDecision(Literal decision)
LiteralIndex GetDecision(const std::function< BooleanOrIntegerLiteral()> &f)
bool IsCurrentlyIgnored(IntegerVariable i) const
std::vector< Literal > ReasonFor(IntegerLiteral literal) const
IntegerValue LevelZeroUpperBound(IntegerVariable var) const
IntegerValue LevelZeroLowerBound(IntegerVariable var) const
IntegerValue LowerBound(IntegerVariable i) const
LbTreeSearch(Model *model)
SatSolver::Status Search(const std::function< void()> &feasible_solution_observer)
const std::vector< std::unique_ptr< IntegerSumLE > > & OptimalConstraints() const
Class that owns everything related to a particular optimization model.
void UpdateVariableActivityIncrement()
void BumpVariableActivities(const std::vector< Literal > &literals)
const VariablesAssignment & Assignment() const
const Trail & LiteralTrail() const
Status UnsatStatus() const
void Backtrack(int target_level)
bool RestoreSolverToAssumptionLevel()
int CurrentDecisionLevel() const
bool ProblemIsSolved() const
IntegerValue GetInnerObjectiveLowerBound()
void UpdateInnerObjectiveBounds(const std::string &update_info, IntegerValue lb, IntegerValue ub)
const AssignmentInfo & Info(BooleanVariable var) const
bool LiteralIsAssigned(Literal literal) const
bool LiteralIsTrue(Literal literal) const
bool LiteralIsFalse(Literal literal) const
SharedBoundsManager * bounds
constexpr IntegerValue kMaxIntegerValue(std::numeric_limits< IntegerValue::ValueType >::max() - 1)
std::function< BooleanOrIntegerLiteral()> SequentialSearch(std::vector< std::function< BooleanOrIntegerLiteral()> > heuristics)
const LiteralIndex kNoLiteralIndex(-1)
std::function< BooleanOrIntegerLiteral()> SatSolverHeuristic(Model *model)
Collection of objects used to extend the Constraint Solver library.
static IntegerLiteral GreaterOrEqual(IntegerVariable i, IntegerValue bound)
IntegerVariable objective_var
#define VLOG_IS_ON(verboselevel)