24#include "absl/container/flat_hash_set.h"
25#include "absl/log/check.h"
26#include "absl/log/log.h"
27#include "absl/strings/str_cat.h"
28#include "absl/types/span.h"
29#include "google/protobuf/arena.h"
30#include "google/protobuf/repeated_field.h"
31#include "google/protobuf/repeated_ptr_field.h"
32#include "google/protobuf/text_format.h"
48 if (context_->params().ignore_names()) {
49 context_->working_model->clear_variables();
50 context_->working_model->mutable_variables()->Reserve(
53 *context_->working_model->add_variables()->mutable_domain() =
57 *context_->working_model->mutable_variables() = in_model.
variables();
62 for (
const Domain& domain : domains) {
74 std::function<
bool(
int)> active_constraints) {
75 context_->InitializeNewDomains();
76 if (context_->ModelIsUnsat())
return false;
77 const bool ignore_names = context_->params().ignore_names();
81 std::vector<int> constraints_using_intervals;
83 interval_mapping_.assign(in_model.
constraints().size(), -1);
85 starting_constraint_index_ = context_->working_model->constraints_size();
87 if (active_constraints !=
nullptr && !active_constraints(c)) {
92 if (!PrepareEnforcementCopyWithDup(ct))
continue;
94 if (!PrepareEnforcementCopy(ct))
continue;
105 if (!CopyBoolOrWithDupSupport(ct))
return CreateUnsatModel(c, ct);
107 if (!CopyBoolOr(ct))
return CreateUnsatModel(c, ct);
111 if (temp_enforcement_literals_.empty()) {
113 context_->UpdateRuleStats(
"bool_and: non-reified.");
114 if (!context_->SetLiteralToTrue(lit)) {
115 return CreateUnsatModel(c, ct);
118 }
else if (first_copy) {
119 if (!CopyBoolAndWithDupSupport(ct))
return CreateUnsatModel(c, ct);
121 if (!CopyBoolAnd(ct))
return CreateUnsatModel(c, ct);
125 if (!CopyLinear(ct, first_copy)) {
126 return CreateUnsatModel(c, ct);
130 if (!CopyIntProd(ct, ignore_names))
return CreateUnsatModel(c, ct);
133 if (!CopyIntDiv(ct, ignore_names))
return CreateUnsatModel(c, ct);
136 if (!CopyIntMod(ct, ignore_names))
return CreateUnsatModel(c, ct);
139 if (!CopyElement(ct))
return CreateUnsatModel(c, ct);
142 if (!CopyTable(ct))
return CreateUnsatModel(c, ct);
145 if (!CopyAutomaton(ct))
return CreateUnsatModel(c, ct);
148 if (!CopyAllDiff(ct))
return CreateUnsatModel(c, ct);
151 if (!CopyLinMax(ct))
return CreateUnsatModel(c, ct);
154 if (!CopyAtMostOne(ct))
return CreateUnsatModel(c, ct);
157 if (!CopyExactlyOne(ct))
return CreateUnsatModel(c, ct);
160 if (!CopyInterval(ct, c, ignore_names))
return CreateUnsatModel(c, ct);
162 if (!AddLinearConstraintForInterval(ct))
163 return CreateUnsatModel(c, ct);
168 constraints_using_intervals.push_back(c);
170 CopyAndMapNoOverlap(ct);
175 constraints_using_intervals.push_back(c);
177 CopyAndMapNoOverlap2D(ct);
182 constraints_using_intervals.push_back(c);
184 if (!CopyAndMapCumulative(ct))
return CreateUnsatModel(c, ct);
191 FinishEnforcementCopy(new_ct);
201 DCHECK(first_copy || constraints_using_intervals.empty());
202 for (
const int c : constraints_using_intervals) {
206 CopyAndMapNoOverlap(ct);
209 CopyAndMapNoOverlap2D(ct);
212 if (!CopyAndMapCumulative(ct))
return CreateUnsatModel(c, ct);
215 LOG(DFATAL) <<
"Shouldn't be here.";
223 temp_enforcement_literals_.clear();
230 temp_enforcement_literals_.push_back(lit);
235bool ModelCopy::PrepareEnforcementCopyWithDup(
const ConstraintProto& ct) {
236 temp_enforcement_literals_.clear();
237 temp_enforcement_literals_set_.clear();
238 for (
const int lit : ct.enforcement_literal()) {
239 if (context_->LiteralIsTrue(lit))
continue;
240 if (temp_enforcement_literals_set_.contains(lit)) {
241 context_->UpdateRuleStats(
"enforcement: removed duplicate literal");
246 if (context_->LiteralIsFalse(lit)) {
247 context_->UpdateRuleStats(
"enforcement: always false");
250 if (temp_enforcement_literals_set_.contains(
NegatedRef(lit))) {
251 context_->UpdateRuleStats(
"enforcement: contains x and not(x)");
255 temp_enforcement_literals_.push_back(lit);
256 temp_enforcement_literals_set_.insert(lit);
262 ct->mutable_enforcement_literal()->Add(temp_enforcement_literals_.begin(),
263 temp_enforcement_literals_.end());
266bool ModelCopy::FinishBoolOrCopy() {
267 if (temp_literals_.empty())
return false;
269 if (temp_literals_.size() == 1) {
270 context_->UpdateRuleStats(
"bool_or: only one literal");
271 return context_->SetLiteralToTrue(temp_literals_[0]);
274 context_->working_model->add_constraints()
277 ->Add(temp_literals_.begin(), temp_literals_.end());
282 temp_literals_.clear();
283 for (
const int lit : temp_enforcement_literals_) {
286 for (
const int lit : ct.bool_or().literals()) {
287 if (context_->LiteralIsTrue(lit)) {
290 if (!context_->LiteralIsFalse(lit)) {
291 temp_literals_.push_back(lit);
294 return FinishBoolOrCopy();
298 temp_literals_.clear();
299 temp_literals_set_.clear();
300 for (
const int enforcement_lit : temp_enforcement_literals_) {
307 temp_literals_set_.insert(lit);
308 temp_literals_.push_back(lit);
310 for (
const int lit : ct.bool_or().literals()) {
311 if (context_->LiteralIsTrue(lit)) {
312 context_->UpdateRuleStats(
"bool_or: always true");
315 if (context_->LiteralIsFalse(lit))
continue;
316 if (temp_literals_set_.contains(
NegatedRef(lit))) {
317 context_->UpdateRuleStats(
"bool_or: always true");
320 const auto [it, inserted] = temp_literals_set_.insert(lit);
321 if (inserted) temp_literals_.push_back(lit);
323 return FinishBoolOrCopy();
327 bool at_least_one_false =
false;
328 int num_non_fixed_literals = 0;
329 for (
const int lit : ct.bool_and().literals()) {
330 if (context_->LiteralIsFalse(lit)) {
331 at_least_one_false =
true;
334 if (!context_->LiteralIsTrue(lit)) {
335 num_non_fixed_literals++;
339 if (at_least_one_false) {
341 BoolArgumentProto* bool_or =
342 context_->working_model->add_constraints()->mutable_bool_or();
343 for (
const int lit : temp_enforcement_literals_) {
346 return !bool_or->literals().empty();
347 }
else if (num_non_fixed_literals > 0) {
348 ConstraintProto* new_ct = context_->working_model->add_constraints();
349 FinishEnforcementCopy(new_ct);
350 BoolArgumentProto* bool_and = new_ct->mutable_bool_and();
351 bool_and->mutable_literals()->Reserve(num_non_fixed_literals);
352 for (
const int lit : ct.bool_and().literals()) {
353 if (context_->LiteralIsTrue(lit))
continue;
354 bool_and->add_literals(lit);
361 DCHECK(!temp_enforcement_literals_.empty());
363 bool at_least_one_false =
false;
364 temp_literals_.clear();
365 temp_literals_set_.clear();
366 for (
const int lit : ct.bool_and().literals()) {
367 if (context_->LiteralIsFalse(lit)) {
368 context_->UpdateRuleStats(
"bool and: always false");
369 at_least_one_false =
true;
372 if (temp_literals_set_.contains(
NegatedRef(lit))) {
373 context_->UpdateRuleStats(
"bool and: => x and not(x) ");
374 at_least_one_false =
true;
377 if (temp_enforcement_literals_set_.contains(
NegatedRef(lit))) {
378 context_->UpdateRuleStats(
"bool and: not(x) => x");
379 at_least_one_false =
true;
383 if (context_->LiteralIsTrue(lit))
continue;
384 if (temp_enforcement_literals_set_.contains(lit)) {
385 context_->UpdateRuleStats(
"bool and: x => x");
388 const auto [it, inserted] = temp_literals_set_.insert(lit);
389 if (inserted) temp_literals_.push_back(lit);
392 if (at_least_one_false) {
394 BoolArgumentProto* bool_or =
395 context_->working_model->add_constraints()->mutable_bool_or();
396 for (
const int lit : temp_enforcement_literals_) {
399 return !bool_or->literals().empty();
402 if (temp_literals_.empty()) {
403 context_->UpdateRuleStats(
"bool and: empty");
408 ConstraintProto* new_ct = context_->working_model->add_constraints();
409 FinishEnforcementCopy(new_ct);
410 new_ct->mutable_bool_and()->mutable_literals()->Add(temp_literals_.begin(),
411 temp_literals_.end());
415bool ModelCopy::CopyLinearExpression(
417 absl::Span<const int> enforcement_literals) {
418 non_fixed_variables_.clear();
419 non_fixed_coefficients_.clear();
420 int64_t offset = expr.offset();
421 for (
int i = 0;
i < expr.vars_size(); ++
i) {
422 const int ref = expr.vars(
i);
423 const int64_t coeff = expr.coeffs(
i);
424 if (coeff == 0)
continue;
425 if (context_->IsFixed(ref)) {
426 offset += coeff * context_->MinOf(ref);
432 non_fixed_variables_.push_back(ref);
433 non_fixed_coefficients_.push_back(coeff);
435 non_fixed_variables_.push_back(
NegatedRef(ref));
436 non_fixed_coefficients_.push_back(-coeff);
440 dst->set_offset(offset);
441 dst->mutable_vars()->Add(non_fixed_variables_.begin(),
442 non_fixed_variables_.end());
443 dst->mutable_coeffs()->Add(non_fixed_coefficients_.begin(),
444 non_fixed_coefficients_.end());
447 context_->CanonicalizeLinearExpression(enforcement_literals, dst);
451bool ModelCopy::CopyLinear(
const ConstraintProto& ct,
bool canonicalize) {
452 non_fixed_variables_.clear();
453 non_fixed_coefficients_.clear();
455 int64_t min_activity = 0;
456 int64_t max_activity = 0;
457 for (
int i = 0;
i < ct.linear().vars_size(); ++
i) {
458 const int ref = ct.linear().vars(
i);
459 const int64_t coeff = ct.linear().coeffs(
i);
460 if (coeff == 0)
continue;
461 if (context_->IsFixed(ref)) {
462 offset += coeff * context_->MinOf(ref);
467 min_activity += coeff * context_->MinOf(ref);
468 max_activity += coeff * context_->MaxOf(ref);
470 min_activity += coeff * context_->MaxOf(ref);
471 max_activity += coeff * context_->MinOf(ref);
476 non_fixed_variables_.push_back(ref);
477 non_fixed_coefficients_.push_back(coeff);
479 non_fixed_variables_.push_back(
NegatedRef(ref));
480 non_fixed_coefficients_.push_back(-coeff);
484 const Domain implied(min_activity, max_activity);
485 const Domain new_rhs =
489 if (implied.IsIncludedIn(new_rhs)) {
490 context_->UpdateRuleStats(
"linear: always true");
496 if (tight_domain.IsEmpty()) {
497 if (ct.enforcement_literal().empty())
return false;
498 temp_literals_.clear();
499 for (
const int literal : ct.enforcement_literal()) {
500 if (!context_->LiteralIsTrue(literal)) {
501 temp_literals_.push_back(
NegatedRef(literal));
504 context_->working_model->add_constraints()
507 ->Add(temp_literals_.begin(), temp_literals_.end());
508 return !temp_literals_.empty();
511 DCHECK(!non_fixed_variables_.empty());
513 if (non_fixed_variables_.size() == 1 && ct.enforcement_literal().empty()) {
514 context_->UpdateRuleStats(
"linear1: x in domain");
515 return context_->IntersectDomainWith(
516 non_fixed_variables_[0],
517 new_rhs.InverseMultiplicationBy(non_fixed_coefficients_[0]));
520 ConstraintProto* new_ct = context_->working_model->add_constraints();
521 FinishEnforcementCopy(new_ct);
522 LinearConstraintProto* linear = new_ct->mutable_linear();
523 linear->mutable_vars()->Add(non_fixed_variables_.begin(),
524 non_fixed_variables_.end());
525 linear->mutable_coeffs()->Add(non_fixed_coefficients_.begin(),
526 non_fixed_coefficients_.end());
529 context_->CanonicalizeLinearConstraint(new_ct);
532 if (new_ct->linear().vars().empty() &&
534 context_->UpdateRuleStats(
"linear: trivial 0=0");
535 context_->working_model->mutable_constraints()->RemoveLast();
543 ConstraintProto* new_ct = context_->working_model->add_constraints();
544 if (ct.element().vars().empty() && !ct.element().exprs().empty()) {
550 auto fill_expr = [
this](
int var, LinearExpressionProto* expr)
mutable {
551 if (context_->IsFixed(var)) {
552 expr->set_offset(context_->FixedValue(var));
555 expr->mutable_vars()->Reserve(1);
556 expr->mutable_coeffs()->Reserve(1);
562 fill_expr(ct.element().index(),
563 new_ct->mutable_element()->mutable_linear_index());
564 fill_expr(ct.element().target(),
565 new_ct->mutable_element()->mutable_linear_target());
566 for (
const int var : ct.element().vars()) {
567 fill_expr(var, new_ct->mutable_element()->add_exprs());
573 ConstraintProto* new_ct = context_->working_model->add_constraints();
575 if (new_ct->automaton().vars().empty())
return true;
577 auto fill_expr = [
this](
int var, LinearExpressionProto* expr)
mutable {
578 if (context_->IsFixed(var)) {
579 expr->set_offset(context_->FixedValue(var));
582 expr->mutable_vars()->Reserve(1);
583 expr->mutable_coeffs()->Reserve(1);
589 for (
const int var : ct.automaton().vars()) {
590 fill_expr(var, new_ct->mutable_automaton()->add_exprs());
592 new_ct->mutable_automaton()->clear_vars();
598 ConstraintProto* new_ct = context_->working_model->add_constraints();
599 if (ct.table().vars().empty() && !ct.table().exprs().empty()) {
605 auto fill_expr = [
this](
int var, LinearExpressionProto* expr)
mutable {
606 if (context_->IsFixed(var)) {
607 expr->set_offset(context_->FixedValue(var));
610 expr->mutable_vars()->Reserve(1);
611 expr->mutable_coeffs()->Reserve(1);
617 for (
const int var : ct.table().vars()) {
618 fill_expr(var, new_ct->mutable_table()->add_exprs());
620 *new_ct->mutable_table()->mutable_values() = ct.table().values();
621 new_ct->mutable_table()->set_negated(ct.table().negated());
622 *new_ct->mutable_enforcement_literal() = ct.enforcement_literal();
628 if (ct.all_diff().exprs().size() <= 1)
return true;
629 ConstraintProto* new_ct = context_->working_model->add_constraints();
630 for (
const LinearExpressionProto& expr : ct.all_diff().exprs()) {
631 CopyLinearExpression(expr, new_ct->mutable_all_diff()->add_exprs());
638 ConstraintProto* new_ct =
nullptr;
641 int64_t max_of_fixed_terms = std::numeric_limits<int64_t>::min();
642 for (
const auto& expr : ct.lin_max().exprs()) {
643 const std::optional<int64_t> fixed = context_->FixedValueOrNullopt(expr);
644 if (fixed != std::nullopt) {
645 max_of_fixed_terms = std::max(max_of_fixed_terms, fixed.value());
648 if (new_ct ==
nullptr) {
649 new_ct = context_->working_model->add_constraints();
651 CopyLinearExpression(expr, new_ct->mutable_lin_max()->add_exprs());
657 if (new_ct ==
nullptr && ct.enforcement_literal().empty() &&
658 ct.lin_max().target().vars().size() <= 1) {
659 context_->UpdateRuleStats(
"lin_max: all exprs fixed during copy");
660 return context_->IntersectDomainWith(ct.lin_max().target(),
661 Domain(max_of_fixed_terms));
665 if (max_of_fixed_terms > std::numeric_limits<int64_t>::min()) {
666 if (new_ct ==
nullptr) {
667 new_ct = context_->working_model->add_constraints();
669 new_ct->mutable_lin_max()->add_exprs()->set_offset(max_of_fixed_terms);
673 if (new_ct ==
nullptr)
return false;
674 CopyLinearExpression(ct.lin_max().target(),
675 new_ct->mutable_lin_max()->mutable_target());
681 temp_literals_.clear();
682 for (
const int lit : ct.at_most_one().literals()) {
683 if (context_->LiteralIsFalse(lit))
continue;
684 temp_literals_.push_back(lit);
685 if (context_->LiteralIsTrue(lit)) num_true++;
688 if (temp_literals_.size() <= 1)
return true;
689 if (num_true > 1)
return false;
692 ConstraintProto* new_ct = context_->working_model->add_constraints();
693 FinishEnforcementCopy(new_ct);
694 new_ct->mutable_at_most_one()->mutable_literals()->Add(temp_literals_.begin(),
695 temp_literals_.end());
701 temp_literals_.clear();
702 for (
const int lit : ct.exactly_one().literals()) {
703 if (context_->LiteralIsFalse(lit))
continue;
704 temp_literals_.push_back(lit);
705 if (context_->LiteralIsTrue(lit)) num_true++;
708 if (temp_literals_.empty() || num_true > 1)
return false;
709 if (temp_literals_.size() == 1 && num_true == 1)
return true;
712 ConstraintProto* new_ct = context_->working_model->add_constraints();
713 FinishEnforcementCopy(new_ct);
714 new_ct->mutable_exactly_one()->mutable_literals()->Add(temp_literals_.begin(),
715 temp_literals_.end());
721 CHECK_EQ(starting_constraint_index_, 0)
722 <<
"Adding new interval constraints to partially filled model is not "
724 interval_mapping_[
c] = context_->working_model->constraints_size();
725 ConstraintProto* new_ct = context_->working_model->add_constraints();
727 new_ct->set_name(ct.name());
729 *new_ct->mutable_enforcement_literal() = ct.enforcement_literal();
730 CopyLinearExpression(ct.interval().start(),
731 new_ct->mutable_interval()->mutable_start(),
732 ct.enforcement_literal());
733 CopyLinearExpression(ct.interval().size(),
734 new_ct->mutable_interval()->mutable_size(),
735 ct.enforcement_literal());
736 CopyLinearExpression(ct.interval().end(),
737 new_ct->mutable_interval()->mutable_end(),
738 ct.enforcement_literal());
742bool ModelCopy::CopyIntProd(
const ConstraintProto& ct,
bool ignore_names) {
743 ConstraintProto* new_ct = context_->working_model->add_constraints();
745 new_ct->set_name(ct.name());
747 for (
const LinearExpressionProto& expr : ct.int_prod().exprs()) {
748 CopyLinearExpression(expr, new_ct->mutable_int_prod()->add_exprs());
750 CopyLinearExpression(ct.int_prod().target(),
751 new_ct->mutable_int_prod()->mutable_target());
755bool ModelCopy::CopyIntDiv(
const ConstraintProto& ct,
bool ignore_names) {
756 ConstraintProto* new_ct = context_->working_model->add_constraints();
758 new_ct->set_name(ct.name());
760 for (
const LinearExpressionProto& expr : ct.int_div().exprs()) {
761 CopyLinearExpression(expr, new_ct->mutable_int_div()->add_exprs());
763 CopyLinearExpression(ct.int_div().target(),
764 new_ct->mutable_int_div()->mutable_target());
768bool ModelCopy::CopyIntMod(
const ConstraintProto& ct,
bool ignore_names) {
769 ConstraintProto* new_ct = context_->working_model->add_constraints();
771 new_ct->set_name(ct.name());
773 for (
const LinearExpressionProto& expr : ct.int_mod().exprs()) {
774 CopyLinearExpression(expr, new_ct->mutable_int_mod()->add_exprs());
776 CopyLinearExpression(ct.int_mod().target(),
777 new_ct->mutable_int_mod()->mutable_target());
781bool ModelCopy::AddLinearConstraintForInterval(
const ConstraintProto& ct) {
786 const IntervalConstraintProto& itv = ct.interval();
787 if (itv.size().vars().empty() &&
788 itv.start().offset() + itv.size().offset() == itv.end().offset() &&
789 absl::Span<const int>(itv.start().vars()) ==
790 absl::Span<const int>(itv.end().vars()) &&
791 absl::Span<const int64_t>(itv.start().coeffs()) ==
792 absl::Span<const int64_t>(itv.end().coeffs())) {
795 tmp_constraint_.Clear();
796 *tmp_constraint_.mutable_enforcement_literal() = ct.enforcement_literal();
797 LinearConstraintProto* mutable_linear = tmp_constraint_.mutable_linear();
799 mutable_linear->add_domain(0);
800 mutable_linear->add_domain(0);
804 if (!CopyLinear(tmp_constraint_,
true))
return false;
808 const LinearExpressionProto& size_expr = itv.size();
809 if (context_->MinOf(size_expr) < 0) {
810 tmp_constraint_.Clear();
811 *tmp_constraint_.mutable_enforcement_literal() = ct.enforcement_literal();
812 *tmp_constraint_.mutable_linear()->mutable_vars() = size_expr.vars();
813 *tmp_constraint_.mutable_linear()->mutable_coeffs() = size_expr.coeffs();
814 tmp_constraint_.mutable_linear()->add_domain(-size_expr.offset());
815 tmp_constraint_.mutable_linear()->add_domain(
816 std::numeric_limits<int64_t>::max());
817 if (!CopyLinear(tmp_constraint_,
true))
return false;
826 context_->working_model->add_constraints()->mutable_no_overlap();
827 new_ct->mutable_intervals()->Reserve(ct.no_overlap().intervals().size());
828 for (
const int index : ct.no_overlap().intervals()) {
829 const int new_index = interval_mapping_[index];
830 if (new_index != -1) {
831 new_ct->add_intervals(new_index);
839 context_->working_model->add_constraints()->mutable_no_overlap_2d();
841 const int num_intervals = ct.no_overlap_2d().x_intervals().size();
842 new_ct->mutable_x_intervals()->Reserve(num_intervals);
843 new_ct->mutable_y_intervals()->Reserve(num_intervals);
844 for (
int i = 0;
i < num_intervals; ++
i) {
845 const int new_x = interval_mapping_[ct.no_overlap_2d().x_intervals(
i)];
846 if (new_x == -1)
continue;
847 const int new_y = interval_mapping_[ct.no_overlap_2d().y_intervals(
i)];
848 if (new_y == -1)
continue;
849 new_ct->add_x_intervals(new_x);
850 new_ct->add_y_intervals(new_y);
855 if (ct.cumulative().intervals().empty() &&
856 context_->IsFixed(ct.cumulative().capacity())) {
858 return context_->FixedValue(ct.cumulative().capacity()) >= 0;
862 context_->working_model->add_constraints()->mutable_cumulative();
863 CopyLinearExpression(ct.cumulative().capacity(), new_ct->mutable_capacity());
865 const int num_intervals = ct.cumulative().intervals().size();
866 new_ct->mutable_intervals()->Reserve(num_intervals);
867 new_ct->mutable_demands()->Reserve(num_intervals);
868 for (
int i = 0;
i < num_intervals; ++
i) {
869 const int new_index = interval_mapping_[ct.cumulative().intervals(
i)];
870 if (new_index != -1) {
871 new_ct->add_intervals(new_index);
872 CopyLinearExpression(ct.cumulative().demands(
i), new_ct->add_demands());
880 context_->working_model->mutable_constraints()->Clear();
881 context_->working_model->add_constraints()->mutable_bool_or();
885 if (context_->ModelIsUnsat())
return false;
887 std::string proto_string;
888#if !defined(__PORTABLE_PLATFORM__)
889 google::protobuf::TextFormat::Printer printer;
891 printer.PrintToString(ct, &proto_string);
893 std::string message = absl::StrCat(
894 "proven during initial copy of constraint #", c,
":\n", proto_string);
896 if (vars.size() < 10) {
897 absl::StrAppend(&message,
"With current variable domains:\n");
898 for (
const int var : vars) {
899 absl::StrAppend(&message,
"var:", var,
900 " domain:", context_->DomainOf(var).ToString(),
"\n");
903 return context_->NotifyThatModelIsUnsat(message);
919 const CpModelProto& in_model, absl::Span<const Domain> domains,
921 std::vector<int>* interval_mapping) {
926 active_constraints)) {
938 if (!in_model.
name().empty()) {
956 return expr->vars().empty();
958 if (!strategy.variables().empty()) {
959 CHECK(strategy.exprs().empty());
960 for (
const int ref : strategy.variables()) {
965 strategy.clear_variables();
983 for (
int i = 0;
i < num_terms; ++
i) {
987 if (domain.
IsEmpty())
continue;
988 const int64_t closest_domain_value = domain.
ClosestValue(value);
989 if (closest_domain_value != value) {
992 i, closest_domain_value);
Domain IntersectionWith(const Domain &domain) const
bool Contains(int64_t value) const
Domain AdditionWith(const Domain &domain) const
int64_t ClosestValue(int64_t wanted) const
::int32_t literals(int index) const
ConstraintCase constraint_case() const
::int32_t enforcement_literal(int index) const
void clear_name()
string name = 1;
const ::operations_research::sat::BoolArgumentProto & bool_and() const
::google::protobuf::RepeatedField<::int32_t > *PROTOBUF_NONNULL mutable_enforcement_literal()
::operations_research::sat::FloatObjectiveProto *PROTOBUF_NONNULL mutable_floating_point_objective()
bool has_symmetry() const
.operations_research.sat.SymmetryProto symmetry = 8;
bool has_solution_hint() const
.operations_research.sat.PartialVariableAssignment solution_hint = 6;
bool has_floating_point_objective() const
.operations_research.sat.FloatObjectiveProto floating_point_objective = 9;
const ::operations_research::sat::SymmetryProto & symmetry() const
const ::operations_research::sat::IntegerVariableProto & variables(int index) const
const ::operations_research::sat::FloatObjectiveProto & floating_point_objective() const
const ::operations_research::sat::ConstraintProto & constraints(int index) const
bool has_objective() const
.operations_research.sat.CpObjectiveProto objective = 4;
const ::operations_research::sat::DecisionStrategyProto & search_strategy(int index) const
::int32_t assumptions(int index) const
int constraints_size() const
repeated .operations_research.sat.ConstraintProto constraints = 3;
void set_name(Arg_ &&arg, Args_... args)
::operations_research::sat::SymmetryProto *PROTOBUF_NONNULL mutable_symmetry()
::operations_research::sat::PartialVariableAssignment *PROTOBUF_NONNULL mutable_solution_hint()
int variables_size() const
repeated .operations_research.sat.IntegerVariableProto variables = 2;
::operations_research::sat::CpObjectiveProto *PROTOBUF_NONNULL mutable_objective()
::google::protobuf::RepeatedField<::int32_t > *PROTOBUF_NONNULL mutable_assumptions()
const ::std::string & name() const
::operations_research::sat::DecisionStrategyProto *PROTOBUF_NONNULL mutable_search_strategy(int index)
const ::operations_research::sat::PartialVariableAssignment & solution_hint() const
const ::operations_research::sat::CpObjectiveProto & objective() const
void add_coeffs(::int64_t value)
void add_vars(::int32_t value)
void ImportVariablesAndMaybeIgnoreNames(const CpModelProto &in_model)
void CreateVariablesFromDomains(absl::Span< const Domain > domains)
ModelCopy(PresolveContext *context)
absl::Span< const int64_t > InternalIntervalMapping() const
bool ImportAndSimplifyConstraints(const CpModelProto &in_model, bool first_copy=false, std::function< bool(int)> active_constraints=nullptr)
void set_values(int index, ::int64_t value)
::int64_t values(int index) const
::int32_t vars(int index) const
CpModelProto * working_model
bool LiteralIsFalse(int lit) const
void UpdateRuleStats(const std::string &name, int num_times=1)
bool ModelIsUnsat() const
bool LiteralIsTrue(int lit) const
int RemoveIf(RepeatedPtrField< T > *array, const Pred &pr)
bool RefIsPositive(int ref)
bool ImportModelWithBasicPresolveIntoContext(const CpModelProto &in_model, PresolveContext *context)
std::vector< int > UsedVariables(const ConstraintProto &ct)
void FillDomainInProto(const Domain &domain, ProtoWithDomain *proto)
Serializes a Domain into the domain field of a proto.
Domain ReadDomainFromProto(const ProtoWithDomain &proto)
Reads a Domain from the domain field of a proto.
void SetupTextFormatPrinter(google::protobuf::TextFormat::Printer *printer)
void CopyEverythingExceptVariablesAndConstraintsFieldsIntoContext(const CpModelProto &in_model, PresolveContext *context)
Copies the non constraint, non variables part of the model.
bool ImportModelAndDomainsWithBasicPresolveIntoContext(const CpModelProto &in_model, absl::Span< const Domain > domains, std::function< bool(int)> active_constraints, PresolveContext *context, std::vector< int > *interval_mapping)
void AddLinearExpressionToLinearConstraint(const LinearExpressionProto &expr, int64_t coefficient, LinearConstraintProto *linear)
int NegatedRef(int ref)
Small utility functions to deal with negative variable/literal references.
In SWIG mode, we don't want anything besides these top-level includes.