Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
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
14#include <string.h>
15
16#include <algorithm>
17#include <cstdint>
18#include <limits>
19#include <memory>
20#include <string>
21#include <utility>
22#include <vector>
23
24#include "absl/log/check.h"
25#include "absl/strings/str_cat.h"
26#include "absl/strings/str_format.h"
27#include "absl/strings/str_join.h"
29#include "ortools/base/types.h"
34
35namespace operations_research {
36
41
47
48namespace {
49class ActionDemon : public Demon {
50 public:
51 explicit ActionDemon(const Solver::Action& action) : action_(action) {
52 CHECK(action != nullptr);
53 }
54
55 ~ActionDemon() override {}
56
57 void Run(Solver* const solver) override { action_(solver); }
58
59 private:
60 Solver::Action action_;
61};
62
63class ClosureDemon : public Demon {
64 public:
65 explicit ClosureDemon(const Solver::Closure& closure) : closure_(closure) {
66 CHECK(closure != nullptr);
67 }
68
69 ~ClosureDemon() override {}
70
71 void Run(Solver* const solver) override { closure_(); }
72
73 private:
74 Solver::Closure closure_;
75};
76
77// ----- True and False Constraint -----
78
79class TrueConstraint : public Constraint {
80 public:
81 explicit TrueConstraint(Solver* const s) : Constraint(s) {}
82 ~TrueConstraint() override {}
83
84 void Post() override {}
85 void InitialPropagate() override {}
86 std::string DebugString() const override { return "TrueConstraint()"; }
87
88 void Accept(ModelVisitor* const visitor) const override {
89 visitor->BeginVisitConstraint(ModelVisitor::kTrueConstraint, this);
90 visitor->EndVisitConstraint(ModelVisitor::kTrueConstraint, this);
91 }
92 IntVar* Var() override { return solver()->MakeIntConst(1); }
93};
94
95class FalseConstraint : public Constraint {
96 public:
97 explicit FalseConstraint(Solver* const s) : Constraint(s) {}
98 FalseConstraint(Solver* const s, const std::string& explanation)
99 : Constraint(s), explanation_(explanation) {}
100 ~FalseConstraint() override {}
101
102 void Post() override {}
103 void InitialPropagate() override { solver()->Fail(); }
104 std::string DebugString() const override {
105 return absl::StrCat("FalseConstraint(", explanation_, ")");
106 }
107
108 void Accept(ModelVisitor* const visitor) const override {
109 visitor->BeginVisitConstraint(ModelVisitor::kFalseConstraint, this);
110 visitor->EndVisitConstraint(ModelVisitor::kFalseConstraint, this);
111 }
112 IntVar* Var() override { return solver()->MakeIntConst(0); }
113
114 private:
115 const std::string explanation_;
116};
117
118// ----- Map Variable Domain to Boolean Var Array -----
119// TODO(user) : optimize constraint to avoid ping pong.
120// After a boolvar is set to 0, we remove the value from the var.
121// There is no need to rescan the var to find the hole if the size at the end of
122// UpdateActive() is the same as the size at the beginning of VarDomain().
123
124class MapDomain : public Constraint {
125 public:
126 MapDomain(Solver* const s, IntVar* const var,
127 const std::vector<IntVar*>& actives)
128 : Constraint(s), var_(var), actives_(actives) {
129 holes_ = var->MakeHoleIterator(true);
130 }
131
132 ~MapDomain() override {}
133
134 void Post() override {
135 Demon* vd = MakeConstraintDemon0(solver(), this, &MapDomain::VarDomain,
136 "VarDomain");
137 var_->WhenDomain(vd);
138 Demon* vb =
139 MakeConstraintDemon0(solver(), this, &MapDomain::VarBound, "VarBound");
140 var_->WhenBound(vb);
141 std::unique_ptr<IntVarIterator> domain_it(
142 var_->MakeDomainIterator(/*reversible=*/false));
143 for (const int64_t index : InitAndGetValues(domain_it.get())) {
144 if (index >= 0 && index < actives_.size() && !actives_[index]->Bound()) {
145 Demon* d = MakeConstraintDemon1(
146 solver(), this, &MapDomain::UpdateActive, "UpdateActive", index);
147 actives_[index]->WhenDomain(d);
148 }
149 }
150 }
151
152 void InitialPropagate() override {
153 for (int i = 0; i < actives_.size(); ++i) {
154 actives_[i]->SetRange(int64_t{0}, int64_t{1});
155 if (!var_->Contains(i)) {
156 actives_[i]->SetValue(0);
157 } else if (actives_[i]->Max() == 0LL) {
158 var_->RemoveValue(i);
159 }
160 if (actives_[i]->Min() == 1LL) {
161 var_->SetValue(i);
162 }
163 }
164 if (var_->Bound()) {
165 VarBound();
166 }
167 }
168
169 void UpdateActive(int64_t index) {
170 IntVar* const act = actives_[index];
171 if (act->Max() == 0) {
172 var_->RemoveValue(index);
173 } else if (act->Min() == 1) {
174 var_->SetValue(index);
175 }
176 }
177
178 void VarDomain() {
179 const int64_t oldmin = var_->OldMin();
180 const int64_t oldmax = var_->OldMax();
181 const int64_t vmin = var_->Min();
182 const int64_t vmax = var_->Max();
183 const int64_t size = actives_.size();
184 for (int64_t j = std::max(oldmin, int64_t{0}); j < std::min(vmin, size);
185 ++j) {
186 actives_[j]->SetValue(0);
187 }
188 for (const int64_t j : InitAndGetValues(holes_)) {
189 if (j >= 0 && j < size) {
190 actives_[j]->SetValue(0);
191 }
192 }
193 for (int64_t j = std::max(vmax + int64_t{1}, int64_t{0});
194 j <= std::min(oldmax, size - int64_t{1}); ++j) {
195 actives_[j]->SetValue(int64_t{0});
196 }
197 }
198
199 void VarBound() {
200 const int64_t val = var_->Min();
201 if (val >= 0 && val < actives_.size()) {
202 actives_[val]->SetValue(1);
203 }
204 }
205 std::string DebugString() const override {
206 return absl::StrFormat("MapDomain(%s, [%s])", var_->DebugString(),
207 JoinDebugStringPtr(actives_, ", "));
208 }
209
210 void Accept(ModelVisitor* const visitor) const override {
211 visitor->BeginVisitConstraint(ModelVisitor::kMapDomain, this);
212 visitor->VisitIntegerExpressionArgument(ModelVisitor::kTargetArgument,
213 var_);
214 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument,
215 actives_);
216 visitor->EndVisitConstraint(ModelVisitor::kMapDomain, this);
217 }
218
219 private:
220 IntVar* const var_;
221 std::vector<IntVar*> actives_;
222 IntVarIterator* holes_;
223};
224
225// ----- Lex constraint -----
226
227class LexicalLessOrEqual : public Constraint {
228 public:
229 LexicalLessOrEqual(Solver* const s, std::vector<IntVar*> left,
230 std::vector<IntVar*> right, std::vector<int64_t> offsets)
231 : Constraint(s),
232 left_(std::move(left)),
233 right_(std::move(right)),
234 active_var_(0),
235 offsets_(std::move(offsets)),
236 demon_added_(offsets_.size(), false),
237 demon_(nullptr) {
238 CHECK_EQ(left_.size(), right_.size());
239 CHECK_EQ(offsets_.size(), right_.size());
240 CHECK(std::all_of(offsets_.begin(), offsets_.end(),
241 [](int step) { return step > 0; }));
242 }
243
244 ~LexicalLessOrEqual() override {}
245
246 void Post() override {
247 const int position = JumpEqualVariables(0);
248 active_var_.SetValue(solver(), position);
249 if (position < left_.size()) {
250 demon_ = solver()->MakeConstraintInitialPropagateCallback(this);
251 AddDemon(position);
252 }
253 }
254
255 void InitialPropagate() override {
256 const int position = JumpEqualVariables(active_var_.Value());
257 if (position >= left_.size()) return;
258 if (position != active_var_.Value()) {
259 AddDemon(position);
260 active_var_.SetValue(solver(), position);
261 }
262 const int next_non_equal = JumpEqualVariables(position + 1);
263 if (next_non_equal < left_.size() &&
264 left_[next_non_equal]->Min() > right_[next_non_equal]->Max()) {
265 // We need to be strict if at next_non_equal, left is above right.
266 left_[position]->SetMax(
267 CapSub(right_[position]->Max(), offsets_[position]));
268 right_[position]->SetMin(
269 CapAdd(left_[position]->Min(), offsets_[position]));
270 } else {
271 left_[position]->SetMax(right_[position]->Max());
272 right_[position]->SetMin(left_[position]->Min());
273 }
274 // Adding demons for the next position as it may trigger changes at the
275 // active position (if the next position becomes invalid for instance).
276 if (next_non_equal < left_.size()) {
277 AddDemon(next_non_equal);
278 }
279 }
280
281 std::string DebugString() const override {
282 return absl::StrFormat(
283 "LexicalLessOrEqual([%s], [%s], [%s])", JoinDebugStringPtr(left_, ", "),
284 JoinDebugStringPtr(right_, ", "), absl::StrJoin(offsets_, ", "));
285 }
286
287 void Accept(ModelVisitor* const visitor) const override {
288 visitor->BeginVisitConstraint(ModelVisitor::kLexLess, this);
289 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kLeftArgument,
290 left_);
291 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kRightArgument,
292 right_);
293 visitor->VisitIntegerArrayArgument(ModelVisitor::kValuesArgument, offsets_);
294 visitor->EndVisitConstraint(ModelVisitor::kLexLess, this);
295 }
296
297 private:
298 int JumpEqualVariables(int start_position) const {
299 int position = start_position;
300 while (position < left_.size() &&
301 left_[position]->Max() <= right_[position]->Min() &&
302 CapSub(right_[position]->Max(), CapSub(offsets_[position], 1)) <=
303 left_[position]->Min()) {
304 position++;
305 }
306 return position;
307 }
308 void AddDemon(int position) {
309 if (demon_added_.Value(position)) return;
310 left_[position]->WhenRange(demon_);
311 right_[position]->WhenRange(demon_);
312 demon_added_.SetValue(solver(), position, true);
313 }
314
315 std::vector<IntVar*> left_;
316 std::vector<IntVar*> right_;
317 NumericalRev<int> active_var_;
318 std::vector<int64_t> offsets_;
319 RevArray<bool> demon_added_;
320 Demon* demon_;
321};
322
323// ----- Inverse permutation constraint -----
324
325class InversePermutationConstraint : public Constraint {
326 public:
327 InversePermutationConstraint(Solver* const s,
328 const std::vector<IntVar*>& left,
329 const std::vector<IntVar*>& right)
330 : Constraint(s),
331 left_(left),
332 right_(right),
333 left_hole_iterators_(left.size()),
334 left_domain_iterators_(left_.size()),
335 right_hole_iterators_(right_.size()),
336 right_domain_iterators_(right_.size()) {
337 CHECK_EQ(left_.size(), right_.size());
338 for (int i = 0; i < left_.size(); ++i) {
339 left_hole_iterators_[i] = left_[i]->MakeHoleIterator(true);
340 left_domain_iterators_[i] = left_[i]->MakeDomainIterator(true);
341 right_hole_iterators_[i] = right_[i]->MakeHoleIterator(true);
342 right_domain_iterators_[i] = right_[i]->MakeDomainIterator(true);
343 }
344 }
345
346 ~InversePermutationConstraint() override {}
347
348 void Post() override {
349 for (int i = 0; i < left_.size(); ++i) {
350 Demon* const left_demon = MakeConstraintDemon1(
351 solver(), this,
352 &InversePermutationConstraint::PropagateHolesOfLeftVarToRight,
353 "PropagateHolesOfLeftVarToRight", i);
354 left_[i]->WhenDomain(left_demon);
355 Demon* const right_demon = MakeConstraintDemon1(
356 solver(), this,
357 &InversePermutationConstraint::PropagateHolesOfRightVarToLeft,
358 "PropagateHolesOfRightVarToLeft", i);
359 right_[i]->WhenDomain(right_demon);
360 }
361 solver()->AddConstraint(
362 solver()->MakeAllDifferent(left_, /*stronger_propagation=*/false));
363 solver()->AddConstraint(
364 solver()->MakeAllDifferent(right_, /*stronger_propagation=*/false));
365 }
366
367 void InitialPropagate() override {
368 const int size = left_.size();
369 for (int i = 0; i < size; ++i) {
370 left_[i]->SetRange(0, size - 1);
371 right_[i]->SetRange(0, size - 1);
372 }
373 for (int i = 0; i < size; ++i) {
374 PropagateDomain(i, left_[i], left_domain_iterators_[i], right_);
375 PropagateDomain(i, right_[i], right_domain_iterators_[i], left_);
376 }
377 }
378
379 void PropagateHolesOfLeftVarToRight(int index) {
380 PropagateHoles(index, left_[index], left_hole_iterators_[index], right_);
381 }
382
383 void PropagateHolesOfRightVarToLeft(int index) {
384 PropagateHoles(index, right_[index], right_hole_iterators_[index], left_);
385 }
386
387 std::string DebugString() const override {
388 return absl::StrFormat("InversePermutationConstraint([%s], [%s])",
389 JoinDebugStringPtr(left_, ", "),
390 JoinDebugStringPtr(right_, ", "));
391 }
392
393 void Accept(ModelVisitor* const visitor) const override {
394 visitor->BeginVisitConstraint(ModelVisitor::kInversePermutation, this);
395 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kLeftArgument,
396 left_);
397 visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kRightArgument,
398 right_);
399 visitor->EndVisitConstraint(ModelVisitor::kInversePermutation, this);
400 }
401
402 private:
403 // See PropagateHolesOfLeftVarToRight() and PropagateHolesOfRightVarToLeft().
404 void PropagateHoles(int index, IntVar* const var, IntVarIterator* const holes,
405 const std::vector<IntVar*>& inverse) {
406 const int64_t oldmin = std::max(var->OldMin(), int64_t{0});
407 const int64_t oldmax =
408 std::min(var->OldMax(), static_cast<int64_t>(left_.size() - 1));
409 const int64_t vmin = var->Min();
410 const int64_t vmax = var->Max();
411 for (int64_t value = oldmin; value < vmin; ++value) {
412 inverse[value]->RemoveValue(index);
413 }
414 for (const int64_t hole : InitAndGetValues(holes)) {
415 if (hole >= 0 && hole < left_.size()) {
416 inverse[hole]->RemoveValue(index);
417 }
418 }
419 for (int64_t value = vmax + 1; value <= oldmax; ++value) {
420 inverse[value]->RemoveValue(index);
421 }
422 }
423
424 void PropagateDomain(int index, IntVar* const var,
425 IntVarIterator* const domain,
426 const std::vector<IntVar*>& inverse) {
427 // Iterators are not safe w.r.t. removal. Postponing deletions.
428 tmp_removed_values_.clear();
429 for (const int64_t value : InitAndGetValues(domain)) {
430 if (!inverse[value]->Contains(index)) {
431 tmp_removed_values_.push_back(value);
432 }
433 }
434 // Once we've finished iterating over the domain, we may call
435 // RemoveValues().
436 if (!tmp_removed_values_.empty()) {
437 var->RemoveValues(tmp_removed_values_);
438 }
439 }
440
441 std::vector<IntVar*> left_;
442 std::vector<IntVar*> right_;
443 std::vector<IntVarIterator*> left_hole_iterators_;
444 std::vector<IntVarIterator*> left_domain_iterators_;
445 std::vector<IntVarIterator*> right_hole_iterators_;
446 std::vector<IntVarIterator*> right_domain_iterators_;
447
448 // used only in PropagateDomain().
449 std::vector<int64_t> tmp_removed_values_;
450};
451
452// Index of first Max Value
453
454class IndexOfFirstMaxValue : public Constraint {
455 public:
456 IndexOfFirstMaxValue(Solver* solver, IntVar* index,
457 const std::vector<IntVar*>& vars)
458 : Constraint(solver), index_(index), vars_(vars) {}
459
460 ~IndexOfFirstMaxValue() override {}
461
462 void Post() override {
463 Demon* const demon =
464 solver()->MakeDelayedConstraintInitialPropagateCallback(this);
465 index_->WhenRange(demon);
466 for (IntVar* const var : vars_) {
467 var->WhenRange(demon);
468 }
469 }
470
471 void InitialPropagate() override {
472 const int64_t vsize = vars_.size();
473 const int64_t imin = std::max(int64_t{0}, index_->Min());
474 const int64_t imax = std::min(vsize - 1, index_->Max());
475 int64_t max_max = std::numeric_limits<int64_t>::min();
476 int64_t max_min = std::numeric_limits<int64_t>::min();
477
478 // Compute min and max value in the current interval covered by index_.
479 for (int i = imin; i <= imax; ++i) {
480 max_max = std::max(max_max, vars_[i]->Max());
481 max_min = std::max(max_min, vars_[i]->Min());
482 }
483
484 // Propagate the fact that the first maximum value belongs to the
485 // [imin..imax].
486 for (int i = 0; i < imin; ++i) {
487 vars_[i]->SetMax(max_max - 1);
488 }
489 for (int i = imax + 1; i < vsize; ++i) {
490 vars_[i]->SetMax(max_max);
491 }
492
493 // Shave bounds for index_.
494 int64_t min_index = imin;
495 while (vars_[min_index]->Max() < max_min) {
496 min_index++;
497 }
498 int64_t max_index = imax;
499 while (vars_[max_index]->Max() < max_min) {
500 max_index--;
501 }
502 index_->SetRange(min_index, max_index);
503 }
504
505 std::string DebugString() const override {
506 return absl::StrFormat("IndexMax(%s, [%s])", index_->DebugString(),
507 JoinDebugStringPtr(vars_, ", "));
508 }
509
510 void Accept(ModelVisitor* const visitor) const override {
511 // TODO(user): Implement me.
512 }
513
514 private:
515 IntVar* const index_;
516 const std::vector<IntVar*> vars_;
517};
518} // namespace
519
520// ----- API -----
521
523 return RevAlloc(new ActionDemon(action));
524}
525
527 return RevAlloc(new ClosureDemon(closure));
528}
529
531 DCHECK(true_constraint_ != nullptr);
532 return true_constraint_;
533}
534
536 DCHECK(false_constraint_ != nullptr);
537 return false_constraint_;
538}
539Constraint* Solver::MakeFalseConstraint(const std::string& explanation) {
540 return RevAlloc(new FalseConstraint(this, explanation));
541}
542
543void Solver::InitCachedConstraint() {
544 DCHECK(true_constraint_ == nullptr);
545 true_constraint_ = RevAlloc(new TrueConstraint(this));
546 DCHECK(false_constraint_ == nullptr);
547 false_constraint_ = RevAlloc(new FalseConstraint(this));
548}
549
551 const std::vector<IntVar*>& actives) {
552 return RevAlloc(new MapDomain(this, var, actives));
553}
554
555Constraint* Solver::MakeLexicalLess(const std::vector<IntVar*>& left,
556 const std::vector<IntVar*>& right) {
557 std::vector<IntVar*> adjusted_left = left;
558 adjusted_left.push_back(MakeIntConst(1));
559 std::vector<IntVar*> adjusted_right = right;
560 adjusted_right.push_back(MakeIntConst(0));
562 std::move(adjusted_left), std::move(adjusted_right),
563 std::vector<int64_t>(left.size() + 1, 1));
564}
565
566Constraint* Solver::MakeLexicalLessOrEqual(const std::vector<IntVar*>& left,
567 const std::vector<IntVar*>& right) {
569 left, right, std::vector<int64_t>(left.size(), 1));
570}
571
573 std::vector<IntVar*> left, std::vector<IntVar*> right,
574 std::vector<int64_t> offsets) {
575 return RevAlloc(new LexicalLessOrEqual(this, std::move(left),
576 std::move(right), std::move(offsets)));
577}
578
580 std::vector<IntVar*> left, std::vector<IntVar*> right,
581 std::vector<int64_t> offsets, IntVar* boolvar) {
582 std::vector<IntVar*> adjusted_left = std::move(left);
583 adjusted_left.insert(adjusted_left.begin(), boolvar);
584 std::vector<IntVar*> adjusted_right = std::move(right);
585 adjusted_right.insert(adjusted_right.begin(), MakeIntConst(1));
586 std::vector<int64_t> adjusted_offsets = std::move(offsets);
587 adjusted_offsets.insert(adjusted_offsets.begin(), 1);
588 return MakeLexicalLessOrEqualWithOffsets(std::move(adjusted_left),
589 std::move(adjusted_right),
590 std::move(adjusted_offsets));
591}
592
594 const std::vector<IntVar*>& left, const std::vector<IntVar*>& right) {
595 return RevAlloc(new InversePermutationConstraint(this, left, right));
596}
597
599 IntVar* index, const std::vector<IntVar*>& vars) {
600 return RevAlloc(new IndexOfFirstMaxValue(this, index, vars));
601}
602
604 IntVar* index, const std::vector<IntVar*>& vars) {
605 std::vector<IntVar*> opp_vars(vars.size());
606 for (int i = 0; i < vars.size(); ++i) {
607 opp_vars[i] = MakeOpposite(vars[i])->Var();
608 }
609 return RevAlloc(new IndexOfFirstMaxValue(this, index, opp_vars));
610}
611} // namespace operations_research
IntegerValue size
const std::vector< IntVar * > vars_
virtual void InitialPropagate()=0
virtual IntVar * Var()=0
Creates a variable from the expression.
Constraint * MakeIsLexicalLessOrEqualWithOffsetsCt(std::vector< IntVar * > left, std::vector< IntVar * > right, std::vector< int64_t > offsets, IntVar *boolvar)
Semi-reified version of the above: boolvar -> LexLE(left, right, offsets).
Demon * MakeClosureDemon(Closure closure)
Creates a demon from a closure.
Constraint * MakeLexicalLess(const std::vector< IntVar * > &left, const std::vector< IntVar * > &right)
std::function< void(Solver *)> Action
IntExpr * MakeOpposite(IntExpr *expr)
-expr
Constraint * MakeLexicalLessOrEqual(const std::vector< IntVar * > &left, const std::vector< IntVar * > &right)
Constraint * MakeIndexOfFirstMinValueConstraint(IntVar *index, const std::vector< IntVar * > &vars)
Constraint * MakeIndexOfFirstMaxValueConstraint(IntVar *index, const std::vector< IntVar * > &vars)
std::function< void()> Closure
Constraint * MakeMapDomain(IntVar *var, const std::vector< IntVar * > &actives)
Constraint * MakeTrueConstraint()
This constraint always succeeds.
Demon * MakeDelayedConstraintInitialPropagateCallback(Constraint *ct)
Constraint * MakeLexicalLessOrEqualWithOffsets(std::vector< IntVar * > left, std::vector< IntVar * > right, std::vector< int64_t > offsets)
Demon * MakeConstraintInitialPropagateCallback(Constraint *ct)
Constraint * MakeFalseConstraint()
This constraint always fails.
IntVar * MakeIntConst(int64_t val, const std::string &name)
IntConst will create a constant expression.
Demon * MakeActionDemon(Action action)
Creates a demon from a callback.
Constraint * MakeInversePermutationConstraint(const std::vector< IntVar * > &left, const std::vector< IntVar * > &right)
const Constraint * ct
int64_t value
IntVar * var
int index
For infeasible and unbounded see Not checked if options check_solutions_if_inf_or_unbounded and the If options first_solution_only is false
problem is infeasible or unbounded (default).
Definition matchers.h:468
In SWIG mode, we don't want anything besides these top-level includes.
int64_t CapAdd(int64_t x, int64_t y)
std::string JoinDebugStringPtr(const std::vector< T > &v, absl::string_view separator)
Join v[i]->DebugString().
int64_t CapSub(int64_t x, int64_t y)
Demon * MakeDelayedConstraintDemon0(Solver *const s, T *const ct, void(T::*method)(), const std::string &name)
Demon * MakeConstraintDemon0(Solver *const s, T *const ct, void(T::*method)(), const std::string &name)
Demon * MakeConstraintDemon1(Solver *const s, T *const ct, void(T::*method)(P), const std::string &name, P param1)
STL namespace.