20#include "absl/types/span.h"
40 const std::vector<AffineExpression>& exprs,
41 const std::vector<Literal>& selectors,
43 : enforcement_literal_(enforcement_literal),
46 selectors_(selectors),
55 const
Literal enforcement_literal_;
74 const auto add_var_non_selection_to_reason = [&](
int i) {
76 literal_reason_.push_back(selectors_[i]);
78 const auto add_var_selection_to_reason = [&](
int i) {
80 literal_reason_.push_back(selectors_[i].Negated());
90 enforcement_lit.
Index()) {
97 if (i_lit.bound > integer_trail_->
UpperBound(i_lit.var)) {
98 integer_reason_.push_back(
102 literal_reason_, integer_reason_);
108 if (!integer_trail_->
Enqueue(i_lit, literal_reason_, integer_reason_)) {
116 const int num_vars = exprs_.size();
117 const IntegerValue target_min = integer_trail_->
LowerBound(target_);
118 const IntegerValue target_max = integer_trail_->
UpperBound(target_);
125 int num_possible_vars = 0;
126 int num_selected_vars = 0;
127 int min_of_selected_maxes_index = -1;
128 int first_selected = -1;
129 for (
int i = 0; i < num_vars; ++i) {
132 const IntegerValue var_min = integer_trail_->
LowerBound(exprs_[i]);
133 const IntegerValue var_max = integer_trail_->
UpperBound(exprs_[i]);
135 min_of_mins =
std::min(min_of_mins, var_min);
140 if (var_max < min_of_selected_maxes) {
141 min_of_selected_maxes = var_max;
142 min_of_selected_maxes_index = i;
144 if (first_selected == -1) {
150 max_of_possible_maxes =
std::max(max_of_possible_maxes, var_max);
154 if (min_of_mins > target_min) {
155 literal_reason_.clear();
156 integer_reason_.clear();
157 for (
int i = 0; i < num_vars; ++i) {
159 add_var_non_selection_to_reason(i);
164 if (!push_bound(enforcement_literal_,
165 target_.GreaterOrEqual(min_of_mins))) {
170 if (num_selected_vars > 0 && min_of_selected_maxes < target_max) {
172 DCHECK_NE(min_of_selected_maxes_index, -1);
174 literal_reason_.clear();
175 integer_reason_.clear();
176 add_var_selection_to_reason(min_of_selected_maxes_index);
178 integer_reason_.push_back(
180 min_of_selected_maxes));
182 if (!integer_trail_->
Enqueue(target_.LowerOrEqual(min_of_selected_maxes),
183 literal_reason_, integer_reason_)) {
189 if (num_possible_vars > 0 && num_selected_vars == 0) {
190 if (target_max > max_of_possible_maxes) {
191 literal_reason_.clear();
192 integer_reason_.clear();
194 for (
int i = 0; i < num_vars; ++i) {
196 add_var_non_selection_to_reason(i);
198 integer_reason_.push_back(
202 if (!push_bound(enforcement_literal_,
203 target_.LowerOrEqual(max_of_possible_maxes))) {
210 if (!assignment.
LiteralIsTrue(enforcement_literal_))
return true;
217 if (num_possible_vars > 0) {
218 DCHECK_GT(num_possible_vars + num_selected_vars, 1);
221 if (num_selected_vars != 1)
return true;
228 if (target_min > integer_trail_->
LowerBound(unique_selected_var)) {
229 literal_reason_.clear();
230 integer_reason_.clear();
231 for (
int i = 0; i < num_vars; ++i) {
232 if (i != first_selected) {
233 add_var_non_selection_to_reason(i);
235 add_var_selection_to_reason(i);
239 integer_reason_.push_back(target_.GreaterOrEqual(target_min));
242 literal_reason_, integer_reason_)) {
247 if (target_max < integer_trail_->
UpperBound(unique_selected_var)) {
248 literal_reason_.clear();
249 integer_reason_.clear();
250 for (
int i = 0; i < num_vars; ++i) {
251 if (i != first_selected) {
252 add_var_non_selection_to_reason(i);
254 add_var_selection_to_reason(i);
258 integer_reason_.push_back(target_.LowerOrEqual(target_max));
261 literal_reason_, integer_reason_)) {
270 const int id = watcher->
Register(
this);
271 for (
int t = 0; t < exprs_.size(); ++t) {
282 const std::vector<AffineExpression>& exprs,
283 const std::vector<Literal>& selectors) {
284 CHECK_EQ(exprs.size(), selectors.size());
288 for (
int i = 0; i < exprs.size(); ++i) {
290 builder.
AddTerm(target, IntegerValue(1));
291 builder.
AddTerm(exprs[i], IntegerValue(-1));
298 enforcement_literal, target, exprs, selectors,
model);
300 model->TakeOwnership(constraint);
306 const std::vector<AffineExpression>& exprs,
307 const std::vector<Literal>& selectors) {
308 CHECK_EQ(exprs.size(), selectors.size());
310 std::vector<AffineExpression> negations;
312 negations.push_back(expr.Negated());
315 enforcement_literal, target.
Negated(), negations, selectors));
320 IntervalVariable span,
const std::vector<IntervalVariable>& intervals) {
326 if (repository->IsAbsent(span)) {
327 for (
const IntervalVariable
interval : intervals) {
328 if (repository->IsOptional(
interval)) {
329 sat_solver->AddBinaryClause(
330 repository->PresenceLiteral(span).Negated(),
331 repository->PresenceLiteral(
interval));
332 }
else if (repository->IsPresent(
interval)) {
333 sat_solver->NotifyThatModelIsUnsat();
342 std::vector<Literal> presence_literals;
343 std::vector<AffineExpression> starts;
344 std::vector<AffineExpression> ends;
345 std::vector<Literal> clause;
346 bool at_least_one_interval_is_present =
false;
350 for (
const IntervalVariable
interval : intervals) {
351 if (repository->IsAbsent(
interval))
continue;
353 if (repository->IsOptional(
interval)) {
355 presence_literals.push_back(task_lit);
356 clause.push_back(task_lit);
358 if (repository->IsOptional(span)) {
361 repository->PresenceLiteral(span));
365 presence_literals.push_back(true_literal);
366 at_least_one_interval_is_present =
true;
368 starts.push_back(repository->Start(
interval));
369 ends.push_back(repository->End(
interval));
372 if (!at_least_one_interval_is_present) {
374 if (repository->IsOptional(span)) {
375 clause.push_back(repository->PresenceLiteral(span).Negated());
377 sat_solver->AddProblemClause(clause);
381 const Literal enforcement_literal =
382 repository->IsOptional(span)
383 ? repository->PresenceLiteral(span)
386 repository->Start(span), starts,
389 enforcement_literal, repository->End(span), ends, presence_literals));
#define DCHECK_NE(val1, val2)
#define CHECK_EQ(val1, val2)
#define DCHECK_GE(val1, val2)
#define DCHECK_GT(val1, val2)
#define DCHECK(condition)
void WatchLiteral(Literal l, int id, int watch_index=-1)
void WatchAffineExpression(AffineExpression e, int id)
int Register(PropagatorInterface *propagator)
ABSL_MUST_USE_RESULT bool Enqueue(IntegerLiteral i_lit, absl::Span< const Literal > literal_reason, absl::Span< const IntegerLiteral > integer_reason)
LiteralIndex OptionalLiteralIndex(IntegerVariable i) const
void EnqueueLiteral(Literal literal, absl::Span< const Literal > literal_reason, absl::Span< const IntegerLiteral > integer_reason)
IntegerValue UpperBound(IntegerVariable i) const
IntegerValue LowerBound(IntegerVariable i) const
void AddTerm(IntegerVariable var, IntegerValue coeff)
LiteralIndex Index() const
Class that owns everything related to a particular optimization model.
bool AddBinaryClause(Literal a, Literal b)
int RegisterWith(GenericLiteralWatcher *watcher)
SelectedMinPropagator(Literal enforcement_literal, AffineExpression target, const std::vector< AffineExpression > &exprs, const std::vector< Literal > &selectors, Model *model)
const VariablesAssignment & Assignment() const
bool LiteralIsTrue(Literal literal) const
bool LiteralIsFalse(Literal literal) const
constexpr IntegerValue kMaxIntegerValue(std::numeric_limits< IntegerValue::ValueType >::max() - 1)
std::function< void(Model *)> LowerOrEqual(IntegerVariable v, int64_t ub)
void LoadConditionalLinearConstraint(const absl::Span< const Literal > enforcement_literals, const LinearConstraint &cst, Model *model)
constexpr IntegerValue kMinIntegerValue(-kMaxIntegerValue.value())
const IntegerVariable kNoIntegerVariable(-1)
std::function< void(Model *)> EqualMaxOfSelectedVariables(Literal enforcement_literal, AffineExpression target, const std::vector< AffineExpression > &exprs, const std::vector< Literal > &selectors)
std::function< int64_t(const Model &)> UpperBound(IntegerVariable v)
std::function< void(Model *)> GreaterOrEqual(IntegerVariable v, int64_t lb)
std::function< void(Model *)> SpanOfIntervals(IntervalVariable span, const std::vector< IntervalVariable > &intervals)
std::function< void(Model *)> EqualMinOfSelectedVariables(Literal enforcement_literal, AffineExpression target, const std::vector< AffineExpression > &exprs, const std::vector< Literal > &selectors)
Collection of objects used to extend the Constraint Solver library.
AffineExpression Negated() const
IntegerLiteral GreaterOrEqual(IntegerValue bound) const
IntegerLiteral LowerOrEqual(IntegerValue bound) const
static IntegerLiteral LowerOrEqual(IntegerVariable i, IntegerValue bound)