Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
cp_constraints.cc
Go to the documentation of this file.
1// Copyright 2010-2024 Google LLC
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
15
16#include <algorithm>
17#include <vector>
18
19#include "absl/types/span.h"
20#include "ortools/sat/integer.h"
21#include "ortools/sat/model.h"
24
25namespace operations_research {
26namespace sat {
27
29 bool sum = false;
30 int unassigned_index = -1;
31 for (int i = 0; i < literals_.size(); ++i) {
32 const Literal l = literals_[i];
33 if (trail_->Assignment().LiteralIsFalse(l)) {
34 sum ^= false;
35 } else if (trail_->Assignment().LiteralIsTrue(l)) {
36 sum ^= true;
37 } else {
38 // If we have more than one unassigned literal, we can't deduce anything.
39 if (unassigned_index != -1) return true;
40 unassigned_index = i;
41 }
42 }
43
44 // Propagates?
45 if (unassigned_index != -1) {
46 literal_reason_.clear();
47 for (int i = 0; i < literals_.size(); ++i) {
48 if (i == unassigned_index) continue;
49 const Literal l = literals_[i];
50 literal_reason_.push_back(
51 trail_->Assignment().LiteralIsFalse(l) ? l : l.Negated());
52 }
53 const Literal u = literals_[unassigned_index];
54 integer_trail_->EnqueueLiteral(sum == value_ ? u.Negated() : u,
55 literal_reason_, {});
56 return true;
57 }
58
59 // Ok.
60 if (sum == value_) return true;
61
62 // Conflict.
63 std::vector<Literal>* conflict = trail_->MutableConflict();
64 conflict->clear();
65 for (int i = 0; i < literals_.size(); ++i) {
66 const Literal l = literals_[i];
67 conflict->push_back(trail_->Assignment().LiteralIsFalse(l) ? l
68 : l.Negated());
69 }
70 return false;
71}
72
74 const int id = watcher->Register(this);
75 for (const Literal& l : literals_) {
76 watcher->WatchLiteral(l, id);
77 watcher->WatchLiteral(l.Negated(), id);
78 }
79}
80
82 IntegerVariable target_var, const absl::Span<const AffineExpression> exprs,
83 const absl::Span<const Literal> selectors,
84 const absl::Span<const Literal> enforcements, Model* model)
85 : target_var_(target_var),
86 enforcements_(enforcements.begin(), enforcements.end()),
87 selectors_(selectors.begin(), selectors.end()),
88 exprs_(exprs.begin(), exprs.end()),
89 trail_(model->GetOrCreate<Trail>()),
90 integer_trail_(model->GetOrCreate<IntegerTrail>()) {}
91
93 int id, IntegerValue propagation_slack, IntegerVariable /*var_to_explain*/,
94 int /*trail_index*/, std::vector<Literal>* literals_reason,
95 std::vector<int>* trail_indices_reason) {
96 literals_reason->clear();
97 trail_indices_reason->clear();
98
99 const int first_non_false = id;
100 const IntegerValue target_min = propagation_slack;
101
102 for (const Literal l : enforcements_) {
103 literals_reason->push_back(l.Negated());
104 }
105 for (int i = 0; i < first_non_false; ++i) {
106 // If the level zero bounds is good enough, no reason needed.
107 //
108 // TODO(user): We could also skip this if we already have the reason for
109 // the expression being high enough in the current conflict.
110 if (integer_trail_->LevelZeroLowerBound(exprs_[i]) >= target_min) {
111 continue;
112 }
113
114 literals_reason->push_back(selectors_[i]);
115 }
116 integer_trail_->AddAllGreaterThanConstantReason(
117 absl::MakeSpan(exprs_).subspan(first_non_false), target_min,
118 trail_indices_reason);
119}
120
122 // TODO(user): In case of a conflict, we could push one of them to false if
123 // it is the only one.
124 for (const Literal l : enforcements_) {
125 if (!trail_->Assignment().LiteralIsTrue(l)) return true;
126 }
127
128 // Compute the min of the lower-bound for the still possible variables.
129 // TODO(user): This could be optimized by keeping more info from the last
130 // Propagate() calls.
131 IntegerValue target_min = kMaxIntegerValue;
132 const IntegerValue current_min = integer_trail_->LowerBound(target_var_);
133 const AssignmentView assignment(trail_->Assignment());
134
135 int first_non_false = 0;
136 const int size = exprs_.size();
137 for (int i = 0; i < size; ++i) {
138 if (assignment.LiteralIsTrue(selectors_[i])) return true;
139
140 // The permutation is needed to have proper lazy reason.
141 if (assignment.LiteralIsFalse(selectors_[i])) {
142 if (i != first_non_false) {
143 std::swap(selectors_[i], selectors_[first_non_false]);
144 std::swap(exprs_[i], exprs_[first_non_false]);
145 }
146 ++first_non_false;
147 continue;
148 }
149
150 const IntegerValue min = integer_trail_->LowerBound(exprs_[i]);
151 if (min < target_min) {
152 target_min = min;
153
154 // Abort if we can't get a better bound.
155 if (target_min <= current_min) return true;
156 }
157 }
158
159 if (target_min == kMaxIntegerValue) {
160 // All false, conflit.
161 *(trail_->MutableConflict()) = selectors_;
162 return false;
163 }
164
165 // Note that we use id/propagation_slack for other purpose.
166 return integer_trail_->EnqueueWithLazyReason(
167 IntegerLiteral::GreaterOrEqual(target_var_, target_min),
168 /*id=*/first_non_false, /*propagation_slack=*/target_min, this);
169}
170
172 GenericLiteralWatcher* watcher) {
173 const int id = watcher->Register(this);
174 for (const Literal l : selectors_) watcher->WatchLiteral(l.Negated(), id);
175 for (const Literal l : enforcements_) watcher->WatchLiteral(l, id);
176 for (const AffineExpression e : exprs_) {
177 if (!e.IsConstant()) {
178 watcher->WatchLowerBound(e, id);
179 }
180 }
181}
182
183} // namespace sat
184} // namespace operations_research
IntegerValue size
int64_t min
bool LiteralIsFalse(Literal literal) const
Definition sat_base.h:227
bool LiteralIsTrue(Literal literal) const
Definition sat_base.h:231
void RegisterWith(GenericLiteralWatcher *watcher)
void WatchLiteral(Literal l, int id, int watch_index=-1)
Definition integer.h:1844
void WatchLowerBound(IntegerVariable var, int id, int watch_index=-1)
Definition integer.h:1852
int Register(PropagatorInterface *propagator)
Registers a propagator and returns its unique ids.
Definition integer.cc:2332
void Explain(int id, IntegerValue propagation_slack, IntegerVariable var_to_explain, int trail_index, std::vector< Literal > *literals_reason, std::vector< int > *trail_indices_reason) final
For LazyReasonInterface.
GreaterThanAtLeastOneOfPropagator(IntegerVariable target_var, absl::Span< const AffineExpression > exprs, absl::Span< const Literal > selectors, absl::Span< const Literal > enforcements, Model *model)
IntegerValue LowerBound(IntegerVariable i) const
Returns the current lower/upper bound of the given integer variable.
Definition integer.h:1717
void AddAllGreaterThanConstantReason(absl::Span< AffineExpression > exprs, IntegerValue target_min, std::vector< int > *indices) const
Definition integer.h:1158
ABSL_MUST_USE_RESULT bool EnqueueWithLazyReason(IntegerLiteral i_lit, int id, IntegerValue propagation_slack, LazyReasonInterface *explainer)
Lazy reason API.
Definition integer.h:1020
void EnqueueLiteral(Literal literal, absl::Span< const Literal > literal_reason, absl::Span< const IntegerLiteral > integer_reason)
Definition integer.cc:1392
IntegerValue LevelZeroLowerBound(IntegerVariable var) const
Returns globally valid lower/upper bound on the given integer variable.
Definition integer.h:1812
std::vector< Literal > * MutableConflict()
Definition sat_base.h:433
const VariablesAssignment & Assignment() const
Definition sat_base.h:462
bool LiteralIsFalse(Literal literal) const
Definition sat_base.h:185
bool LiteralIsTrue(Literal literal) const
Definition sat_base.h:188
GRBmodel * model
constexpr IntegerValue kMaxIntegerValue(std::numeric_limits< IntegerValue::ValueType >::max() - 1)
In SWIG mode, we don't want anything besides these top-level includes.
std::optional< int64_t > end
static IntegerLiteral GreaterOrEqual(IntegerVariable i, IntegerValue bound)
Definition integer.h:1667