22#include "ortools/sat/cp_model.pb.h"
36 const int size =
ct.bool_or().literals_size();
38 bool satisfied =
false;
39 for (
int i = 0; i < size; ++i) {
40 const int ref =
ct.bool_or().literals(i);
51 if (satisfied)
return;
54 const int first_ref =
ct.bool_or().literals(0);
59 std::vector<Domain>* domains) {
60 bool satisfied =
false;
61 std::vector<int> free_variables;
62 for (
const int ref :
ct.exactly_one().literals()) {
66 CHECK(!satisfied) <<
"Two variables at one in exactly one.";
70 free_variables.push_back(ref);
75 CHECK(!free_variables.empty()) <<
"All zero in exactly one";
76 const int ref = free_variables.back();
78 free_variables.pop_back();
82 for (
const int ref : free_variables) {
90 std::vector<Domain>* domains) {
91 CHECK(!
ct.enforcement_literal().empty());
92 bool has_free_enforcement_literal =
false;
93 for (
const int enf :
ct.enforcement_literal()) {
95 has_free_enforcement_literal =
true;
97 (*domains)[enf] =
Domain(0);
103 if (!has_free_enforcement_literal) {
105 <<
"Unsatisfied linear constraint with no free enforcement literal: "
106 <<
ct.ShortDebugString();
113 int64_t fixed_activity = 0;
114 const int size =
ct.linear().vars().size();
115 std::vector<int> free_vars;
116 std::vector<int64_t> free_coeffs;
117 for (
int i = 0; i < size; ++i) {
118 const int var =
ct.linear().vars(i);
119 const int64_t
coeff =
ct.linear().coeffs(i);
121 if (
coeff == 0)
continue;
123 fixed_activity += (*domains)[
var].FixedValue() *
coeff;
125 free_vars.push_back(
var);
126 free_coeffs.push_back(
coeff);
129 if (free_vars.empty()) {
131 if (!rhs.
Contains(fixed_activity)) {
139 if (free_vars.size() == 1) {
140 const int var = free_vars[0];
159 std::vector<Domain> rhs_domains;
160 rhs_domains.push_back(initial_rhs);
161 for (
int i = 0; i + 1 < free_vars.size(); ++i) {
168 rhs_domains.push_back(term.
AdditionWith(rhs_domains.back()));
170 for (
int i = free_vars.size() - 1; i >= 0; --i) {
174 const int var = free_vars[i];
175 const int64_t
coeff = free_coeffs[i];
176 const Domain domain = rhs_domains[i]
195int64_t EvaluateLinearExpression(
const LinearExpressionProto& expr,
196 const std::vector<Domain>& domains) {
197 int64_t
value = expr.offset();
198 for (
int i = 0; i < expr.vars_size(); ++i) {
199 const int ref = expr.vars(i);
200 const int64_t increment =
201 domains[
PositiveRef(expr.vars(i))].FixedValue() * expr.coeffs(i);
215 for (
const LinearExpressionProto& expr :
ct.lin_max().exprs()) {
216 max_value =
std::max(max_value, EvaluateLinearExpression(expr, *domains));
220 (*domains)[target_var] = (*domains)[target_var].IntersectionWith(
222 CHECK(!(*domains)[target_var].IsEmpty());
227 const int index_ref =
ct.element().index();
229 const int target_ref =
ct.element().target();
235 if (!(*domains)[target_var].
IsFixed() && !(*domains)[index_var].
IsFixed()) {
236 const int64_t index_var_value = (*domains)[index_var].Min();
237 (*domains)[index_var] =
Domain(index_var_value);
240 const int selected_ref =
ct.element().vars(
241 RefIsPositive(index_ref) ? index_var_value : -index_var_value);
242 const int selected_var =
PositiveRef(selected_ref);
243 if (!(*domains)[selected_var].
IsFixed()) {
244 (*domains)[selected_var] =
Domain((*domains)[selected_var].Min());
249 if ((*domains)[index_var].
IsFixed()) {
250 const int64_t index_var_value = (*domains)[index_var].FixedValue();
251 const int selected_ref =
ct.element().vars(
252 RefIsPositive(index_ref) ? index_var_value : -index_var_value);
253 const int selected_var =
PositiveRef(selected_ref);
254 if ((*domains)[selected_var].
IsFixed()) {
255 const int64_t selected_value = (*domains)[selected_var].FixedValue();
256 (*domains)[target_var] = (*domains)[target_var].IntersectionWith(
260 DCHECK(!(*domains)[target_var].IsEmpty());
262 const bool same_sign =
263 (selected_var == selected_ref) == (target_var == target_ref);
264 const Domain target_domain = (*domains)[target_var];
265 const Domain selected_domain = same_sign
266 ? (*domains)[selected_var]
267 : (*domains)[selected_var].
Negation();
269 const int64_t
value =
final.SmallestValue();
270 (*domains)[target_var] =
271 (*domains)[target_var].IntersectionWith(
Domain(
value));
272 (*domains)[selected_var] = (*domains)[selected_var].IntersectionWith(
274 DCHECK(!(*domains)[target_var].IsEmpty());
275 DCHECK(!(*domains)[selected_var].IsEmpty());
281 const int64_t target_value = (*domains)[target_var].FixedValue();
282 int selected_index_value = -1;
283 for (
const int64_t v : (*domains)[index_var].Values()) {
284 const int64_t i = index_var == index_ref ? v : -v;
285 if (i < 0 || i >=
ct.element().vars_size())
continue;
287 const int ref =
ct.element().vars(i);
289 const int64_t
value = (*domains)[
var].FixedValue();
291 if (
value == target_value) {
292 selected_index_value = i;
296 if (
value == -target_value) {
297 selected_index_value = i;
304 (*domains)[index_var] = (*domains)[index_var].IntersectionWith(
Domain(
305 RefIsPositive(index_ref) ? selected_index_value : -selected_index_value));
306 DCHECK(!(*domains)[index_var].IsEmpty());
310 const CpModelProto& mapping_proto,
311 const std::vector<int>& postsolve_mapping,
312 std::vector<int64_t>* solution) {
313 CHECK_EQ(solution->size(), postsolve_mapping.size());
317 std::vector<Domain> domains(mapping_proto.variables_size());
318 for (
int i = 0; i < postsolve_mapping.size(); ++i) {
319 CHECK_LE(postsolve_mapping[i], domains.size());
320 domains[postsolve_mapping[i]] =
Domain((*solution)[i]);
322 for (
int i = 0; i < domains.size(); ++i) {
323 if (domains[i].IsEmpty()) {
326 CHECK(!domains[i].IsEmpty());
330 const int num_constraints = mapping_proto.constraints_size();
331 for (
int i = num_constraints - 1; i >= 0; i--) {
332 const ConstraintProto&
ct = mapping_proto.constraints(i);
336 bool constraint_can_be_ignored =
false;
337 for (
const int enf :
ct.enforcement_literal()) {
339 const bool is_false =
340 domains[
var].IsFixed() &&
343 constraint_can_be_ignored =
true;
347 if (constraint_can_be_ignored)
continue;
349 switch (
ct.constraint_case()) {
350 case ConstraintProto::kBoolOr:
353 case ConstraintProto::kExactlyOne:
356 case ConstraintProto::kLinear:
359 case ConstraintProto::kLinMax:
362 case ConstraintProto::kElement:
368 LOG(
FATAL) <<
"Unsupported constraint: " <<
ct.ShortDebugString();
375 CHECK_LE(num_variables_in_original_model, domains.size());
376 for (
int i = 0; i < num_variables_in_original_model; ++i) {
377 solution->push_back(domains[i].SmallestValue());
#define CHECK_LT(val1, val2)
#define CHECK_EQ(val1, val2)
#define CHECK_NE(val1, val2)
#define DCHECK(condition)
#define CHECK_LE(val1, val2)
We call domain any subset of Int64 = [kint64min, kint64max].
Domain InverseMultiplicationBy(const int64_t coeff) const
Returns {x ∈ Int64, ∃ e ∈ D, x * coeff = e}.
Domain Negation() const
Returns {x ∈ Int64, ∃ e ∈ D, x = -e}.
bool Contains(int64_t value) const
Returns true iff value is in Domain.
Domain AdditionWith(const Domain &domain) const
Returns {x ∈ Int64, ∃ a ∈ D, ∃ b ∈ domain, x = a + b}.
Domain MultiplicationBy(int64_t coeff, bool *exact=nullptr) const
Returns {x ∈ Int64, ∃ e ∈ D, x = e * coeff}.
Domain IntersectionWith(const Domain &domain) const
Returns the intersection of D and domain.
bool IsEmpty() const
Returns true if this is the empty set.
int64_t SmallestValue() const
Returns the value closest to zero.
void PostsolveElement(const ConstraintProto &ct, std::vector< Domain > *domains)
void PostsolveLinear(const ConstraintProto &ct, std::vector< Domain > *domains)
bool RefIsPositive(int ref)
void PostsolveResponse(const int64_t num_variables_in_original_model, const CpModelProto &mapping_proto, const std::vector< int > &postsolve_mapping, std::vector< int64_t > *solution)
std::function< bool(const Model &)> IsFixed(IntegerVariable v)
void PostsolveExactlyOne(const ConstraintProto &ct, std::vector< Domain > *domains)
void SetEnforcementLiteralToFalse(const ConstraintProto &ct, std::vector< Domain > *domains)
void PostsolveLinMax(const ConstraintProto &ct, std::vector< Domain > *domains)
Domain ReadDomainFromProto(const ProtoWithDomain &proto)
void PostsolveClause(const ConstraintProto &ct, std::vector< Domain > *domains)
int GetSingleRefFromExpression(const LinearExpressionProto &expr)
Collection of objects used to extend the Constraint Solver library.