20#include "absl/strings/str_format.h"
29int64_t ValueToIndex(int64_t
value) {
return value - 1; }
31int64_t IndexToValue(int64_t
index) {
return index + 1; }
40 const std::vector<IntervalVar*>& intervals,
41 const std::vector<IntVar*>& nexts,
42 const std::string&
name)
44 intervals_(intervals),
46 previous_(nexts.size() + 1, -1) {
53 return intervals_[
index];
59 int64_t hmin, hmax, dmin, dmax;
66 return absl::StrFormat(
67 "%s(horizon = %d..%d, duration = %d..%d, not ranked = %d, ranked = %d, "
69 name(), hmin, hmax, dmin, dmax, not_ranked, ranked,
78 int64_t*
const dmax)
const {
81 for (
int i = 0; i < intervals_.size(); ++i) {
97 for (
int i = 0; i < intervals_.size(); ++i) {
110 int64_t*
const hmax)
const {
111 absl::flat_hash_set<int> decided;
112 for (
int i = 0; i < intervals_.size(); ++i) {
113 if (intervals_[i]->CannotBePerformed()) {
118 while (nexts_[first]->Bound()) {
119 first = nexts_[first]->Min();
120 if (first < nexts_.size()) {
121 decided.insert(ValueToIndex(first));
126 if (first != nexts_.size()) {
128 int last = nexts_.size();
129 while (previous_[last] != -1) {
130 last = previous_[last];
131 decided.insert(ValueToIndex(last));
136 for (
int i = 0; i < intervals_.size(); ++i) {
137 if (!decided.contains(i)) {
148 int*
const unperformed)
const {
150 for (
int i = 0; i < intervals_.size(); ++i) {
151 if (intervals_[i]->CannotBePerformed()) {
157 while (first < nexts_.size() && nexts_[first]->Bound()) {
158 first = nexts_[first]->Min();
161 if (first != nexts_.size()) {
163 int last = nexts_.size();
164 while (previous_[last] != -1) {
165 last = previous_[last];
171 *not_ranked = intervals_.size() - *ranked - *unperformed;
174int SequenceVar::ComputeForwardFrontier() {
176 while (first != nexts_.size() && nexts_[first]->Bound()) {
177 first = nexts_[first]->Min();
182int SequenceVar::ComputeBackwardFrontier() {
184 int last = nexts_.size();
185 while (previous_[last] != -1) {
186 last = previous_[last];
192 std::vector<int>*
const possible_firsts,
193 std::vector<int>*
const possible_lasts) {
194 possible_firsts->clear();
195 possible_lasts->clear();
196 absl::flat_hash_set<int> to_check;
197 for (
int i = 0; i < intervals_.size(); ++i) {
198 if (intervals_[i]->MayBePerformed()) {
203 while (nexts_[first]->Bound()) {
204 first = nexts_[first]->Min();
205 if (first == nexts_.size()) {
208 to_check.erase(ValueToIndex(first));
211 IntVar*
const forward_var = nexts_[first];
212 std::vector<int> candidates;
214 int ssm_support = -1;
215 for (int64_t i = forward_var->
Min(); i <= forward_var->Max(); ++i) {
217 if (i != 0 && i < IndexToValue(intervals_.size()) &&
218 intervals_[ValueToIndex(i)]->MayBePerformed() &&
220 const int candidate = ValueToIndex(i);
221 candidates.push_back(candidate);
222 if (intervals_[candidate]->MustBePerformed()) {
223 if (smallest_start_max > intervals_[candidate]->StartMax()) {
224 smallest_start_max = intervals_[candidate]->StartMax();
225 ssm_support = candidate;
230 for (
int i = 0; i < candidates.size(); ++i) {
231 const int candidate = candidates[i];
232 if (candidate == ssm_support ||
233 intervals_[candidate]->EndMin() <= smallest_start_max) {
234 possible_firsts->push_back(candidate);
239 int last = nexts_.size();
240 while (previous_[last] != -1) {
241 last = previous_[last];
242 to_check.erase(ValueToIndex(last));
247 int bem_support = -1;
248 for (
const int candidate : to_check) {
249 if (nexts_[IndexToValue(candidate)]->Contains(last)) {
250 candidates.push_back(candidate);
251 if (intervals_[candidate]->MustBePerformed()) {
252 if (biggest_end_min < intervals_[candidate]->EndMin()) {
253 biggest_end_min = intervals_[candidate]->EndMin();
254 bem_support = candidate;
260 for (
int i = 0; i < candidates.size(); ++i) {
261 const int candidate = candidates[i];
262 if (candidate == bem_support ||
263 intervals_[candidate]->StartMax() >= biggest_end_min) {
264 possible_lasts->push_back(candidate);
270 const std::vector<int>& rank_last,
271 const std::vector<int>& unperformed) {
275 for (
const int value : unperformed) {
276 intervals_[
value]->SetPerformed(
false);
280 for (
int i = 0; i < rank_first.size(); ++i) {
281 const int next = 1 + rank_first[i];
282 nexts_[forward]->SetValue(
next);
286 int backward = IndexToValue(intervals_.size());
287 for (
int i = 0; i < rank_last.size(); ++i) {
288 const int next = 1 + rank_last[i];
289 nexts_[
next]->SetValue(backward);
296 intervals_[
index]->SetPerformed(
true);
297 int forward_frontier = 0;
298 while (forward_frontier != nexts_.size() &&
299 nexts_[forward_frontier]->Bound()) {
300 forward_frontier = nexts_[forward_frontier]->Min();
301 if (forward_frontier == IndexToValue(
index)) {
305 DCHECK_LT(forward_frontier, nexts_.size());
306 nexts_[forward_frontier]->SetValue(IndexToValue(
index));
311 const int forward_frontier = ComputeForwardFrontier();
312 if (forward_frontier < nexts_.size()) {
313 nexts_[forward_frontier]->RemoveValue(IndexToValue(
index));
319 intervals_[
index]->SetPerformed(
true);
321 int backward_frontier = nexts_.size();
322 while (previous_[backward_frontier] != -1) {
323 backward_frontier = previous_[backward_frontier];
324 if (backward_frontier == IndexToValue(
index)) {
329 nexts_[IndexToValue(
index)]->SetValue(backward_frontier);
334 const int backward_frontier = ComputeBackwardFrontier();
335 nexts_[IndexToValue(
index)]->RemoveValue(backward_frontier);
338void SequenceVar::UpdatePrevious()
const {
339 for (
int i = 0; i < intervals_.size() + 2; ++i) {
342 for (
int i = 0; i < nexts_.size(); ++i) {
343 if (nexts_[i]->Bound()) {
344 previous_[nexts_[i]->Min()] = i;
350 std::vector<int>*
const rank_last,
351 std::vector<int>*
const unperformed)
const {
352 CHECK(rank_first !=
nullptr);
353 CHECK(rank_last !=
nullptr);
354 CHECK(unperformed !=
nullptr);
357 unperformed->clear();
358 for (
int i = 0; i < intervals_.size(); ++i) {
359 if (intervals_[i]->CannotBePerformed()) {
360 unperformed->push_back(i);
364 while (nexts_[first]->Bound()) {
365 first = nexts_[first]->Min();
366 if (first < nexts_.size()) {
367 rank_first->push_back(ValueToIndex(first));
372 if (first != nexts_.size()) {
374 int last = nexts_.size();
375 while (previous_[last] != -1) {
376 last = previous_[last];
377 rank_last->push_back(ValueToIndex(last));
390class ScheduleOrPostpone :
public Decision {
392 ScheduleOrPostpone(
IntervalVar*
const var, int64_t est, int64_t*
const marker)
393 : var_(
var), est_(est), marker_(marker) {}
394 ~ScheduleOrPostpone()
override {}
396 void Apply(Solver*
const s)
override {
397 var_->SetPerformed(
true);
398 if (est_.Value() < var_->StartMin()) {
399 est_.SetValue(s, var_->StartMin());
401 var_->SetStartRange(est_.Value(), est_.Value());
404 void Refute(Solver*
const s)
override {
405 s->SaveAndSetValue(marker_, est_.Value());
408 void Accept(DecisionVisitor*
const visitor)
const override {
409 CHECK(visitor !=
nullptr);
410 visitor->VisitScheduleOrPostpone(var_, est_.Value());
413 std::string DebugString()
const override {
414 return absl::StrFormat(
"ScheduleOrPostpone(%s at %d)", var_->DebugString(),
419 IntervalVar*
const var_;
420 NumericalRev<int64_t> est_;
421 int64_t*
const marker_;
424class SetTimesForward :
public DecisionBuilder {
426 explicit SetTimesForward(
const std::vector<IntervalVar*>& vars)
428 markers_(vars.size(),
std::numeric_limits<int64_t>::
min()) {}
430 ~SetTimesForward()
override {}
432 Decision* Next(Solver*
const s)
override {
439 for (
int i = 0; i <
vars_.size(); ++i) {
440 IntervalVar*
const v =
vars_[i];
441 if (v->MayBePerformed() && v->StartMax() != v->StartMin() &&
443 (v->StartMin() < best_est ||
444 (v->StartMin() == best_est && v->EndMax() < best_lct))) {
445 best_est = v->StartMin();
446 best_lct = v->EndMax();
456 UnperformPostponedTaskBefore(best_est);
458 new ScheduleOrPostpone(vars_[support], best_est, &markers_[support]));
461 std::string DebugString()
const override {
return "SetTimesForward()"; }
463 void Accept(ModelVisitor*
const visitor)
const override {
471 bool IsPostponed(
int index) {
476 void UnperformPostponedTaskBefore(int64_t date) {
477 for (
int i = 0; i <
vars_.size(); ++i) {
478 IntervalVar*
const v =
vars_[i];
479 if (v->MayBePerformed() && v->StartMin() != v->StartMax() &&
488 (v->EndMin() <= date || v->StartMax() <= date)) {
489 v->SetPerformed(
false);
494 const std::vector<IntervalVar*>
vars_;
495 std::vector<int64_t> markers_;
501class ScheduleOrExpedite :
public Decision {
503 ScheduleOrExpedite(IntervalVar*
const var, int64_t est, int64_t*
const marker)
504 : var_(
var), est_(est), marker_(marker) {}
505 ~ScheduleOrExpedite()
override {}
507 void Apply(Solver*
const s)
override {
508 var_->SetPerformed(
true);
509 if (est_.Value() > var_->EndMax()) {
510 est_.SetValue(s, var_->EndMax());
512 var_->SetEndRange(est_.Value(), est_.Value());
515 void Refute(Solver*
const s)
override {
516 s->SaveAndSetValue(marker_, est_.Value() - 1);
519 void Accept(DecisionVisitor*
const visitor)
const override {
520 CHECK(visitor !=
nullptr);
521 visitor->VisitScheduleOrExpedite(var_, est_.Value());
524 std::string DebugString()
const override {
525 return absl::StrFormat(
"ScheduleOrExpedite(%s at %d)", var_->DebugString(),
530 IntervalVar*
const var_;
531 NumericalRev<int64_t> est_;
532 int64_t*
const marker_;
535class SetTimesBackward :
public DecisionBuilder {
537 explicit SetTimesBackward(
const std::vector<IntervalVar*>& vars)
539 markers_(vars.size(),
std::numeric_limits<int64_t>::
max()) {}
541 ~SetTimesBackward()
override {}
543 Decision* Next(Solver*
const s)
override {
548 for (
int i = 0; i <
vars_.size(); ++i) {
549 IntervalVar*
const v =
vars_[i];
550 if (v->MayBePerformed() && v->EndMax() > v->EndMin()) {
551 if (v->EndMax() <= markers_[i] &&
552 (v->EndMax() > best_end ||
553 (v->EndMax() == best_end && v->StartMin() > best_start))) {
554 best_end = v->EndMax();
555 best_start = v->StartMin();
571 return s->RevAlloc(
new ScheduleOrExpedite(
572 vars_[support], vars_[support]->EndMax(), &markers_[support]));
575 std::string DebugString()
const override {
return "SetTimesBackward()"; }
577 void Accept(ModelVisitor*
const visitor)
const override {
585 const std::vector<IntervalVar*>
vars_;
586 std::vector<int64_t> markers_;
591class RankFirst :
public Decision {
593 RankFirst(SequenceVar*
const seq,
int index)
594 : sequence_(seq), index_(
index) {}
595 ~RankFirst()
override {}
597 void Apply(Solver*
const s)
override { sequence_->RankFirst(index_); }
599 void Refute(Solver*
const s)
override { sequence_->RankNotFirst(index_); }
601 void Accept(DecisionVisitor*
const visitor)
const override {
602 CHECK(visitor !=
nullptr);
603 visitor->VisitRankFirstInterval(sequence_, index_);
606 std::string DebugString()
const override {
607 return absl::StrFormat(
"RankFirst(%s, %d)", sequence_->DebugString(),
612 SequenceVar*
const sequence_;
616class RankLast :
public Decision {
618 RankLast(SequenceVar*
const seq,
int index) : sequence_(seq), index_(
index) {}
619 ~RankLast()
override {}
621 void Apply(Solver*
const s)
override { sequence_->RankLast(index_); }
623 void Refute(Solver*
const s)
override { sequence_->RankNotLast(index_); }
625 void Accept(DecisionVisitor*
const visitor)
const override {
626 CHECK(visitor !=
nullptr);
627 visitor->VisitRankLastInterval(sequence_, index_);
630 std::string DebugString()
const override {
631 return absl::StrFormat(
"RankLast(%s, %d)", sequence_->DebugString(),
636 SequenceVar*
const sequence_;
640class RankFirstIntervalVars :
public DecisionBuilder {
642 RankFirstIntervalVars(
const std::vector<SequenceVar*>& sequences,
644 : sequences_(sequences), strategy_(str) {}
646 ~RankFirstIntervalVars()
override {}
648 Decision* Next(Solver*
const s)
override {
649 SequenceVar* best_sequence =
nullptr;
650 best_possible_firsts_.clear();
652 if (FindSequenceVar(s, &best_sequence)) {
654 DCHECK(best_sequence !=
nullptr);
655 if (best_possible_firsts_.size() == 1 &&
656 best_sequence->Interval(best_possible_firsts_.back())
657 ->MustBePerformed()) {
658 best_sequence->RankFirst(best_possible_firsts_.back());
661 int best_interval = -1;
662 if (!FindIntervalVar(s, best_sequence, &best_interval)) {
666 return s->RevAlloc(
new RankFirst(best_sequence, best_interval));
673 void Accept(ModelVisitor*
const visitor)
const override {
682 bool FindIntervalVarOnStartMin(Solver*
const s,
683 SequenceVar*
const best_sequence,
684 int*
const best_interval_index) {
685 int best_interval = -1;
688 const int candidate = best_possible_firsts_[
index];
689 IntervalVar*
const interval = best_sequence->Interval(candidate);
690 if (
interval->StartMin() < best_start_min) {
691 best_interval = candidate;
692 best_start_min =
interval->StartMin();
695 if (best_interval == -1) {
698 *best_interval_index = best_interval;
703 bool FindIntervalVarRandomly(Solver*
const s,
704 SequenceVar*
const best_sequence,
705 int*
const best_interval_index) {
706 DCHECK(!best_possible_firsts_.empty());
707 const int index = s->Rand32(best_possible_firsts_.size());
708 *best_interval_index = best_possible_firsts_[
index];
712 bool FindIntervalVar(Solver*
const s, SequenceVar*
const best_sequence,
713 int*
const best_interval_index) {
718 return FindIntervalVarOnStartMin(s, best_sequence, best_interval_index);
720 return FindIntervalVarRandomly(s, best_sequence, best_interval_index);
722 LOG(
FATAL) <<
"Unknown strategy " << strategy_;
728 bool FindSequenceVarOnSlack(Solver*
const s,
729 SequenceVar**
const best_sequence) {
732 *best_sequence =
nullptr;
733 best_possible_firsts_.clear();
734 for (
int i = 0; i < sequences_.size(); ++i) {
735 SequenceVar*
const candidate_sequence = sequences_[i];
739 candidate_sequence->ComputeStatistics(&ranked, ¬_ranked, &unperformed);
740 if (not_ranked > 0) {
741 candidate_possible_firsts_.clear();
742 candidate_possible_lasts_.clear();
743 candidate_sequence->ComputePossibleFirstsAndLasts(
744 &candidate_possible_firsts_, &candidate_possible_lasts_);
746 if (candidate_possible_firsts_.empty()) {
750 if (candidate_possible_firsts_.size() == 1 &&
751 candidate_sequence->Interval(candidate_possible_firsts_.back())
752 ->MustBePerformed()) {
753 *best_sequence = candidate_sequence;
754 best_possible_firsts_ = candidate_possible_firsts_;
759 int64_t hmin, hmax, dmin, dmax;
760 candidate_sequence->HorizonRange(&hmin, &hmax);
761 candidate_sequence->DurationRange(&dmin, &dmax);
762 int64_t ahmin, ahmax;
763 candidate_sequence->ActiveHorizonRange(&ahmin, &ahmax);
764 const int64_t current_slack = (hmax - hmin - dmax);
765 if (current_slack < best_slack ||
766 (current_slack == best_slack && ahmin < best_ahmin)) {
767 best_slack = current_slack;
768 *best_sequence = candidate_sequence;
769 best_possible_firsts_ = candidate_possible_firsts_;
774 return *best_sequence !=
nullptr;
777 bool FindSequenceVarRandomly(Solver*
const s,
778 SequenceVar**
const best_sequence) {
779 std::vector<SequenceVar*> all_candidates;
780 std::vector<std::vector<int>> all_possible_firsts;
781 for (
int i = 0; i < sequences_.size(); ++i) {
782 SequenceVar*
const candidate_sequence = sequences_[i];
786 candidate_sequence->ComputeStatistics(&ranked, ¬_ranked, &unperformed);
787 if (not_ranked > 0) {
788 candidate_possible_firsts_.clear();
789 candidate_possible_lasts_.clear();
790 candidate_sequence->ComputePossibleFirstsAndLasts(
791 &candidate_possible_firsts_, &candidate_possible_lasts_);
793 if (candidate_possible_firsts_.empty()) {
797 if (candidate_possible_firsts_.size() == 1 &&
798 candidate_sequence->Interval(candidate_possible_firsts_.back())
799 ->MustBePerformed()) {
800 *best_sequence = candidate_sequence;
801 best_possible_firsts_ = candidate_possible_firsts_;
805 all_candidates.push_back(candidate_sequence);
806 all_possible_firsts.push_back(candidate_possible_firsts_);
809 if (all_candidates.empty()) {
812 const int chosen = s->Rand32(all_candidates.size());
813 *best_sequence = all_candidates[chosen];
814 best_possible_firsts_ = all_possible_firsts[chosen];
818 bool FindSequenceVar(Solver*
const s, SequenceVar**
const best_sequence) {
823 return FindSequenceVarOnSlack(s, best_sequence);
825 return FindSequenceVarRandomly(s, best_sequence);
827 LOG(
FATAL) <<
"Unknown strategy " << strategy_;
831 const std::vector<SequenceVar*> sequences_;
833 std::vector<int> best_possible_firsts_;
834 std::vector<int> candidate_possible_firsts_;
835 std::vector<int> candidate_possible_lasts_;
840 int64_t*
const marker) {
842 CHECK(marker !=
nullptr);
843 return RevAlloc(
new ScheduleOrPostpone(
var, est, marker));
847 int64_t*
const marker) {
849 CHECK(marker !=
nullptr);
850 return RevAlloc(
new ScheduleOrExpedite(
var, est, marker));
859 return RevAlloc(
new SetTimesForward(intervals));
861 return RevAlloc(
new SetTimesBackward(intervals));
863 LOG(
FATAL) <<
"Unknown strategy " << str;
869 CHECK(sequence !=
nullptr);
874 CHECK(sequence !=
nullptr);
880 return RevAlloc(
new RankFirstIntervalVars(sequences, str));
const std::vector< IntVar * > vars_
#define DCHECK_NE(val1, val2)
#define CHECK_NE(val1, val2)
#define DCHECK_LT(val1, val2)
#define DCHECK(condition)
A DecisionBuilder is responsible for creating the search tree.
A Decision represents a choice point in the search tree.
virtual int64_t Min() const =0
The class IntVar is a subset of IntExpr.
virtual bool Contains(int64_t v) const =0
This method returns whether the value 'v' is in the domain of the variable.
Interval variables are often used in scheduling.
virtual int64_t DurationMax() const =0
virtual int64_t DurationMin() const =0
These methods query, set, and watch the duration of the interval var.
virtual bool MustBePerformed() const =0
These methods query, set, and watch the performed status of the interval var.
virtual int64_t StartMin() const =0
These methods query, set, and watch the start position of the interval var.
virtual int64_t EndMax() const =0
virtual bool MayBePerformed() const =0
virtual void VisitSequenceVariable(const SequenceVar *const variable)
static const char kIntervalsArgument[]
static const char kVariableGroupExtension[]
static const char kSequencesArgument[]
virtual std::string name() const
Object naming.
void set_name(const std::string &name)
virtual void RankLast(SequenceVar *const var, int index)=0
virtual void RankNotLast(SequenceVar *const var, int index)=0
virtual void RankNotFirst(SequenceVar *const var, int index)=0
virtual void RankSequence(SequenceVar *const var, const std::vector< int > &rank_first, const std::vector< int > &rank_last, const std::vector< int > &unperformed)=0
virtual void RankFirst(SequenceVar *const var, int index)=0
SequenceVar modifiers.
A sequence variable is a variable whose domain is a set of possible orderings of the interval variabl...
void ComputePossibleFirstsAndLasts(std::vector< int > *const possible_firsts, std::vector< int > *const possible_lasts)
Computes the set of indices of interval variables that can be ranked first in the set of unranked act...
void HorizonRange(int64_t *const hmin, int64_t *const hmax) const
Returns the minimum start min and the maximum end max of all interval vars in the sequence.
void FillSequence(std::vector< int > *const rank_first, std::vector< int > *const rank_last, std::vector< int > *const unperformed) const
Clears 'rank_first' and 'rank_last', and fills them with the intervals in the order of the ranks.
void RankSequence(const std::vector< int > &rank_first, const std::vector< int > &rank_last, const std::vector< int > &unperformed)
Applies the following sequence of ranks, ranks first, then rank last.
void ComputeStatistics(int *const ranked, int *const not_ranked, int *const unperformed) const
Compute statistics on the sequence.
void DurationRange(int64_t *const dmin, int64_t *const dmax) const
Returns the minimum and maximum duration of combined interval vars in the sequence.
void ActiveHorizonRange(int64_t *const hmin, int64_t *const hmax) const
Returns the minimum start min and the maximum end max of all unranked interval vars in the sequence.
IntVar * Next(int index) const
Returns the next of the index_th interval of the sequence.
IntervalVar * Interval(int index) const
Returns the index_th interval of the sequence.
void RankLast(int index)
Ranks the index_th interval var first of all unranked interval vars.
virtual void Accept(ModelVisitor *const visitor) const
Accepts the given visitor.
void RankFirst(int index)
Ranks the index_th interval var first of all unranked interval vars.
void RankNotLast(int index)
Indicates that the index_th interval var will not be ranked first of all currently unranked interval ...
void RankNotFirst(int index)
Indicates that the index_th interval var will not be ranked first of all currently unranked interval ...
SequenceVar(Solver *const s, const std::vector< IntervalVar * > &intervals, const std::vector< IntVar * > &nexts, const std::string &name)
std::string DebugString() const override
Decision * MakeScheduleOrExpedite(IntervalVar *const var, int64_t est, int64_t *const marker)
Returns a decision that tries to schedule a task at a given time.
IntervalStrategy
This enum describes the straregy used to select the next interval variable and its value to be fixed.
@ INTERVAL_SET_TIMES_FORWARD
Selects the variable with the lowest starting time of all variables, and fixes its starting time to t...
@ INTERVAL_SIMPLE
The simple is INTERVAL_SET_TIMES_FORWARD.
@ INTERVAL_SET_TIMES_BACKWARD
Selects the variable with the highest ending time of all variables, and fixes the ending time to this...
@ INTERVAL_DEFAULT
The default is INTERVAL_SET_TIMES_FORWARD.
PropagationMonitor * GetPropagationMonitor() const
Returns the propagation monitor.
Decision * MakeRankFirstInterval(SequenceVar *const sequence, int index)
Returns a decision that tries to rank first the ith interval var in the sequence variable.
DecisionBuilder * MakePhase(const std::vector< IntVar * > &vars, IntVarStrategy var_str, IntValueStrategy val_str)
Phases on IntVar arrays.
SequenceStrategy
Used for scheduling. Not yet implemented.
@ CHOOSE_MIN_SLACK_RANK_FORWARD
@ CHOOSE_RANDOM_RANK_FORWARD
Decision * MakeScheduleOrPostpone(IntervalVar *const var, int64_t est, int64_t *const marker)
Returns a decision that tries to schedule a task at a given time.
Decision * MakeRankLastInterval(SequenceVar *const sequence, int index)
Returns a decision that tries to rank last the ith interval var in the sequence variable.
T * RevAlloc(T *object)
Registers the given object as being reversible.
Collection of objects used to extend the Constraint Solver library.
std::string JoinDebugStringPtr(const std::vector< T > &v, const std::string &separator)