Google OR-Tools v9.15
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
cp_constraints.h
Go to the documentation of this file.
1// Copyright 2010-2025 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
14#ifndef ORTOOLS_SAT_CP_CONSTRAINTS_H_
15#define ORTOOLS_SAT_CP_CONSTRAINTS_H_
16
17#include <cstdint>
18#include <functional>
19#include <string>
20#include <vector>
21
22#include "absl/log/check.h"
23#include "absl/types/span.h"
27#include "ortools/sat/integer.h"
29#include "ortools/sat/model.h"
31
32namespace operations_research {
33namespace sat {
34
35// Propagate the fact that a XOR of literals is equal to the given value.
36// The complexity is in O(n).
37//
38// TODO(user): By using a two watcher mechanism, we can propagate this a lot
39// faster.
41 public:
42 BooleanXorPropagator(absl::Span<const Literal> enforcement_literals,
43 const std::vector<Literal>& literals, bool value,
44 Model* model);
45
46 // This type is neither copyable nor movable.
49
50 bool Propagate() final;
51
52 private:
53 int RegisterWith(GenericLiteralWatcher* watcher);
54
55 const std::vector<Literal> literals_;
56 const bool value_;
57 std::vector<Literal> literal_reason_;
58 const Trail& trail_;
59 const IntegerTrail& integer_trail_;
60 EnforcementHelper& enforcement_helper_;
61 EnforcementId enforcement_id_;
62};
63
64// If we have:
65// - selectors[i] => (target_var >= vars[i] + offset[i])
66// - and we known that at least one selectors[i] must be true
67// then we can propagate the fact that if no selectors is chosen yet, the lower
68// bound of target_var is greater than the min of the still possible
69// alternatives.
70//
71// This constraint take care of this case when no selectors[i] is chosen yet.
72//
73// This constraint support duplicate selectors.
75 public LazyReasonInterface {
76 public:
77 GreaterThanAtLeastOneOfPropagator(IntegerVariable target_var,
78 absl::Span<const AffineExpression> exprs,
79 absl::Span<const Literal> selectors,
80 absl::Span<const Literal> enforcements,
81 Model* model);
82
83 // This type is neither copyable nor movable.
85 delete;
87 const GreaterThanAtLeastOneOfPropagator&) = delete;
88
89 std::string LazyReasonName() const override {
90 return "GreaterThanAtLeastOneOfPropagator";
91 }
92
93 bool Propagate() final;
94 void RegisterWith(GenericLiteralWatcher* watcher);
95
96 // For LazyReasonInterface.
97 void Explain(int id, IntegerLiteral to_explain, IntegerReason* reason) final;
98
99 private:
100 const IntegerVariable target_var_;
101 const std::vector<Literal> enforcements_;
102
103 // Non-const as we swap elements around.
104 std::vector<Literal> selectors_;
105 std::vector<AffineExpression> exprs_;
106
107 Trail* trail_;
108 IntegerTrail* integer_trail_;
109};
110
111// ============================================================================
112// Model based functions.
113// ============================================================================
114
115inline std::vector<IntegerValue> ToIntegerValueVector(
116 absl::Span<const int64_t> input) {
117 std::vector<IntegerValue> result(input.size());
118 for (int i = 0; i < input.size(); ++i) {
119 result[i] = IntegerValue(input[i]);
120 }
121 return result;
122}
123
124// Enforces the XOR of a set of literals to be equal to the given value.
125inline std::function<void(Model*)> LiteralXorIs(
126 absl::Span<const Literal> enforcement_literals,
127 const std::vector<Literal>& literals, bool value) {
128 return [=, enforcement_literals = std::vector<Literal>(
129 enforcement_literals.begin(), enforcement_literals.end())](
130 Model* model) {
131 model->TakeOwnership(
132 new BooleanXorPropagator(enforcement_literals, literals, value, model));
133 };
134}
135
136inline std::function<void(Model*)> GreaterThanAtLeastOneOf(
137 IntegerVariable target_var, const absl::Span<const IntegerVariable> vars,
138 const absl::Span<const IntegerValue> offsets,
139 const absl::Span<const Literal> selectors,
140 const absl::Span<const Literal> enforcements) {
141 return [=](Model* model) {
142 std::vector<AffineExpression> exprs;
143 for (int i = 0; i < vars.size(); ++i) {
144 exprs.push_back(AffineExpression(vars[i], 1, offsets[i]));
145 }
147 new GreaterThanAtLeastOneOfPropagator(target_var, exprs, selectors,
148 enforcements, model);
149 constraint->RegisterWith(model->GetOrCreate<GenericLiteralWatcher>());
150 model->TakeOwnership(constraint);
151 };
152}
153
154// The target variable is equal to exactly one of the candidate variable. The
155// equality is controlled by the given "selector" literals.
156//
157// Note(user): This only propagate from the min/max of still possible candidates
158// to the min/max of the target variable. The full constraint also requires
159// to deal with the case when one of the literal is true.
160//
161// Note(user): If there is just one or two candidates, this doesn't add
162// anything.
163inline std::function<void(Model*)> PartialIsOneOfVar(
164 IntegerVariable target_var, absl::Span<const IntegerVariable> vars,
165 absl::Span<const Literal> selectors) {
166 CHECK_EQ(vars.size(), selectors.size());
167 return [=,
168 selectors = std::vector<Literal>(selectors.begin(), selectors.end()),
169 vars = std::vector<IntegerVariable>(vars.begin(), vars.end())](
170 Model* model) {
171 const std::vector<IntegerValue> offsets(vars.size(), IntegerValue(0));
172 if (vars.size() > 2) {
173 // Propagate the min.
174 model->Add(
175 GreaterThanAtLeastOneOf(target_var, vars, offsets, selectors, {}));
176 }
177 if (vars.size() > 2) {
178 // Propagate the max.
180 NegationOf(target_var), NegationOf(vars), offsets, selectors, {}));
181 }
182 };
183}
184
185} // namespace sat
186} // namespace operations_research
187
188#endif // ORTOOLS_SAT_CP_CONSTRAINTS_H_
Definition model.h:345
BooleanXorPropagator & operator=(const BooleanXorPropagator &)=delete
BooleanXorPropagator(const BooleanXorPropagator &)=delete
BooleanXorPropagator(absl::Span< const Literal > enforcement_literals, const std::vector< Literal > &literals, bool value, Model *model)
GreaterThanAtLeastOneOfPropagator & operator=(const GreaterThanAtLeastOneOfPropagator &)=delete
GreaterThanAtLeastOneOfPropagator(const GreaterThanAtLeastOneOfPropagator &)=delete
GreaterThanAtLeastOneOfPropagator(IntegerVariable target_var, absl::Span< const AffineExpression > exprs, absl::Span< const Literal > selectors, absl::Span< const Literal > enforcements, Model *model)
T Add(std::function< T(Model *)> f)
Definition model.h:104
std::function< void(Model *)> GreaterThanAtLeastOneOf(IntegerVariable target_var, const absl::Span< const IntegerVariable > vars, const absl::Span< const IntegerValue > offsets, const absl::Span< const Literal > selectors, const absl::Span< const Literal > enforcements)
std::function< void(Model *)> PartialIsOneOfVar(IntegerVariable target_var, absl::Span< const IntegerVariable > vars, absl::Span< const Literal > selectors)
std::vector< IntegerVariable > NegationOf(absl::Span< const IntegerVariable > vars)
Definition integer.cc:52
std::function< void(Model *)> LiteralXorIs(absl::Span< const Literal > enforcement_literals, const std::vector< Literal > &literals, bool value)
std::vector< IntegerValue > ToIntegerValueVector(absl::Span< const int64_t > input)
OR-Tools root namespace.
STL namespace.
static int input(yyscan_t yyscanner)