forked from google/or-tools
-
Notifications
You must be signed in to change notification settings - Fork 9
/
cp_constraints.h
185 lines (163 loc) · 6.66 KB
/
cp_constraints.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
// Copyright 2010-2024 Google LLC
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef OR_TOOLS_SAT_CP_CONSTRAINTS_H_
#define OR_TOOLS_SAT_CP_CONSTRAINTS_H_
#include <cstdint>
#include <functional>
#include <memory>
#include <vector>
#include "absl/log/check.h"
#include "absl/types/span.h"
#include "ortools/base/logging.h"
#include "ortools/base/types.h"
#include "ortools/sat/integer.h"
#include "ortools/sat/model.h"
#include "ortools/sat/sat_base.h"
#include "ortools/util/rev.h"
#include "ortools/util/strong_integers.h"
namespace operations_research {
namespace sat {
// Propagate the fact that a XOR of literals is equal to the given value.
// The complexity is in O(n).
//
// TODO(user): By using a two watcher mechanism, we can propagate this a lot
// faster.
class BooleanXorPropagator : public PropagatorInterface {
public:
BooleanXorPropagator(const std::vector<Literal>& literals, bool value,
Trail* trail, IntegerTrail* integer_trail)
: literals_(literals),
value_(value),
trail_(trail),
integer_trail_(integer_trail) {}
// This type is neither copyable nor movable.
BooleanXorPropagator(const BooleanXorPropagator&) = delete;
BooleanXorPropagator& operator=(const BooleanXorPropagator&) = delete;
bool Propagate() final;
void RegisterWith(GenericLiteralWatcher* watcher);
private:
const std::vector<Literal> literals_;
const bool value_;
std::vector<Literal> literal_reason_;
Trail* trail_;
IntegerTrail* integer_trail_;
};
// If we have:
// - selectors[i] => (target_var >= vars[i] + offset[i])
// - and we known that at least one selectors[i] must be true
// then we can propagate the fact that if no selectors is chosen yet, the lower
// bound of target_var is greater than the min of the still possible
// alternatives.
//
// This constraint take care of this case when no selectors[i] is chosen yet.
//
// This constraint support duplicate selectors.
class GreaterThanAtLeastOneOfPropagator : public PropagatorInterface,
public LazyReasonInterface {
public:
GreaterThanAtLeastOneOfPropagator(IntegerVariable target_var,
absl::Span<const AffineExpression> exprs,
absl::Span<const Literal> selectors,
absl::Span<const Literal> enforcements,
Model* model);
// This type is neither copyable nor movable.
GreaterThanAtLeastOneOfPropagator(const GreaterThanAtLeastOneOfPropagator&) =
delete;
GreaterThanAtLeastOneOfPropagator& operator=(
const GreaterThanAtLeastOneOfPropagator&) = delete;
bool Propagate() final;
void RegisterWith(GenericLiteralWatcher* watcher);
// For LazyReasonInterface.
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;
private:
const IntegerVariable target_var_;
const std::vector<Literal> enforcements_;
// Non-const as we swap elements around.
std::vector<Literal> selectors_;
std::vector<AffineExpression> exprs_;
Trail* trail_;
IntegerTrail* integer_trail_;
};
// ============================================================================
// Model based functions.
// ============================================================================
inline std::vector<IntegerValue> ToIntegerValueVector(
absl::Span<const int64_t> input) {
std::vector<IntegerValue> result(input.size());
for (int i = 0; i < input.size(); ++i) {
result[i] = IntegerValue(input[i]);
}
return result;
}
// Enforces the XOR of a set of literals to be equal to the given value.
inline std::function<void(Model*)> LiteralXorIs(
const std::vector<Literal>& literals, bool value) {
return [=](Model* model) {
Trail* trail = model->GetOrCreate<Trail>();
IntegerTrail* integer_trail = model->GetOrCreate<IntegerTrail>();
BooleanXorPropagator* constraint =
new BooleanXorPropagator(literals, value, trail, integer_trail);
constraint->RegisterWith(model->GetOrCreate<GenericLiteralWatcher>());
model->TakeOwnership(constraint);
};
}
inline 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) {
return [=](Model* model) {
std::vector<AffineExpression> exprs;
for (int i = 0; i < vars.size(); ++i) {
exprs.push_back(AffineExpression(vars[i], 1, offsets[i]));
}
GreaterThanAtLeastOneOfPropagator* constraint =
new GreaterThanAtLeastOneOfPropagator(target_var, exprs, selectors,
enforcements, model);
constraint->RegisterWith(model->GetOrCreate<GenericLiteralWatcher>());
model->TakeOwnership(constraint);
};
}
// The target variable is equal to exactly one of the candidate variable. The
// equality is controlled by the given "selector" literals.
//
// Note(user): This only propagate from the min/max of still possible candidates
// to the min/max of the target variable. The full constraint also requires
// to deal with the case when one of the literal is true.
//
// Note(user): If there is just one or two candidates, this doesn't add
// anything.
inline std::function<void(Model*)> PartialIsOneOfVar(
IntegerVariable target_var, const std::vector<IntegerVariable>& vars,
const std::vector<Literal>& selectors) {
CHECK_EQ(vars.size(), selectors.size());
return [=](Model* model) {
const std::vector<IntegerValue> offsets(vars.size(), IntegerValue(0));
if (vars.size() > 2) {
// Propagate the min.
model->Add(
GreaterThanAtLeastOneOf(target_var, vars, offsets, selectors, {}));
}
if (vars.size() > 2) {
// Propagate the max.
model->Add(GreaterThanAtLeastOneOf(
NegationOf(target_var), NegationOf(vars), offsets, selectors, {}));
}
};
}
} // namespace sat
} // namespace operations_research
#endif // OR_TOOLS_SAT_CP_CONSTRAINTS_H_