25 #include "ortools/sat/boolean_problem.pb.h"
28 #include "ortools/sat/sat_parameters.pb.h"
36 : for_sorting_(l.Variable()), literals_(1, l) {}
39 std::function<
Literal(
int x)> create_lit)
40 : lb_(lb), ub_(ub), create_lit_(create_lit) {
42 literals_.push_back(create_lit(
lb));
46 for_sorting_ = literals_[0].Variable();
51 CHECK(literals_.empty()) <<
"Already initialized";
53 const BooleanVariable first_var_index(solver->
NumVariables());
55 for (
int i = 0; i < n; ++i) {
56 literals_.push_back(
Literal(first_var_index + i,
true));
61 lb_ =
a->lb_ +
b->lb_;
66 for_sorting_ = first_var_index;
71 CHECK(literals_.empty()) <<
"Already initialized";
72 const BooleanVariable first_var_index(solver->
NumVariables());
74 literals_.emplace_back(first_var_index,
true);
77 ub_ =
a->ub_ +
b->ub_;
78 lb_ =
a->lb_ +
b->lb_;
82 for_sorting_ =
std::min(
a->for_sorting_,
b->for_sorting_);
87 CHECK(literals_.empty()) <<
"Already initialized";
90 ub_ =
a->ub_ +
b->ub_;
92 weight_lb_ =
a->lb_ +
b->lb_;
97 for_sorting_ =
std::min(
a->for_sorting_,
b->for_sorting_);
102 if (create_lit_ !=
nullptr) {
103 literals_.emplace_back(create_lit_(
current_ub()));
105 CHECK_NE(solver,
nullptr);
106 literals_.emplace_back(BooleanVariable(solver->
NumVariables()),
true);
109 if (literals_.size() > 1) {
111 literals_[literals_.size() - 2]);
118 while (i < literals_.size() &&
123 literals_.erase(literals_.begin(), literals_.begin() + i);
124 while (!literals_.empty() &&
126 literals_.pop_back();
127 ub_ = lb_ + literals_.size();
137 CHECK_GT(weight_, 0);
141 if (
size() <= new_size)
return;
142 for (
int i = new_size.value(); i <
size(); ++i) {
145 literals_.resize(new_size.value());
146 ub_ = lb_ + literals_.size();
151 const int index = weight_lb_ - lb_;
152 return index < literals_.size() && literals_[
index].Negated() == other;
157 const int index = weight_lb_ - lb_;
158 CHECK_GE(
index, 0) <<
"Not reduced?";
159 while (
index >= literals_.size()) {
162 return literals_[
index].Negated();
166 CHECK_LT(weight_lb_ - lb_, literals_.size());
171 return weight_ == 0 || weight_lb_ >= ub_;
177 absl::StrAppend(&result,
"depth:", depth_);
178 absl::StrAppend(&result,
" [", lb_,
",", lb_ + literals_.size(),
"]");
179 absl::StrAppend(&result,
" ub:", ub_);
180 absl::StrAppend(&result,
" weight:", weight_.value());
181 absl::StrAppend(&result,
" weight_lb:", weight_lb_);
182 absl::StrAppend(&result,
" values:");
183 const size_t limit = 20;
185 for (
int i = 0; i <
std::min(literals_.size(), limit); ++i) {
195 absl::StrAppend(&result,
" val:", lb_ +
value);
211 std::vector<EncodingNode*> to_process;
212 to_process.push_back(node);
219 const bool complete_encoding =
false;
221 while (!to_process.empty()) {
225 to_process.pop_back();
228 if (
a ==
nullptr)
continue;
229 CHECK_NE(solver,
nullptr);
240 if (
a->current_ub() !=
a->ub()) {
241 CHECK_GE(
a->current_ub() - 1 +
b->lb(), target - 1);
242 if (
a->current_ub() - 1 +
b->lb() < target) {
243 CHECK(
a->IncreaseCurrentUB(solver));
244 to_process.push_back(
a);
249 if (
b->current_ub() !=
b->ub()) {
250 CHECK_GE(
b->current_ub() - 1 +
a->lb(), target - 1);
251 if (
b->current_ub() - 1 +
a->lb() < target) {
252 CHECK(
b->IncreaseCurrentUB(solver));
253 to_process.push_back(
b);
258 for (
int ia =
a->lb(); ia < a->current_ub(); ++ia) {
259 const int ib = target - ia;
260 if (complete_encoding && ib >=
b->lb() && ib < b->current_ub()) {
263 a->GreaterThan(ia),
b->GreaterThan(ib));
265 if (complete_encoding && ib ==
b->ub()) {
270 if (ib - 1 ==
b->lb() - 1) {
272 a->GreaterThan(ia).Negated());
274 if ((ib - 1) >=
b->lb() && (ib - 1) <
b->current_ub()) {
277 a->GreaterThan(ia).Negated(),
278 b->GreaterThan(ib - 1).Negated());
284 const int ib = target - (
a->lb() - 1);
285 if ((ib - 1) ==
b->lb() - 1) {
288 if ((ib - 1) >=
b->lb() && (ib - 1) <
b->current_ub()) {
290 b->GreaterThan(ib - 1).Negated());
296 const int ib = target -
a->ub();
297 if (complete_encoding && ib >=
b->lb() && ib <
b->current_ub()) {
314 for (
int ia = 0; ia <
a->size(); ++ia) {
315 if (ia +
b->size() < size) {
326 for (
int ib = 0; ib <
b->size(); ++ib) {
327 if (ib +
a->size() < size) {
338 for (
int ia = 0; ia <
a->size(); ++ia) {
339 for (
int ib = 0; ib <
b->size(); ++ib) {
340 if (ia + ib < size) {
345 if (ia + ib + 1 < size) {
348 a->literal(ia).Negated(),
349 b->literal(ib).Negated());
352 b->literal(ib).Negated());
360 const std::vector<EncodingNode*>&
nodes,
362 std::deque<EncodingNode>* repository) {
363 std::deque<EncodingNode*> dq(
nodes.begin(),
nodes.end());
364 while (dq.size() > 1) {
370 dq.push_back(&repository->back());
376 struct SortEncodingNodePointers {
377 bool operator()(EncodingNode*
a, EncodingNode*
b)
const {
return *
a < *
b; }
383 SatSolver* solver, std::deque<EncodingNode>* repository) {
384 std::priority_queue<EncodingNode*, std::vector<EncodingNode*>,
385 SortEncodingNodePointers>
387 while (pq.size() > 2) {
393 pq.push(&repository->back());
396 CHECK_EQ(pq.size(), 2);
410 const std::vector<Literal>& literals,
411 const std::vector<Coefficient>& coeffs,
Coefficient* offset,
412 std::deque<EncodingNode>* repository) {
413 CHECK_EQ(literals.size(), coeffs.size());
415 std::vector<EncodingNode*>
nodes;
416 for (
int i = 0; i < literals.size(); ++i) {
419 repository->emplace_back(literals[i]);
420 nodes.push_back(&repository->back());
421 nodes.back()->set_weight(coeffs[i]);
423 repository->emplace_back(literals[i].Negated());
424 nodes.push_back(&repository->back());
425 nodes.back()->set_weight(-coeffs[i]);
428 *offset -= coeffs[i];
435 const LinearObjective& objective_proto,
Coefficient* offset,
436 std::deque<EncodingNode>* repository) {
438 std::vector<EncodingNode*>
nodes;
439 for (
int i = 0; i < objective_proto.literals_size(); ++i) {
443 if (objective_proto.coefficients(i) > 0) {
444 repository->emplace_back(
literal);
445 nodes.push_back(&repository->back());
449 nodes.push_back(&repository->back());
453 *offset -= objective_proto.coefficients(i);
461 bool EncodingNodeByWeight(
const EncodingNode*
a,
const EncodingNode*
b) {
462 return a->weight() <
b->weight();
465 bool EncodingNodeByDepth(
const EncodingNode*
a,
const EncodingNode*
b) {
466 return a->depth() <
b->depth();
487 if (gap < 0)
return {};
489 n->ApplyWeightUpperBound(gap, solver);
499 switch (solver->
parameters().max_sat_assumption_order()) {
500 case SatParameters::DEFAULT_ASSUMPTION_ORDER:
502 case SatParameters::ORDER_ASSUMPTION_BY_DEPTH:
503 std::sort(
nodes->begin(),
nodes->end(), EncodingNodeByDepth);
505 case SatParameters::ORDER_ASSUMPTION_BY_WEIGHT:
506 std::sort(
nodes->begin(),
nodes->end(), EncodingNodeByWeight);
509 if (solver->
parameters().max_sat_reverse_assumption_order()) {
516 std::vector<Literal> assumptions;
518 if (n->weight() >= stratified_lower_bound) {
519 assumptions.push_back(n->GetAssumption(solver));
526 const std::vector<Literal>& core) {
529 for (
int i = 0; i < core.size(); ++i) {
543 CHECK_GT(n->weight(), 0);
545 result =
std::max(result, n->weight());
552 std::deque<EncodingNode>* repository,
556 if (core.size() == 1) {
563 int new_node_index = 0;
564 std::vector<EncodingNode*> to_merge;
565 for (
int i = 0; i < core.size(); ++i) {
569 for (; !(*nodes)[
index]->AssumptionIs(core[i]); ++
index) {
571 (*nodes)[new_node_index] = (*nodes)[
index];
584 (*nodes)[new_node_index] = (*nodes)[
index];
590 (*nodes)[new_node_index] = (*nodes)[
index];
593 nodes->resize(new_node_index);
595 solver, repository));
601 std::deque<EncodingNode>* repository,
602 std::vector<EncodingNode*>*
nodes,
607 if (core.size() == 1) {
611 std::vector<EncodingNode*> new_nodes;
612 std::vector<EncodingNode*> to_merge;
616 CHECK_GT(n->size(), 0);
622 for (
int i = 0; i < core.size(); ++i) {
627 for (; !(*nodes)[
index]->AssumptionIs(core[i]); ++
index) {
639 CHECK_GT(n->
size(), 0);
643 repository->emplace_back(lit);
646 CHECK_GT(new_bool_node->
size(), 0);
647 to_merge.push_back(new_bool_node);
648 if (n->
weight() > min_weight) {
650 new_nodes.push_back(new_bool_node);
654 new_nodes.push_back(n);
663 solver, repository));
void InitializeLazyCoreNode(Coefficient weight, EncodingNode *a, EncodingNode *b)
Literal GetAssumption(SatSolver *solver)
EncodingNode * child_a() const
bool IncreaseCurrentUB(SatSolver *solver)
void ApplyWeightUpperBound(Coefficient gap, SatSolver *solver)
bool AssumptionIs(Literal other) const
Coefficient Reduce(const SatSolver &solver)
void InitializeLazyNode(EncodingNode *a, EncodingNode *b, SatSolver *solver)
void InitializeFullNode(int n, EncodingNode *a, EncodingNode *b, SatSolver *solver)
Coefficient weight() const
Literal literal(int i) const
std::string DebugString(const VariablesAssignment &assignment) const
EncodingNode * child_b() const
void set_weight(Coefficient w)
Literal GreaterThan(int i) const
void set_depth(int depth)
void SetNumVariables(int num_variables)
bool AddTernaryClause(Literal a, Literal b, Literal c)
const SatParameters & parameters() const
bool ModelIsUnsat() const
const VariablesAssignment & Assignment() const
bool AddBinaryClause(Literal a, Literal b)
void Backtrack(int target_level)
bool AddUnitClause(Literal true_literal)
bool LiteralIsTrue(Literal literal) const
bool LiteralIsFalse(Literal literal) const
std::tuple< int64_t, int64_t, const double > Coefficient
Coefficient ComputeCoreMinWeight(const std::vector< EncodingNode * > &nodes, const std::vector< Literal > &core)
EncodingNode * MergeAllNodesWithDeque(Coefficient upper_bound, const std::vector< EncodingNode * > &nodes, SatSolver *solver, std::deque< EncodingNode > *repository)
EncodingNode * LazyMergeAllNodeWithPQAndIncreaseLb(Coefficient weight, const std::vector< EncodingNode * > &nodes, SatSolver *solver, std::deque< EncodingNode > *repository)
std::vector< Literal > ReduceNodesAndExtractAssumptions(Coefficient upper_bound, Coefficient stratified_lower_bound, Coefficient *lower_bound, std::vector< EncodingNode * > *nodes, SatSolver *solver)
void IncreaseNodeSize(EncodingNode *node, SatSolver *solver)
EncodingNode LazyMerge(EncodingNode *a, EncodingNode *b, SatSolver *solver)
EncodingNode FullMerge(Coefficient upper_bound, EncodingNode *a, EncodingNode *b, SatSolver *solver)
bool ProcessCore(const std::vector< Literal > &core, Coefficient min_weight, std::deque< EncodingNode > *repository, std::vector< EncodingNode * > *nodes, SatSolver *solver)
Coefficient MaxNodeWeightSmallerThan(const std::vector< EncodingNode * > &nodes, Coefficient upper_bound)
bool ProcessCoreWithAlternativeEncoding(const std::vector< Literal > &core, Coefficient min_weight, std::deque< EncodingNode > *repository, std::vector< EncodingNode * > *nodes, SatSolver *solver)
std::vector< EncodingNode * > CreateInitialEncodingNodes(const std::vector< Literal > &literals, const std::vector< Coefficient > &coeffs, Coefficient *offset, std::deque< EncodingNode > *repository)
const Coefficient kCoefficientMax(std::numeric_limits< Coefficient::ValueType >::max())
Collection of objects used to extend the Constraint Solver library.