23#include "ortools/sat/boolean_problem.pb.h"
26#include "ortools/sat/sat_parameters.pb.h"
34 : for_sorting_(l.Variable()),
41 CHECK(literals_.empty()) <<
"Already initialized";
43 const BooleanVariable first_var_index(solver->
NumVariables());
45 for (
int i = 0; i < n; ++i) {
46 literals_.push_back(
Literal(first_var_index + i,
true));
51 lb_ =
a->lb_ +
b->lb_;
56 for_sorting_ = first_var_index;
61 CHECK(literals_.empty()) <<
"Already initialized";
62 const BooleanVariable first_var_index(solver->
NumVariables());
64 literals_.emplace_back(first_var_index,
true);
67 ub_ =
a->ub_ +
b->ub_;
68 lb_ =
a->lb_ +
b->lb_;
72 for_sorting_ =
std::min(
a->for_sorting_,
b->for_sorting_);
77 CHECK(literals_.empty()) <<
"Already initialized";
80 ub_ =
a->ub_ +
b->ub_;
82 weight_lb_ =
a->lb_ +
b->lb_;
87 for_sorting_ =
std::min(
a->for_sorting_,
b->for_sorting_);
92 literals_.emplace_back(BooleanVariable(solver->
NumVariables()),
true);
94 if (literals_.size() > 1) {
96 literals_[literals_.size() - 2]);
103 while (i < literals_.size() &&
108 literals_.erase(literals_.begin(), literals_.begin() + i);
109 while (!literals_.empty() &&
111 literals_.pop_back();
112 ub_ = lb_ + literals_.size();
126 if (
size() <= new_size)
return;
127 for (
int i = new_size.value(); i <
size(); ++i) {
130 literals_.resize(new_size.value());
131 ub_ = lb_ + literals_.size();
136 const int index = weight_lb_ - lb_;
138 while (
index >= literals_.size()) {
142 return literals_[
index].Negated();
146 CHECK_LT(weight_lb_ - lb_, literals_.size());
151 return weight_ == 0 || weight_lb_ >= ub_;
157 absl::StrAppend(&result,
"depth:", depth_);
158 absl::StrAppend(&result,
" [", lb_,
",", lb_ + literals_.size(),
"]");
159 absl::StrAppend(&result,
" ub:", ub_);
160 absl::StrAppend(&result,
" weight:", weight_.value());
161 absl::StrAppend(&result,
" weight_lb:", weight_lb_);
162 absl::StrAppend(&result,
" values:");
163 const size_t limit = 20;
165 for (
int i = 0; i <
std::min(literals_.size(), limit); ++i) {
175 absl::StrAppend(&result,
" val:", lb_ +
value);
191 std::vector<EncodingNode*> to_process;
192 to_process.push_back(node);
199 const bool complete_encoding =
false;
201 while (!to_process.empty()) {
205 to_process.pop_back();
216 if (
a->current_ub() !=
a->ub()) {
217 CHECK_GE(
a->current_ub() - 1 +
b->lb(), target - 1);
218 if (
a->current_ub() - 1 +
b->lb() < target) {
219 CHECK(
a->IncreaseCurrentUB(solver));
220 to_process.push_back(
a);
225 if (
b->current_ub() !=
b->ub()) {
226 CHECK_GE(
b->current_ub() - 1 +
a->lb(), target - 1);
227 if (
b->current_ub() - 1 +
a->lb() < target) {
228 CHECK(
b->IncreaseCurrentUB(solver));
229 to_process.push_back(
b);
234 for (
int ia =
a->lb(); ia < a->current_ub(); ++ia) {
235 const int ib = target - ia;
236 if (complete_encoding && ib >=
b->lb() && ib < b->current_ub()) {
239 a->GreaterThan(ia),
b->GreaterThan(ib));
241 if (complete_encoding && ib ==
b->ub()) {
246 if (ib - 1 ==
b->lb() - 1) {
248 a->GreaterThan(ia).Negated());
250 if ((ib - 1) >=
b->lb() && (ib - 1) <
b->current_ub()) {
253 a->GreaterThan(ia).Negated(),
254 b->GreaterThan(ib - 1).Negated());
260 const int ib = target - (
a->lb() - 1);
261 if ((ib - 1) ==
b->lb() - 1) {
264 if ((ib - 1) >=
b->lb() && (ib - 1) <
b->current_ub()) {
266 b->GreaterThan(ib - 1).Negated());
272 const int ib = target -
a->ub();
273 if (complete_encoding && ib >=
b->lb() && ib <
b->current_ub()) {
290 for (
int ia = 0; ia <
a->size(); ++ia) {
291 if (ia +
b->size() < size) {
302 for (
int ib = 0; ib <
b->size(); ++ib) {
303 if (ib +
a->size() < size) {
314 for (
int ia = 0; ia <
a->size(); ++ia) {
315 for (
int ib = 0; ib <
b->size(); ++ib) {
316 if (ia + ib < size) {
321 if (ia + ib + 1 < size) {
324 a->literal(ia).Negated(),
325 b->literal(ib).Negated());
328 b->literal(ib).Negated());
336 const std::vector<EncodingNode*>&
nodes,
338 std::deque<EncodingNode>* repository) {
339 std::deque<EncodingNode*> dq(
nodes.begin(),
nodes.end());
340 while (dq.size() > 1) {
346 dq.push_back(&repository->back());
352struct SortEncodingNodePointers {
353 bool operator()(EncodingNode*
a, EncodingNode*
b)
const {
return *
a < *
b; }
359 SatSolver* solver, std::deque<EncodingNode>* repository) {
360 std::priority_queue<EncodingNode*, std::vector<EncodingNode*>,
361 SortEncodingNodePointers>
363 while (pq.size() > 2) {
369 pq.push(&repository->back());
386 const std::vector<Literal>& literals,
387 const std::vector<Coefficient>& coeffs,
Coefficient* offset,
388 std::deque<EncodingNode>* repository) {
389 CHECK_EQ(literals.size(), coeffs.size());
391 std::vector<EncodingNode*>
nodes;
392 for (
int i = 0; i < literals.size(); ++i) {
395 repository->emplace_back(literals[i]);
396 nodes.push_back(&repository->back());
397 nodes.back()->set_weight(coeffs[i]);
399 repository->emplace_back(literals[i].Negated());
400 nodes.push_back(&repository->back());
401 nodes.back()->set_weight(-coeffs[i]);
404 *offset -= coeffs[i];
411 const LinearObjective& objective_proto,
Coefficient* offset,
412 std::deque<EncodingNode>* repository) {
414 std::vector<EncodingNode*>
nodes;
415 for (
int i = 0; i < objective_proto.literals_size(); ++i) {
419 if (objective_proto.coefficients(i) > 0) {
420 repository->emplace_back(
literal);
421 nodes.push_back(&repository->back());
425 nodes.push_back(&repository->back());
429 *offset -= objective_proto.coefficients(i);
437bool EncodingNodeByWeight(
const EncodingNode*
a,
const EncodingNode*
b) {
438 return a->weight() <
b->weight();
441bool EncodingNodeByDepth(
const EncodingNode*
a,
const EncodingNode*
b) {
442 return a->depth() <
b->depth();
463 if (gap < 0)
return {};
465 n->ApplyWeightUpperBound(gap, solver);
475 switch (solver->
parameters().max_sat_assumption_order()) {
476 case SatParameters::DEFAULT_ASSUMPTION_ORDER:
478 case SatParameters::ORDER_ASSUMPTION_BY_DEPTH:
479 std::sort(
nodes->begin(),
nodes->end(), EncodingNodeByDepth);
481 case SatParameters::ORDER_ASSUMPTION_BY_WEIGHT:
482 std::sort(
nodes->begin(),
nodes->end(), EncodingNodeByWeight);
485 if (solver->
parameters().max_sat_reverse_assumption_order()) {
492 std::vector<Literal> assumptions;
494 if (n->weight() >= stratified_lower_bound) {
495 assumptions.push_back(n->GetAssumption(solver));
502 const std::vector<Literal>& core) {
505 for (
int i = 0; i < core.size(); ++i) {
507 nodes[
index]->GetAssumption(
nullptr) != core[i];
522 result =
std::max(result, n->weight());
529 std::deque<EncodingNode>* repository,
533 if (core.size() == 1) {
540 int new_node_index = 0;
541 std::vector<EncodingNode*> to_merge;
542 for (
int i = 0; i < core.size(); ++i) {
546 for (; (*nodes)[
index]->GetAssumption(
nullptr) != core[i]; ++
index) {
548 (*nodes)[new_node_index] = (*nodes)[
index];
561 (*nodes)[new_node_index] = (*nodes)[
index];
567 (*nodes)[new_node_index] = (*nodes)[
index];
570 nodes->resize(new_node_index);
572 solver, repository));
578 std::deque<EncodingNode>* repository,
579 std::vector<EncodingNode*>*
nodes,
584 if (core.size() == 1) {
588 std::vector<EncodingNode*> new_nodes;
589 std::vector<EncodingNode*> to_merge;
599 for (
int i = 0; i < core.size(); ++i) {
604 for (; (*nodes)[
index]->GetAssumption(
nullptr) != core[i]; ++
index) {
620 repository->emplace_back(lit);
624 to_merge.push_back(new_bool_node);
625 if (n->
weight() > min_weight) {
627 new_nodes.push_back(new_bool_node);
631 new_nodes.push_back(n);
640 solver, repository));
#define CHECK_LT(val1, val2)
#define CHECK_EQ(val1, val2)
#define CHECK_GE(val1, val2)
#define CHECK_GT(val1, val2)
#define CHECK_NE(val1, val2)
void InitializeLazyCoreNode(Coefficient weight, EncodingNode *a, EncodingNode *b)
Literal GetAssumption(SatSolver *solver)
bool IncreaseCurrentUB(SatSolver *solver)
void ApplyWeightUpperBound(Coefficient gap, SatSolver *solver)
Coefficient Reduce(const SatSolver &solver)
EncodingNode * child_b() const
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_a() 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
const VariablesAssignment & Assignment() const
bool AddBinaryClause(Literal a, Literal b)
void Backtrack(int target_level)
bool IsModelUnsat() const
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.