21 #include "absl/strings/str_format.h"
30 int64_t ValueToIndex(int64_t
value) {
return value - 1; }
32 int64_t IndexToValue(int64_t
index) {
return index + 1; }
41 const std::vector<IntervalVar*>& intervals,
42 const std::vector<IntVar*>& nexts,
43 const std::string&
name)
45 intervals_(intervals),
47 previous_(nexts.size() + 1, -1) {
54 return intervals_[
index];
60 int64_t hmin, hmax, dmin, dmax;
67 return absl::StrFormat(
68 "%s(horizon = %d..%d, duration = %d..%d, not ranked = %d, ranked = %d, "
70 name(), hmin, hmax, dmin, dmax, not_ranked, ranked,
79 int64_t*
const dmax)
const {
82 for (
int i = 0; i < intervals_.size(); ++i) {
98 for (
int i = 0; i < intervals_.size(); ++i) {
111 int64_t*
const hmax)
const {
112 absl::flat_hash_set<int> decided;
113 for (
int i = 0; i < intervals_.size(); ++i) {
114 if (intervals_[i]->CannotBePerformed()) {
119 while (nexts_[first]->Bound()) {
120 first = nexts_[first]->Min();
121 if (first < nexts_.size()) {
122 decided.insert(ValueToIndex(first));
127 if (first != nexts_.size()) {
129 int last = nexts_.size();
130 while (previous_[last] != -1) {
131 last = previous_[last];
132 decided.insert(ValueToIndex(last));
137 for (
int i = 0; i < intervals_.size(); ++i) {
138 if (!decided.contains(i)) {
149 int*
const unperformed)
const {
151 for (
int i = 0; i < intervals_.size(); ++i) {
152 if (intervals_[i]->CannotBePerformed()) {
158 while (first < nexts_.size() && nexts_[first]->Bound()) {
159 first = nexts_[first]->Min();
162 if (first != nexts_.size()) {
164 int last = nexts_.size();
165 while (previous_[last] != -1) {
166 last = previous_[last];
172 *not_ranked = intervals_.size() - *ranked - *unperformed;
175 int SequenceVar::ComputeForwardFrontier() {
177 while (first != nexts_.size() && nexts_[first]->Bound()) {
178 first = nexts_[first]->Min();
183 int SequenceVar::ComputeBackwardFrontier() {
185 int last = nexts_.size();
186 while (previous_[last] != -1) {
187 last = previous_[last];
193 std::vector<int>*
const possible_firsts,
194 std::vector<int>*
const possible_lasts) {
195 possible_firsts->clear();
196 possible_lasts->clear();
197 absl::flat_hash_set<int> to_check;
198 for (
int i = 0; i < intervals_.size(); ++i) {
199 if (intervals_[i]->MayBePerformed()) {
204 while (nexts_[first]->Bound()) {
205 first = nexts_[first]->Min();
206 if (first == nexts_.size()) {
209 to_check.erase(ValueToIndex(first));
212 IntVar*
const forward_var = nexts_[first];
213 std::vector<int> candidates;
215 int ssm_support = -1;
216 for (int64_t i = forward_var->
Min(); i <= forward_var->Max(); ++i) {
218 if (i != 0 && i < IndexToValue(intervals_.size()) &&
219 intervals_[ValueToIndex(i)]->MayBePerformed() &&
221 const int candidate = ValueToIndex(i);
222 candidates.push_back(candidate);
223 if (intervals_[candidate]->MustBePerformed()) {
224 if (smallest_start_max > intervals_[candidate]->StartMax()) {
225 smallest_start_max = intervals_[candidate]->StartMax();
226 ssm_support = candidate;
231 for (
int i = 0; i < candidates.size(); ++i) {
232 const int candidate = candidates[i];
233 if (candidate == ssm_support ||
234 intervals_[candidate]->EndMin() <= smallest_start_max) {
235 possible_firsts->push_back(candidate);
240 int last = nexts_.size();
241 while (previous_[last] != -1) {
242 last = previous_[last];
243 to_check.erase(ValueToIndex(last));
248 int bem_support = -1;
249 for (
const int candidate : to_check) {
250 if (nexts_[IndexToValue(candidate)]->Contains(last)) {
251 candidates.push_back(candidate);
252 if (intervals_[candidate]->MustBePerformed()) {
253 if (biggest_end_min < intervals_[candidate]->EndMin()) {
254 biggest_end_min = intervals_[candidate]->EndMin();
255 bem_support = candidate;
261 for (
int i = 0; i < candidates.size(); ++i) {
262 const int candidate = candidates[i];
263 if (candidate == bem_support ||
264 intervals_[candidate]->StartMax() >= biggest_end_min) {
265 possible_lasts->push_back(candidate);
271 const std::vector<int>& rank_last,
272 const std::vector<int>& unperformed) {
276 for (
const int value : unperformed) {
277 intervals_[
value]->SetPerformed(
false);
281 for (
int i = 0; i < rank_first.size(); ++i) {
282 const int next = 1 + rank_first[i];
283 nexts_[forward]->SetValue(
next);
287 int backward = IndexToValue(intervals_.size());
288 for (
int i = 0; i < rank_last.size(); ++i) {
289 const int next = 1 + rank_last[i];
290 nexts_[
next]->SetValue(backward);
297 intervals_[
index]->SetPerformed(
true);
298 int forward_frontier = 0;
299 while (forward_frontier != nexts_.size() &&
300 nexts_[forward_frontier]->Bound()) {
301 forward_frontier = nexts_[forward_frontier]->Min();
302 if (forward_frontier == IndexToValue(
index)) {
306 DCHECK_LT(forward_frontier, nexts_.size());
307 nexts_[forward_frontier]->SetValue(IndexToValue(
index));
312 const int forward_frontier = ComputeForwardFrontier();
313 if (forward_frontier < nexts_.size()) {
314 nexts_[forward_frontier]->RemoveValue(IndexToValue(
index));
320 intervals_[
index]->SetPerformed(
true);
322 int backward_frontier = nexts_.size();
323 while (previous_[backward_frontier] != -1) {
324 backward_frontier = previous_[backward_frontier];
325 if (backward_frontier == IndexToValue(
index)) {
329 DCHECK_NE(backward_frontier, 0);
330 nexts_[IndexToValue(
index)]->SetValue(backward_frontier);
335 const int backward_frontier = ComputeBackwardFrontier();
336 nexts_[IndexToValue(
index)]->RemoveValue(backward_frontier);
339 void SequenceVar::UpdatePrevious()
const {
340 for (
int i = 0; i < intervals_.size() + 2; ++i) {
343 for (
int i = 0; i < nexts_.size(); ++i) {
344 if (nexts_[i]->Bound()) {
345 previous_[nexts_[i]->Min()] = i;
351 std::vector<int>*
const rank_last,
352 std::vector<int>*
const unperformed)
const {
353 CHECK(rank_first !=
nullptr);
354 CHECK(rank_last !=
nullptr);
355 CHECK(unperformed !=
nullptr);
358 unperformed->clear();
359 for (
int i = 0; i < intervals_.size(); ++i) {
360 if (intervals_[i]->CannotBePerformed()) {
361 unperformed->push_back(i);
365 while (nexts_[first]->Bound()) {
366 first = nexts_[first]->Min();
367 if (first < nexts_.size()) {
368 rank_first->push_back(ValueToIndex(first));
373 if (first != nexts_.size()) {
375 int last = nexts_.size();
376 while (previous_[last] != -1) {
377 last = previous_[last];
378 rank_last->push_back(ValueToIndex(last));
391 class ScheduleOrPostpone :
public Decision {
393 ScheduleOrPostpone(
IntervalVar*
const var, int64_t est, int64_t*
const marker)
394 : var_(
var), est_(est), marker_(marker) {}
395 ~ScheduleOrPostpone()
override {}
397 void Apply(Solver*
const s)
override {
398 var_->SetPerformed(
true);
399 if (est_.Value() < var_->StartMin()) {
400 est_.SetValue(s, var_->StartMin());
402 var_->SetStartRange(est_.Value(), est_.Value());
405 void Refute(Solver*
const s)
override {
406 s->SaveAndSetValue(marker_, est_.Value());
409 void Accept(DecisionVisitor*
const visitor)
const override {
410 CHECK(visitor !=
nullptr);
411 visitor->VisitScheduleOrPostpone(var_, est_.Value());
414 std::string DebugString()
const override {
415 return absl::StrFormat(
"ScheduleOrPostpone(%s at %d)", var_->DebugString(),
420 IntervalVar*
const var_;
421 NumericalRev<int64_t> est_;
422 int64_t*
const marker_;
425 class SetTimesForward :
public DecisionBuilder {
427 explicit SetTimesForward(
const std::vector<IntervalVar*>& vars)
429 markers_(vars.size(), std::numeric_limits<int64_t>::
min()) {}
431 ~SetTimesForward()
override {}
433 Decision* Next(Solver*
const s)
override {
440 for (
int i = 0; i <
vars_.size(); ++i) {
441 IntervalVar*
const v =
vars_[i];
442 if (v->MayBePerformed() && v->StartMax() != v->StartMin() &&
444 (v->StartMin() < best_est ||
445 (v->StartMin() == best_est && v->EndMax() < best_lct))) {
446 best_est = v->StartMin();
447 best_lct = v->EndMax();
457 UnperformPostponedTaskBefore(best_est);
459 new ScheduleOrPostpone(vars_[support], best_est, &markers_[support]));
462 std::string DebugString()
const override {
return "SetTimesForward()"; }
464 void Accept(ModelVisitor*
const visitor)
const override {
472 bool IsPostponed(
int index) {
473 DCHECK(vars_[
index]->MayBePerformed());
477 void UnperformPostponedTaskBefore(int64_t date) {
478 for (
int i = 0; i <
vars_.size(); ++i) {
479 IntervalVar*
const v =
vars_[i];
480 if (v->MayBePerformed() && v->StartMin() != v->StartMax() &&
489 (v->EndMin() <= date || v->StartMax() <= date)) {
490 v->SetPerformed(
false);
495 const std::vector<IntervalVar*>
vars_;
496 std::vector<int64_t> markers_;
502 class ScheduleOrExpedite :
public Decision {
504 ScheduleOrExpedite(IntervalVar*
const var, int64_t est, int64_t*
const marker)
505 : var_(
var), est_(est), marker_(marker) {}
506 ~ScheduleOrExpedite()
override {}
508 void Apply(Solver*
const s)
override {
509 var_->SetPerformed(
true);
510 if (est_.Value() > var_->EndMax()) {
511 est_.SetValue(s, var_->EndMax());
513 var_->SetEndRange(est_.Value(), est_.Value());
516 void Refute(Solver*
const s)
override {
517 s->SaveAndSetValue(marker_, est_.Value() - 1);
520 void Accept(DecisionVisitor*
const visitor)
const override {
521 CHECK(visitor !=
nullptr);
522 visitor->VisitScheduleOrExpedite(var_, est_.Value());
525 std::string DebugString()
const override {
526 return absl::StrFormat(
"ScheduleOrExpedite(%s at %d)", var_->DebugString(),
531 IntervalVar*
const var_;
532 NumericalRev<int64_t> est_;
533 int64_t*
const marker_;
536 class SetTimesBackward :
public DecisionBuilder {
538 explicit SetTimesBackward(
const std::vector<IntervalVar*>& vars)
540 markers_(vars.size(), std::numeric_limits<int64_t>::
max()) {}
542 ~SetTimesBackward()
override {}
544 Decision* Next(Solver*
const s)
override {
549 for (
int i = 0; i <
vars_.size(); ++i) {
550 IntervalVar*
const v =
vars_[i];
551 if (v->MayBePerformed() && v->EndMax() > v->EndMin()) {
552 if (v->EndMax() <= markers_[i] &&
553 (v->EndMax() > best_end ||
554 (v->EndMax() == best_end && v->StartMin() > best_start))) {
555 best_end = v->EndMax();
556 best_start = v->StartMin();
572 return s->RevAlloc(
new ScheduleOrExpedite(
573 vars_[support], vars_[support]->EndMax(), &markers_[support]));
576 std::string DebugString()
const override {
return "SetTimesBackward()"; }
578 void Accept(ModelVisitor*
const visitor)
const override {
586 const std::vector<IntervalVar*>
vars_;
587 std::vector<int64_t> markers_;
592 class RankFirst :
public Decision {
594 RankFirst(SequenceVar*
const seq,
int index)
595 : sequence_(seq), index_(
index) {}
596 ~RankFirst()
override {}
598 void Apply(Solver*
const s)
override { sequence_->RankFirst(index_); }
600 void Refute(Solver*
const s)
override { sequence_->RankNotFirst(index_); }
602 void Accept(DecisionVisitor*
const visitor)
const override {
603 CHECK(visitor !=
nullptr);
604 visitor->VisitRankFirstInterval(sequence_, index_);
607 std::string DebugString()
const override {
608 return absl::StrFormat(
"RankFirst(%s, %d)", sequence_->DebugString(),
613 SequenceVar*
const sequence_;
617 class RankLast :
public Decision {
619 RankLast(SequenceVar*
const seq,
int index) : sequence_(seq), index_(
index) {}
620 ~RankLast()
override {}
622 void Apply(Solver*
const s)
override { sequence_->RankLast(index_); }
624 void Refute(Solver*
const s)
override { sequence_->RankNotLast(index_); }
626 void Accept(DecisionVisitor*
const visitor)
const override {
627 CHECK(visitor !=
nullptr);
628 visitor->VisitRankLastInterval(sequence_, index_);
631 std::string DebugString()
const override {
632 return absl::StrFormat(
"RankLast(%s, %d)", sequence_->DebugString(),
637 SequenceVar*
const sequence_;
641 class RankFirstIntervalVars :
public DecisionBuilder {
643 RankFirstIntervalVars(
const std::vector<SequenceVar*>& sequences,
645 : sequences_(sequences), strategy_(str) {}
647 ~RankFirstIntervalVars()
override {}
649 Decision* Next(Solver*
const s)
override {
650 SequenceVar* best_sequence =
nullptr;
651 best_possible_firsts_.clear();
653 if (FindSequenceVar(s, &best_sequence)) {
655 DCHECK(best_sequence !=
nullptr);
656 if (best_possible_firsts_.size() == 1 &&
657 best_sequence->Interval(best_possible_firsts_.back())
658 ->MustBePerformed()) {
659 best_sequence->RankFirst(best_possible_firsts_.back());
662 int best_interval = -1;
663 if (!FindIntervalVar(s, best_sequence, &best_interval)) {
666 CHECK_NE(-1, best_interval);
667 return s->RevAlloc(
new RankFirst(best_sequence, best_interval));
674 void Accept(ModelVisitor*
const visitor)
const override {
683 bool FindIntervalVarOnStartMin(Solver*
const s,
684 SequenceVar*
const best_sequence,
685 int*
const best_interval_index) {
686 int best_interval = -1;
689 const int candidate = best_possible_firsts_[
index];
690 IntervalVar*
const interval = best_sequence->Interval(candidate);
691 if (
interval->StartMin() < best_start_min) {
692 best_interval = candidate;
693 best_start_min =
interval->StartMin();
696 if (best_interval == -1) {
699 *best_interval_index = best_interval;
704 bool FindIntervalVarRandomly(Solver*
const s,
705 SequenceVar*
const best_sequence,
706 int*
const best_interval_index) {
707 DCHECK(!best_possible_firsts_.empty());
708 const int index = s->Rand32(best_possible_firsts_.size());
709 *best_interval_index = best_possible_firsts_[
index];
713 bool FindIntervalVar(Solver*
const s, SequenceVar*
const best_sequence,
714 int*
const best_interval_index) {
719 return FindIntervalVarOnStartMin(s, best_sequence, best_interval_index);
721 return FindIntervalVarRandomly(s, best_sequence, best_interval_index);
723 LOG(FATAL) <<
"Unknown strategy " << strategy_;
729 bool FindSequenceVarOnSlack(Solver*
const s,
730 SequenceVar**
const best_sequence) {
733 *best_sequence =
nullptr;
734 best_possible_firsts_.clear();
735 for (
int i = 0; i < sequences_.size(); ++i) {
736 SequenceVar*
const candidate_sequence = sequences_[i];
740 candidate_sequence->ComputeStatistics(&ranked, ¬_ranked, &unperformed);
741 if (not_ranked > 0) {
742 candidate_possible_firsts_.clear();
743 candidate_possible_lasts_.clear();
744 candidate_sequence->ComputePossibleFirstsAndLasts(
745 &candidate_possible_firsts_, &candidate_possible_lasts_);
747 if (candidate_possible_firsts_.empty()) {
751 if (candidate_possible_firsts_.size() == 1 &&
752 candidate_sequence->Interval(candidate_possible_firsts_.back())
753 ->MustBePerformed()) {
754 *best_sequence = candidate_sequence;
755 best_possible_firsts_ = candidate_possible_firsts_;
760 int64_t hmin, hmax, dmin, dmax;
761 candidate_sequence->HorizonRange(&hmin, &hmax);
762 candidate_sequence->DurationRange(&dmin, &dmax);
763 int64_t ahmin, ahmax;
764 candidate_sequence->ActiveHorizonRange(&ahmin, &ahmax);
765 const int64_t current_slack = (hmax - hmin - dmax);
766 if (current_slack < best_slack ||
767 (current_slack == best_slack && ahmin < best_ahmin)) {
768 best_slack = current_slack;
769 *best_sequence = candidate_sequence;
770 best_possible_firsts_ = candidate_possible_firsts_;
775 return *best_sequence !=
nullptr;
778 bool FindSequenceVarRandomly(Solver*
const s,
779 SequenceVar**
const best_sequence) {
780 std::vector<SequenceVar*> all_candidates;
781 std::vector<std::vector<int>> all_possible_firsts;
782 for (
int i = 0; i < sequences_.size(); ++i) {
783 SequenceVar*
const candidate_sequence = sequences_[i];
787 candidate_sequence->ComputeStatistics(&ranked, ¬_ranked, &unperformed);
788 if (not_ranked > 0) {
789 candidate_possible_firsts_.clear();
790 candidate_possible_lasts_.clear();
791 candidate_sequence->ComputePossibleFirstsAndLasts(
792 &candidate_possible_firsts_, &candidate_possible_lasts_);
794 if (candidate_possible_firsts_.empty()) {
798 if (candidate_possible_firsts_.size() == 1 &&
799 candidate_sequence->Interval(candidate_possible_firsts_.back())
800 ->MustBePerformed()) {
801 *best_sequence = candidate_sequence;
802 best_possible_firsts_ = candidate_possible_firsts_;
806 all_candidates.push_back(candidate_sequence);
807 all_possible_firsts.push_back(candidate_possible_firsts_);
810 if (all_candidates.empty()) {
813 const int chosen = s->Rand32(all_candidates.size());
814 *best_sequence = all_candidates[chosen];
815 best_possible_firsts_ = all_possible_firsts[chosen];
819 bool FindSequenceVar(Solver*
const s, SequenceVar**
const best_sequence) {
824 return FindSequenceVarOnSlack(s, best_sequence);
826 return FindSequenceVarRandomly(s, best_sequence);
828 LOG(FATAL) <<
"Unknown strategy " << strategy_;
832 const std::vector<SequenceVar*> sequences_;
834 std::vector<int> best_possible_firsts_;
835 std::vector<int> candidate_possible_firsts_;
836 std::vector<int> candidate_possible_lasts_;
841 int64_t*
const marker) {
842 CHECK(
var !=
nullptr);
843 CHECK(marker !=
nullptr);
844 return RevAlloc(
new ScheduleOrPostpone(
var, est, marker));
848 int64_t*
const marker) {
849 CHECK(
var !=
nullptr);
850 CHECK(marker !=
nullptr);
851 return RevAlloc(
new ScheduleOrExpedite(
var, est, marker));
860 return RevAlloc(
new SetTimesForward(intervals));
862 return RevAlloc(
new SetTimesBackward(intervals));
864 LOG(FATAL) <<
"Unknown strategy " << str;
870 CHECK(sequence !=
nullptr);
875 CHECK(sequence !=
nullptr);
881 return RevAlloc(
new RankFirstIntervalVars(sequences, str));
const std::vector< IntVar * > vars_
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.
T * RevAlloc(T *object)
Registers the given object as being reversible.
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.
Collection of objects used to extend the Constraint Solver library.
std::string JoinDebugStringPtr(const std::vector< T > &v, const std::string &separator)