22#include "absl/container/flat_hash_set.h"
23#include "absl/log/check.h"
24#include "absl/strings/str_format.h"
32int64_t ValueToIndex(int64_t value) {
return value - 1; }
34int64_t IndexToValue(int64_t index) {
return index + 1; }
43 const std::vector<IntervalVar*>& intervals,
44 const std::vector<IntVar*>& nexts,
45 const std::string&
name)
47 intervals_(intervals),
49 previous_(nexts.
size() + 1, -1) {
56 return intervals_[index];
62 int64_t hmin, hmax, dmin, dmax;
69 return absl::StrFormat(
70 "%s(horizon = %d..%d, duration = %d..%d, not ranked = %d, ranked = %d, "
72 name(), hmin, hmax, dmin, dmax, not_ranked, ranked,
81 int64_t*
const dmax)
const {
84 for (
int i = 0; i < intervals_.size(); ++i) {
98 int64_t hor_min = std::numeric_limits<int64_t>::max();
99 int64_t hor_max = std::numeric_limits<int64_t>::min();
100 for (
int i = 0; i < intervals_.size(); ++i) {
104 hor_min = std::min(hor_min, t->
StartMin());
105 hor_max = std::max(hor_max, t->
EndMax());
113 int64_t*
const hmax)
const {
114 absl::flat_hash_set<int> decided;
115 for (
int i = 0; i < intervals_.size(); ++i) {
116 if (intervals_[i]->CannotBePerformed()) {
121 while (nexts_[first]->Bound()) {
122 first = nexts_[first]->Min();
123 if (first < nexts_.size()) {
124 decided.insert(ValueToIndex(first));
129 if (first != nexts_.size()) {
131 int last = nexts_.size();
132 while (previous_[last] != -1) {
133 last = previous_[last];
134 decided.insert(ValueToIndex(last));
137 int64_t hor_min = std::numeric_limits<int64_t>::max();
138 int64_t hor_max = std::numeric_limits<int64_t>::min();
139 for (
int i = 0; i < intervals_.size(); ++i) {
140 if (!decided.contains(i)) {
142 hor_min = std::min(hor_min, t->
StartMin());
143 hor_max = std::max(hor_max, t->
EndMax());
151 int*
const unperformed)
const {
153 for (
int i = 0; i < intervals_.size(); ++i) {
154 if (intervals_[i]->CannotBePerformed()) {
160 while (first < nexts_.size() && nexts_[first]->Bound()) {
161 first = nexts_[first]->Min();
164 if (first != nexts_.size()) {
166 int last = nexts_.size();
167 while (previous_[last] != -1) {
168 last = previous_[last];
174 *not_ranked = intervals_.size() - *ranked - *unperformed;
177int SequenceVar::ComputeForwardFrontier() {
179 while (first != nexts_.size() && nexts_[first]->Bound()) {
180 first = nexts_[first]->Min();
185int SequenceVar::ComputeBackwardFrontier() {
187 int last = nexts_.size();
188 while (previous_[last] != -1) {
189 last = previous_[last];
195 std::vector<int>*
const possible_firsts,
196 std::vector<int>*
const possible_lasts) {
197 possible_firsts->clear();
198 possible_lasts->clear();
199 absl::flat_hash_set<int> to_check;
200 for (
int i = 0; i < intervals_.size(); ++i) {
201 if (intervals_[i]->MayBePerformed()) {
206 while (nexts_[first]->Bound()) {
207 first = nexts_[first]->Min();
208 if (first == nexts_.size()) {
211 to_check.erase(ValueToIndex(first));
214 IntVar*
const forward_var = nexts_[first];
215 std::vector<int> candidates;
216 int64_t smallest_start_max = std::numeric_limits<int64_t>::max();
217 int ssm_support = -1;
218 for (int64_t i = forward_var->
Min(); i <= forward_var->Max(); ++i) {
220 if (i != 0 && i < IndexToValue(intervals_.size()) &&
221 intervals_[ValueToIndex(i)]->MayBePerformed() &&
223 const int candidate = ValueToIndex(i);
224 candidates.push_back(candidate);
225 if (intervals_[candidate]->MustBePerformed()) {
226 if (smallest_start_max > intervals_[candidate]->StartMax()) {
227 smallest_start_max = intervals_[candidate]->StartMax();
228 ssm_support = candidate;
233 for (
int i = 0; i < candidates.size(); ++i) {
234 const int candidate = candidates[i];
235 if (candidate == ssm_support ||
236 intervals_[candidate]->EndMin() <= smallest_start_max) {
237 possible_firsts->push_back(candidate);
242 int last = nexts_.size();
243 while (previous_[last] != -1) {
244 last = previous_[last];
245 to_check.erase(ValueToIndex(last));
249 int64_t biggest_end_min = std::numeric_limits<int64_t>::min();
250 int bem_support = -1;
251 for (
const int candidate : to_check) {
252 if (nexts_[IndexToValue(candidate)]->Contains(last)) {
253 candidates.push_back(candidate);
254 if (intervals_[candidate]->MustBePerformed()) {
255 if (biggest_end_min < intervals_[candidate]->EndMin()) {
256 biggest_end_min = intervals_[candidate]->EndMin();
257 bem_support = candidate;
263 for (
int i = 0; i < candidates.size(); ++i) {
264 const int candidate = candidates[i];
265 if (candidate == bem_support ||
266 intervals_[candidate]->StartMax() >= biggest_end_min) {
267 possible_lasts->push_back(candidate);
273 const std::vector<int>& rank_last,
274 const std::vector<int>& unperformed) {
278 for (
const int value : unperformed) {
279 intervals_[value]->SetPerformed(
false);
283 for (
int i = 0; i < rank_first.size(); ++i) {
284 const int next = 1 + rank_first[i];
285 nexts_[forward]->SetValue(next);
289 int backward = IndexToValue(intervals_.size());
290 for (
int i = 0; i < rank_last.size(); ++i) {
291 const int next = 1 + rank_last[i];
292 nexts_[next]->SetValue(backward);
299 intervals_[index]->SetPerformed(
true);
300 int forward_frontier = 0;
301 while (forward_frontier != nexts_.size() &&
302 nexts_[forward_frontier]->Bound()) {
303 forward_frontier = nexts_[forward_frontier]->Min();
304 if (forward_frontier == IndexToValue(index)) {
308 DCHECK_LT(forward_frontier, nexts_.size());
309 nexts_[forward_frontier]->SetValue(IndexToValue(index));
314 const int forward_frontier = ComputeForwardFrontier();
315 if (forward_frontier < nexts_.size()) {
316 nexts_[forward_frontier]->RemoveValue(IndexToValue(index));
322 intervals_[index]->SetPerformed(
true);
324 int backward_frontier = nexts_.size();
325 while (previous_[backward_frontier] != -1) {
326 backward_frontier = previous_[backward_frontier];
327 if (backward_frontier == IndexToValue(index)) {
331 DCHECK_NE(backward_frontier, 0);
332 nexts_[IndexToValue(index)]->SetValue(backward_frontier);
337 const int backward_frontier = ComputeBackwardFrontier();
338 nexts_[IndexToValue(index)]->RemoveValue(backward_frontier);
341void SequenceVar::UpdatePrevious()
const {
342 for (
int i = 0; i < intervals_.size() + 2; ++i) {
345 for (
int i = 0; i < nexts_.size(); ++i) {
346 if (nexts_[i]->Bound()) {
347 previous_[nexts_[i]->Min()] = i;
353 std::vector<int>*
const rank_last,
354 std::vector<int>*
const unperformed)
const {
355 CHECK(rank_first !=
nullptr);
356 CHECK(rank_last !=
nullptr);
357 CHECK(unperformed !=
nullptr);
360 unperformed->clear();
361 for (
int i = 0; i < intervals_.size(); ++i) {
362 if (intervals_[i]->CannotBePerformed()) {
363 unperformed->push_back(i);
367 while (nexts_[first]->Bound()) {
368 first = nexts_[first]->Min();
369 if (first < nexts_.size()) {
370 rank_first->push_back(ValueToIndex(first));
375 if (first != nexts_.size()) {
377 int last = nexts_.size();
378 while (previous_[last] != -1) {
379 last = previous_[last];
380 rank_last->push_back(ValueToIndex(last));
393class ScheduleOrPostpone :
public Decision {
395 ScheduleOrPostpone(
IntervalVar*
const var, int64_t est, int64_t*
const marker)
396 : var_(var), est_(est), marker_(marker) {}
397 ~ScheduleOrPostpone()
override {}
399 void Apply(Solver*
const s)
override {
400 var_->SetPerformed(
true);
401 if (est_.Value() < var_->StartMin()) {
402 est_.SetValue(s, var_->StartMin());
404 var_->SetStartRange(est_.Value(), est_.Value());
407 void Refute(Solver*
const s)
override {
408 s->SaveAndSetValue(marker_, est_.Value());
411 void Accept(DecisionVisitor*
const visitor)
const override {
412 CHECK(visitor !=
nullptr);
413 visitor->VisitScheduleOrPostpone(var_, est_.Value());
416 std::string DebugString()
const override {
417 return absl::StrFormat(
"ScheduleOrPostpone(%s at %d)", var_->DebugString(),
422 IntervalVar*
const var_;
423 NumericalRev<int64_t> est_;
424 int64_t*
const marker_;
429 explicit SetTimesForward(
const std::vector<IntervalVar*>& vars)
431 markers_(vars.size(), std::numeric_limits<int64_t>::min()) {}
433 ~SetTimesForward()
override {}
435 Decision*
Next(Solver*
const s)
override {
436 int64_t best_est = std::numeric_limits<int64_t>::max();
437 int64_t best_lct = std::numeric_limits<int64_t>::max();
442 for (
int i = 0;
i < vars_.size(); ++
i) {
443 IntervalVar*
const v = vars_[
i];
444 if (v->MayBePerformed() && v->StartMax() != v->StartMin() &&
446 (v->StartMin() < best_est ||
447 (v->StartMin() == best_est && v->EndMax() < best_lct))) {
448 best_est = v->StartMin();
449 best_lct = v->EndMax();
456 UnperformPostponedTaskBefore(std::numeric_limits<int64_t>::max());
459 UnperformPostponedTaskBefore(best_est);
461 new ScheduleOrPostpone(vars_[support], best_est, &markers_[support]));
464 std::string DebugString()
const override {
return "SetTimesForward()"; }
466 void Accept(ModelVisitor*
const visitor)
const override {
474 bool IsPostponed(
int index) {
475 DCHECK(vars_[index]->MayBePerformed());
476 return vars_[index]->StartMin() <= markers_[index];
479 void UnperformPostponedTaskBefore(int64_t date) {
480 for (
int i = 0;
i < vars_.size(); ++
i) {
481 IntervalVar*
const v = vars_[
i];
482 if (v->MayBePerformed() && v->StartMin() != v->StartMax() &&
491 (v->EndMin() <= date || v->StartMax() <= date)) {
492 v->SetPerformed(
false);
497 const std::vector<IntervalVar*> vars_;
498 std::vector<int64_t> markers_;
504class ScheduleOrExpedite :
public Decision {
506 ScheduleOrExpedite(IntervalVar*
const var, int64_t est, int64_t*
const marker)
507 : var_(var), est_(est), marker_(marker) {}
508 ~ScheduleOrExpedite()
override {}
510 void Apply(Solver*
const s)
override {
511 var_->SetPerformed(
true);
512 if (est_.Value() > var_->EndMax()) {
513 est_.SetValue(s, var_->EndMax());
515 var_->SetEndRange(est_.Value(), est_.Value());
518 void Refute(Solver*
const s)
override {
519 s->SaveAndSetValue(marker_, est_.Value() - 1);
522 void Accept(DecisionVisitor*
const visitor)
const override {
523 CHECK(visitor !=
nullptr);
524 visitor->VisitScheduleOrExpedite(var_, est_.Value());
527 std::string DebugString()
const override {
528 return absl::StrFormat(
"ScheduleOrExpedite(%s at %d)", var_->DebugString(),
533 IntervalVar*
const var_;
534 NumericalRev<int64_t> est_;
535 int64_t*
const marker_;
540 explicit SetTimesBackward(
const std::vector<IntervalVar*>& vars)
542 markers_(vars.size(), std::numeric_limits<int64_t>::max()) {}
544 ~SetTimesBackward()
override {}
546 Decision*
Next(Solver*
const s)
override {
547 int64_t best_end = std::numeric_limits<int64_t>::min();
548 int64_t best_start = std::numeric_limits<int64_t>::min();
551 for (
int i = 0;
i < vars_.size(); ++
i) {
552 IntervalVar*
const v = vars_[
i];
553 if (v->MayBePerformed() && v->EndMax() > v->EndMin()) {
554 if (v->EndMax() <= markers_[i] &&
555 (v->EndMax() > best_end ||
556 (v->EndMax() == best_end && v->StartMin() > best_start))) {
557 best_end = v->EndMax();
558 best_start = v->StartMin();
574 return s->RevAlloc(
new ScheduleOrExpedite(
575 vars_[support], vars_[support]->EndMax(), &markers_[support]));
578 std::string DebugString()
const override {
return "SetTimesBackward()"; }
580 void Accept(ModelVisitor*
const visitor)
const override {
588 const std::vector<IntervalVar*> vars_;
589 std::vector<int64_t> markers_;
596 RankFirst(SequenceVar*
const seq,
int index)
597 : sequence_(seq), index_(index) {}
598 ~RankFirst()
override {}
600 void Apply(Solver*
const s)
override { sequence_->RankFirst(index_); }
602 void Refute(Solver*
const s)
override { sequence_->RankNotFirst(index_); }
604 void Accept(DecisionVisitor*
const visitor)
const override {
605 CHECK(visitor !=
nullptr);
606 visitor->VisitRankFirstInterval(sequence_, index_);
609 std::string DebugString()
const override {
610 return absl::StrFormat(
"RankFirst(%s, %d)", sequence_->DebugString(),
615 SequenceVar*
const sequence_;
621 RankLast(SequenceVar*
const seq,
int index) : sequence_(seq), index_(index) {}
622 ~RankLast()
override {}
624 void Apply(Solver*
const s)
override { sequence_->RankLast(index_); }
626 void Refute(Solver*
const s)
override { sequence_->RankNotLast(index_); }
628 void Accept(DecisionVisitor*
const visitor)
const override {
629 CHECK(visitor !=
nullptr);
630 visitor->VisitRankLastInterval(sequence_, index_);
633 std::string DebugString()
const override {
634 return absl::StrFormat(
"RankLast(%s, %d)", sequence_->DebugString(),
639 SequenceVar*
const sequence_;
645 RankFirstIntervalVars(
const std::vector<SequenceVar*>& sequences,
647 : sequences_(sequences), strategy_(str) {}
649 ~RankFirstIntervalVars()
override {}
651 Decision*
Next(Solver*
const s)
override {
652 SequenceVar* best_sequence =
nullptr;
653 best_possible_firsts_.clear();
655 if (FindSequenceVar(s, &best_sequence)) {
657 DCHECK(best_sequence !=
nullptr);
658 if (best_possible_firsts_.size() == 1 &&
659 best_sequence->Interval(best_possible_firsts_.back())
660 ->MustBePerformed()) {
661 best_sequence->RankFirst(best_possible_firsts_.back());
664 int best_interval = -1;
665 if (!FindIntervalVar(s, best_sequence, &best_interval)) {
668 CHECK_NE(-1, best_interval);
669 return s->RevAlloc(
new RankFirst(best_sequence, best_interval));
676 void Accept(ModelVisitor*
const visitor)
const override {
685 bool FindIntervalVarOnStartMin(Solver*
const s,
686 SequenceVar*
const best_sequence,
687 int*
const best_interval_index) {
688 int best_interval = -1;
689 int64_t best_start_min = std::numeric_limits<int64_t>::max();
690 for (
int index = 0; index < best_possible_firsts_.size(); ++index) {
691 const int candidate = best_possible_firsts_[index];
692 IntervalVar*
const interval = best_sequence->Interval(candidate);
693 if (interval->StartMin() < best_start_min) {
694 best_interval = candidate;
695 best_start_min = interval->StartMin();
698 if (best_interval == -1) {
701 *best_interval_index = best_interval;
706 bool FindIntervalVarRandomly(Solver*
const s,
707 SequenceVar*
const best_sequence,
708 int*
const best_interval_index) {
709 DCHECK(!best_possible_firsts_.empty());
710 const int index = s->Rand32(best_possible_firsts_.size());
711 *best_interval_index = best_possible_firsts_[index];
715 bool FindIntervalVar(Solver*
const s, SequenceVar*
const best_sequence,
716 int*
const best_interval_index) {
721 return FindIntervalVarOnStartMin(s, best_sequence, best_interval_index);
723 return FindIntervalVarRandomly(s, best_sequence, best_interval_index);
725 LOG(FATAL) <<
"Unknown strategy " << strategy_;
731 bool FindSequenceVarOnSlack(Solver*
const s,
732 SequenceVar**
const best_sequence) {
733 int64_t best_slack = std::numeric_limits<int64_t>::max();
734 int64_t best_ahmin = std::numeric_limits<int64_t>::max();
735 *best_sequence =
nullptr;
736 best_possible_firsts_.clear();
737 for (
int i = 0;
i < sequences_.size(); ++
i) {
738 SequenceVar*
const candidate_sequence = sequences_[
i];
742 candidate_sequence->ComputeStatistics(&ranked, ¬_ranked, &unperformed);
743 if (not_ranked > 0) {
744 candidate_possible_firsts_.clear();
745 candidate_possible_lasts_.clear();
746 candidate_sequence->ComputePossibleFirstsAndLasts(
747 &candidate_possible_firsts_, &candidate_possible_lasts_);
749 if (candidate_possible_firsts_.empty()) {
753 if (candidate_possible_firsts_.size() == 1 &&
754 candidate_sequence->Interval(candidate_possible_firsts_.back())
755 ->MustBePerformed()) {
756 *best_sequence = candidate_sequence;
757 best_possible_firsts_ = candidate_possible_firsts_;
762 int64_t hmin, hmax, dmin, dmax;
763 candidate_sequence->HorizonRange(&hmin, &hmax);
764 candidate_sequence->DurationRange(&dmin, &dmax);
765 int64_t ahmin, ahmax;
766 candidate_sequence->ActiveHorizonRange(&ahmin, &ahmax);
767 const int64_t current_slack = (hmax - hmin - dmax);
768 if (current_slack < best_slack ||
769 (current_slack == best_slack && ahmin < best_ahmin)) {
770 best_slack = current_slack;
771 *best_sequence = candidate_sequence;
772 best_possible_firsts_ = candidate_possible_firsts_;
777 return *best_sequence !=
nullptr;
780 bool FindSequenceVarRandomly(Solver*
const s,
781 SequenceVar**
const best_sequence) {
782 std::vector<SequenceVar*> all_candidates;
783 std::vector<std::vector<int>> all_possible_firsts;
784 for (
int i = 0;
i < sequences_.size(); ++
i) {
785 SequenceVar*
const candidate_sequence = sequences_[
i];
789 candidate_sequence->ComputeStatistics(&ranked, ¬_ranked, &unperformed);
790 if (not_ranked > 0) {
791 candidate_possible_firsts_.clear();
792 candidate_possible_lasts_.clear();
793 candidate_sequence->ComputePossibleFirstsAndLasts(
794 &candidate_possible_firsts_, &candidate_possible_lasts_);
796 if (candidate_possible_firsts_.empty()) {
800 if (candidate_possible_firsts_.size() == 1 &&
801 candidate_sequence->Interval(candidate_possible_firsts_.back())
802 ->MustBePerformed()) {
803 *best_sequence = candidate_sequence;
804 best_possible_firsts_ = candidate_possible_firsts_;
808 all_candidates.push_back(candidate_sequence);
809 all_possible_firsts.push_back(candidate_possible_firsts_);
812 if (all_candidates.empty()) {
815 const int chosen = s->Rand32(all_candidates.size());
816 *best_sequence = all_candidates[chosen];
817 best_possible_firsts_ = std::move(all_possible_firsts[chosen]);
821 bool FindSequenceVar(Solver*
const s, SequenceVar**
const best_sequence) {
826 return FindSequenceVarOnSlack(s, best_sequence);
828 return FindSequenceVarRandomly(s, best_sequence);
830 LOG(FATAL) <<
"Unknown strategy " << strategy_;
834 const std::vector<SequenceVar*> sequences_;
836 std::vector<int> best_possible_firsts_;
837 std::vector<int> candidate_possible_firsts_;
838 std::vector<int> candidate_possible_lasts_;
843 int64_t*
const marker) {
844 CHECK(var !=
nullptr);
845 CHECK(marker !=
nullptr);
846 return RevAlloc(
new ScheduleOrPostpone(var, est, marker));
850 int64_t*
const marker) {
851 CHECK(var !=
nullptr);
852 CHECK(marker !=
nullptr);
853 return RevAlloc(
new ScheduleOrExpedite(var, est, marker));
862 return RevAlloc(
new SetTimesForward(intervals));
864 return RevAlloc(
new SetTimesBackward(intervals));
866 LOG(FATAL) <<
"Unknown strategy " << str;
872 CHECK(sequence !=
nullptr);
873 return RevAlloc(
new RankFirst(sequence, index));
877 CHECK(sequence !=
nullptr);
878 return RevAlloc(
new RankLast(sequence, index));
883 return RevAlloc(
new RankFirstIntervalVars(sequences, str));
virtual int64_t Min() const =0
virtual bool Contains(int64_t v) const =0
virtual int64_t DurationMax() const =0
virtual int64_t EndMax() const =0
virtual bool MayBePerformed() const =0
virtual int64_t DurationMin() const =0
These methods query, set, and watch the duration of the interval var.
virtual int64_t StartMin() const =0
virtual bool MustBePerformed() const =0
virtual void VisitSequenceVariable(const SequenceVar *variable)
static const char kSequencesArgument[]
static const char kVariableGroupExtension[]
static const char kIntervalsArgument[]
virtual std::string name() const
Object naming.
void set_name(absl::string_view name)
PropagationBaseObject(Solver *const s)
virtual void RankSequence(SequenceVar *var, const std::vector< int > &rank_first, const std::vector< int > &rank_last, const std::vector< int > &unperformed)=0
virtual void RankNotFirst(SequenceVar *var, int index)=0
virtual void RankNotLast(SequenceVar *var, int index)=0
virtual void RankFirst(SequenceVar *var, int index)=0
SequenceVar modifiers.
virtual void RankLast(SequenceVar *var, int index)=0
void RankNotFirst(int index)
void HorizonRange(int64_t *hmin, int64_t *hmax) const
virtual void Accept(ModelVisitor *visitor) const
Accepts the given visitor.
void RankNotLast(int index)
void RankSequence(const std::vector< int > &rank_first, const std::vector< int > &rank_last, const std::vector< int > &unperformed)
IntervalVar * Interval(int index) const
Returns the index_th interval of the sequence.
void ComputePossibleFirstsAndLasts(std::vector< int > *possible_firsts, std::vector< int > *possible_lasts)
int64_t size() const
Returns the number of interval vars in the sequence.
IntVar * Next(int index) const
Returns the next of the index_th interval of the sequence.
SequenceVar(Solver *s, const std::vector< IntervalVar * > &intervals, const std::vector< IntVar * > &nexts, const std::string &name)
--— SequenceVar --—
void RankFirst(int index)
void ComputeStatistics(int *ranked, int *not_ranked, int *unperformed) const
Compute statistics on the sequence.
void FillSequence(std::vector< int > *rank_first, std::vector< int > *rank_last, std::vector< int > *unperformed) const
std::string DebugString() const override
void ActiveHorizonRange(int64_t *hmin, int64_t *hmax) const
void DurationRange(int64_t *dmin, int64_t *dmax) const
For the time being, Solver is neither MT_SAFE nor MT_HOT.
Decision * MakeRankLastInterval(SequenceVar *sequence, int index)
DecisionBuilder * MakePhase(const std::vector< IntVar * > &vars, IntVarStrategy var_str, IntValueStrategy val_str)
Decision * MakeScheduleOrExpedite(IntervalVar *var, int64_t est, int64_t *marker)
SequenceStrategy
Used for scheduling. Not yet implemented.
@ CHOOSE_RANDOM_RANK_FORWARD
@ CHOOSE_MIN_SLACK_RANK_FORWARD
Decision * MakeRankFirstInterval(SequenceVar *sequence, int index)
Decision * MakeScheduleOrPostpone(IntervalVar *var, int64_t est, int64_t *marker)
@ INTERVAL_SET_TIMES_FORWARD
@ INTERVAL_DEFAULT
The default is INTERVAL_SET_TIMES_FORWARD.
@ INTERVAL_SET_TIMES_BACKWARD
@ INTERVAL_SIMPLE
The simple is INTERVAL_SET_TIMES_FORWARD.
PropagationMonitor * GetPropagationMonitor() const
Returns the propagation monitor.
In SWIG mode, we don't want anything besides these top-level includes.
std::string JoinDebugStringPtr(const std::vector< T > &v, absl::string_view separator)
Join v[i]->DebugString().