set times backward in scheduling; speedup in local search
This commit is contained in:
@@ -2575,6 +2575,8 @@ void DecisionVisitor::VisitSplitVariableDomain(IntVar* const var, int64 value,
|
||||
void DecisionVisitor::VisitUnknownDecision() {}
|
||||
void DecisionVisitor::VisitScheduleOrPostpone(IntervalVar* const var,
|
||||
int64 est) {}
|
||||
void DecisionVisitor::VisitScheduleOrExpedite(IntervalVar* const var,
|
||||
int64 est) {}
|
||||
void DecisionVisitor::VisitRankFirstInterval(SequenceVar* const sequence,
|
||||
int index) {}
|
||||
|
||||
|
||||
@@ -520,11 +520,19 @@ class Solver {
|
||||
CHOOSE_RANDOM_RANK_FORWARD,
|
||||
};
|
||||
|
||||
// Used for scheduling. Not yet implemented.
|
||||
// This enum describes the straregy used to select the next interval variable
|
||||
// and its value to be fixed.
|
||||
enum IntervalStrategy {
|
||||
// The default is INTERVAL_SET_TIMES_FORWARD.
|
||||
INTERVAL_DEFAULT,
|
||||
// The simple is INTERVAL_SET_TIMES_FORWARD.
|
||||
INTERVAL_SIMPLE,
|
||||
INTERVAL_SET_TIMES_FORWARD
|
||||
// Selects the variable with the lowest starting time of all variables,
|
||||
// and fixes its starting time to this lowest value.
|
||||
INTERVAL_SET_TIMES_FORWARD,
|
||||
// Selects the variable with the highest ending time of all variables,
|
||||
// and fixes the ending time to this highest values.
|
||||
INTERVAL_SET_TIMES_BACKWARD
|
||||
};
|
||||
|
||||
// This enum is used in Solver::MakeOperator to specify the neighborhood to
|
||||
@@ -2409,6 +2417,14 @@ class Solver {
|
||||
Decision* MakeScheduleOrPostpone(IntervalVar* const var, int64 est,
|
||||
int64* const marker);
|
||||
|
||||
// Returns a decision that tries to schedule a task at a given time.
|
||||
// On the Apply branch, it will set that interval var as performed and set
|
||||
// its end to 'est'. On the Refute branch, it will just update the
|
||||
// 'marker' to 'est' - 1. This decision is used in the
|
||||
// INTERVAL_SET_TIMES_BACKWARD strategy.
|
||||
Decision* MakeScheduleOrExpedite(IntervalVar* const var, int64 est,
|
||||
int64* const marker);
|
||||
|
||||
// Returns a decision that tries to rank first the ith interval var
|
||||
// in the sequence variable.
|
||||
Decision* MakeRankFirstInterval(SequenceVar* const sequence, int index);
|
||||
@@ -3138,6 +3154,7 @@ class DecisionVisitor : public BaseObject {
|
||||
virtual void VisitSplitVariableDomain(IntVar* const var, int64 value,
|
||||
bool start_with_lower_half);
|
||||
virtual void VisitScheduleOrPostpone(IntervalVar* const var, int64 est);
|
||||
virtual void VisitScheduleOrExpedite(IntervalVar* const var, int64 est);
|
||||
virtual void VisitRankFirstInterval(SequenceVar* const sequence, int index);
|
||||
virtual void VisitRankLastInterval(SequenceVar* const sequence, int index);
|
||||
virtual void VisitUnknownDecision();
|
||||
@@ -4601,16 +4618,30 @@ class AssignmentContainer {
|
||||
return Find(var, &index);
|
||||
}
|
||||
E* MutableElement(const V* const var) {
|
||||
E* const element = MutableElementOrNull(var);
|
||||
DCHECK(element != nullptr) << "Unknown variable " << var->DebugString()
|
||||
<< " in solution";
|
||||
return element;
|
||||
}
|
||||
E* MutableElementOrNull(const V* const var) {
|
||||
int index = -1;
|
||||
const bool found = Find(var, &index);
|
||||
CHECK(found) << "Unknown variable " << var->DebugString() << " in solution";
|
||||
return MutableElement(index);
|
||||
if (Find(var, &index)) {
|
||||
return MutableElement(index);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
const E& Element(const V* const var) const {
|
||||
const E* const element = ElementPtrOrNull(var);
|
||||
DCHECK(element != nullptr) << "Unknown variable " << var->DebugString()
|
||||
<< " in solution";
|
||||
return *element;
|
||||
}
|
||||
const E* ElementPtrOrNull(const V* const var) const {
|
||||
int index = -1;
|
||||
const bool found = Find(var, &index);
|
||||
CHECK(found) << "Unknown variable " << var->DebugString() << " in solution";
|
||||
return Element(index);
|
||||
if (Find(var, &index)) {
|
||||
return &Element(index);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
const std::vector<E>& elements() const { return elements_; }
|
||||
E* MutableElement(int index) { return &elements_[index]; }
|
||||
@@ -4665,9 +4696,23 @@ class AssignmentContainer {
|
||||
}
|
||||
}
|
||||
bool Find(const V* const var, int* index) const {
|
||||
EnsureMapIsUpToDate();
|
||||
DCHECK_EQ(elements_map_.size(), elements_.size());
|
||||
return FindCopy(elements_map_, var, index);
|
||||
// This threshold was determined from microbenchmarks on Nehalem platform.
|
||||
const size_t kMaxSizeForLinearAccess = 11;
|
||||
if (Size() <= kMaxSizeForLinearAccess) {
|
||||
// Look for 'var' in the container by performing a linear search, avoiding
|
||||
// the access to (and creation of) the elements hash table.
|
||||
for (int i = 0; i < elements_.size(); ++i) {
|
||||
if (var == elements_[i].Var()) {
|
||||
*index = i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
EnsureMapIsUpToDate();
|
||||
DCHECK_EQ(elements_map_.size(), elements_.size());
|
||||
return FindCopy(elements_map_, var, index);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<E> elements_;
|
||||
|
||||
@@ -146,7 +146,7 @@ void GreaterEqExprCst::Post() {
|
||||
demon_ = solver()->MakeConstraintInitialPropagateCallback(this);
|
||||
expr_->WhenRange(demon_);
|
||||
} else {
|
||||
// Let's clean the demon in case the constraints is posted during search.
|
||||
// Let's clean the demon in case the constraint is posted during search.
|
||||
demon_ = nullptr;
|
||||
}
|
||||
}
|
||||
@@ -220,7 +220,7 @@ void LessEqExprCst::Post() {
|
||||
demon_ = solver()->MakeConstraintInitialPropagateCallback(this);
|
||||
expr_->WhenRange(demon_);
|
||||
} else {
|
||||
// Let's clean the demon in case the constraints is posted during search.
|
||||
// Let's clean the demon in case the constraint is posted during search.
|
||||
demon_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -382,7 +382,8 @@ class RoutingModel {
|
||||
typedef _RoutingModel_DisjunctionIndex DisjunctionIndex;
|
||||
typedef ResultCallback1<int64, int64> VehicleEvaluator;
|
||||
typedef ResultCallback2<int64, NodeIndex, NodeIndex> NodeEvaluator2;
|
||||
typedef std::vector<std::pair<int, int> > NodePairs;
|
||||
typedef std::pair<int, int> NodePair;
|
||||
typedef std::vector<NodePair> NodePairs;
|
||||
|
||||
struct CostClass {
|
||||
// arc_cost_evaluator->Run(from, to) is the transit cost of arc
|
||||
@@ -1485,11 +1486,19 @@ class CheapestInsertionFilteredDecisionBuilder
|
||||
virtual ~CheapestInsertionFilteredDecisionBuilder() {}
|
||||
|
||||
protected:
|
||||
typedef std::pair<int64, int64> ValuedPosition;
|
||||
// Inserts 'node' just after 'predecessor', and just before 'successor',
|
||||
// resulting in the following subsequence: predecessor -> node -> successor.
|
||||
// If 'node' is part of a disjunction, other nodes of the disjunction are made
|
||||
// unperformed.
|
||||
void InsertBetween(int64 node, int64 predecessor, int64 successor);
|
||||
// Helper method to the ComputeEvaluatorSortedPositions* methods. Finds all
|
||||
// possible insertion positions of node 'node_to_insert' in the partial route
|
||||
// starting at node 'start' and adds them to 'valued_position', a list of
|
||||
// unsorted pairs of (cost, position to insert the node).
|
||||
void AppendEvaluatedPositionsAfter(
|
||||
int64 node_to_insert, int64 start, int64 next_after_start,
|
||||
std::vector<ValuedPosition>* valued_positions);
|
||||
|
||||
std::unique_ptr<ResultCallback2<int64, int64, int64> > evaluator_;
|
||||
};
|
||||
@@ -1509,13 +1518,18 @@ class GlobalCheapestInsertionFilteredDecisionBuilder
|
||||
virtual bool BuildSolution();
|
||||
|
||||
private:
|
||||
// Computes the possible insertions for all non-inserted nodes and sorts them
|
||||
// according to the current cost evaluator.
|
||||
// Each std::pair<int64, int64> of the output represents an already performed node,
|
||||
typedef std::pair<int64, int64> InsertionPosition;
|
||||
// Computes the possible insertion positions for all non-inserted nodes and
|
||||
// sorts them according to the current cost evaluator.
|
||||
// Each InsertionPosition of the output represents an already performed node,
|
||||
// followed by a non-inserted node that should be set as the "Next" of the
|
||||
// former.
|
||||
void ComputeEvaluatorSortedInsertions(
|
||||
std::vector<std::pair<int64, int64> >* sorted_insertions);
|
||||
void ComputeEvaluatorSortedPositions(
|
||||
std::vector<InsertionPosition>* sorted_positions);
|
||||
// Same as above but limited to pickup and delivery pairs. Each pair of
|
||||
// InsertionPosition applies respectively to a pickup and its delivery.
|
||||
void ComputeEvaluatorSortedPositionPairs(
|
||||
std::vector<std::pair<InsertionPosition, InsertionPosition> >* sorted_positions);
|
||||
};
|
||||
|
||||
// Filtered-base decision builder which builds a solution by inserting
|
||||
@@ -1547,11 +1561,6 @@ class LocalCheapestInsertionFilteredDecisionBuilder
|
||||
void ComputeEvaluatorSortedPositionsOnRouteAfter(
|
||||
int64 node, int64 start, int64 next_after_start,
|
||||
std::vector<int64>* sorted_positions);
|
||||
// Helper method to the ComputeEvaluatorSortedPositions* methods; the output
|
||||
// is a list of unsorted pairs of (cost, position to insert the node).
|
||||
void AppendEvaluatedPositionsAfter(
|
||||
int64 node_to_insert, int64 start, int64 next_after_start,
|
||||
std::vector<std::pair<int64, int64> >* valued_positions);
|
||||
};
|
||||
|
||||
// Filtered-base decision builder based on the addition heuristic, extending
|
||||
|
||||
@@ -277,10 +277,10 @@ int64 BasePathFilter::GetNext(const Assignment::IntContainer& container,
|
||||
int64 node) const {
|
||||
const IntVar* const next_var = Var(node);
|
||||
int64 next = IsVarSynced(node) ? Value(node) : kUnassigned;
|
||||
if (container.Contains(next_var)) {
|
||||
const IntVarElement& element = container.Element(next_var);
|
||||
if (element.Bound()) {
|
||||
next = element.Value();
|
||||
const IntVarElement* const element = container.ElementPtrOrNull(next_var);
|
||||
if (element != nullptr) {
|
||||
if (element->Bound()) {
|
||||
next = element->Value();
|
||||
} else {
|
||||
return kUnassigned;
|
||||
}
|
||||
@@ -945,6 +945,24 @@ void CheapestInsertionFilteredDecisionBuilder::InsertBetween(int64 node,
|
||||
MakeDisjunctionNodesUnperformed(node);
|
||||
}
|
||||
|
||||
void
|
||||
CheapestInsertionFilteredDecisionBuilder::AppendEvaluatedPositionsAfter(
|
||||
int64 node_to_insert, int64 start, int64 next_after_start,
|
||||
std::vector<ValuedPosition>* valued_positions) {
|
||||
CHECK(valued_positions != nullptr);
|
||||
int64 insert_after = start;
|
||||
while (!model()->IsEnd(insert_after)) {
|
||||
const int64 insert_before =
|
||||
(insert_after == start) ? next_after_start : Value(insert_after);
|
||||
valued_positions->push_back(
|
||||
std::make_pair(evaluator_->Run(insert_after, node_to_insert) +
|
||||
evaluator_->Run(node_to_insert, insert_before) -
|
||||
evaluator_->Run(insert_after, insert_before),
|
||||
insert_after));
|
||||
insert_after = insert_before;
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
template <class T>
|
||||
void SortAndExtractPairSeconds(std::vector<std::pair<int64, T>>* pairs,
|
||||
@@ -971,12 +989,38 @@ bool GlobalCheapestInsertionFilteredDecisionBuilder::BuildSolution() {
|
||||
if (!InitializeRoutes()) {
|
||||
return false;
|
||||
}
|
||||
// Node insertions currently being considered.
|
||||
std::vector<std::pair<int64, int64>> insertions;
|
||||
// Node pair insertions currently being considered.
|
||||
std::vector<std::pair<std::pair<int64, int64>, std::pair<int64, int64>>> insertion_pairs;
|
||||
bool found = true;
|
||||
while (found) {
|
||||
found = false;
|
||||
ComputeEvaluatorSortedInsertions(&insertions);
|
||||
ComputeEvaluatorSortedPositionPairs(&insertion_pairs);
|
||||
for (const std::pair<std::pair<int64, int64>, std::pair<int64, int64>>& insertion_pair :
|
||||
insertion_pairs) {
|
||||
const int64 pickup = insertion_pair.first.second;
|
||||
const int64 pickup_insertion = insertion_pair.first.first;
|
||||
const int64 pickup_insertion_next = Value(pickup_insertion);
|
||||
InsertBetween(pickup, pickup_insertion, pickup_insertion_next);
|
||||
const int64 delivery = insertion_pair.second.second;
|
||||
const int64 delivery_insertion = insertion_pair.second.first;
|
||||
DCHECK_NE(delivery_insertion, pickup_insertion);
|
||||
const int64 delivery_insertion_next =
|
||||
(delivery_insertion == pickup) ? pickup_insertion_next
|
||||
: Value(delivery_insertion);
|
||||
InsertBetween(delivery, delivery_insertion, delivery_insertion_next);
|
||||
if (Commit()) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Node insertions currently being considered.
|
||||
std::vector<std::pair<int64, int64>> insertions;
|
||||
// Iterating on remaining nodes.
|
||||
found = true;
|
||||
while (found) {
|
||||
found = false;
|
||||
ComputeEvaluatorSortedPositions(&insertions);
|
||||
for (const std::pair<int64, int64> insertion : insertions) {
|
||||
InsertBetween(insertion.second, insertion.first, Value(insertion.first));
|
||||
if (Commit()) {
|
||||
@@ -990,30 +1034,71 @@ bool GlobalCheapestInsertionFilteredDecisionBuilder::BuildSolution() {
|
||||
}
|
||||
|
||||
void GlobalCheapestInsertionFilteredDecisionBuilder::
|
||||
ComputeEvaluatorSortedInsertions(
|
||||
std::vector<std::pair<int64, int64>>* sorted_insertions) {
|
||||
CHECK(sorted_insertions != nullptr);
|
||||
sorted_insertions->clear();
|
||||
std::vector<std::pair<int64, std::pair<int64, int64>>> valued_insertions;
|
||||
ComputeEvaluatorSortedPositions(
|
||||
std::vector<InsertionPosition>* sorted_positions) {
|
||||
CHECK(sorted_positions != nullptr);
|
||||
sorted_positions->clear();
|
||||
std::vector<std::pair<int64, InsertionPosition>> valued_insertions;
|
||||
for (int node = 0; node < model()->Size(); ++node) {
|
||||
if (Contains(node)) {
|
||||
continue;
|
||||
}
|
||||
std::vector<ValuedPosition> valued_positions;
|
||||
for (int vehicle = 0; vehicle < model()->vehicles(); ++vehicle) {
|
||||
int64 insert_after = model()->Start(vehicle);
|
||||
while (!model()->IsEnd(insert_after)) {
|
||||
const int64 insert_before = Value(insert_after);
|
||||
valued_insertions.push_back(
|
||||
std::make_pair(evaluator_->Run(insert_after, node) +
|
||||
evaluator_->Run(node, insert_before),
|
||||
std::make_pair(insert_after, node)));
|
||||
insert_after = insert_before;
|
||||
const int64 start = model()->Start(vehicle);
|
||||
AppendEvaluatedPositionsAfter(node, start, Value(start),
|
||||
&valued_positions);
|
||||
}
|
||||
for (const std::pair<int64, int64>& valued_position : valued_positions) {
|
||||
valued_insertions.push_back(std::make_pair(valued_position.first,
|
||||
std::make_pair(valued_position.second,
|
||||
node)));
|
||||
}
|
||||
}
|
||||
SortAndExtractPairSeconds(&valued_insertions, sorted_positions);
|
||||
}
|
||||
|
||||
void GlobalCheapestInsertionFilteredDecisionBuilder::
|
||||
ComputeEvaluatorSortedPositionPairs(
|
||||
std::vector<std::pair<InsertionPosition, InsertionPosition>>* sorted_positions) {
|
||||
CHECK(sorted_positions != nullptr);
|
||||
sorted_positions->clear();
|
||||
std::vector<std::pair<int64, std::pair<InsertionPosition, InsertionPosition>>>
|
||||
valued_positions;
|
||||
for (const RoutingModel::NodePair node_pair :
|
||||
model()->GetPickupAndDeliveryPairs()) {
|
||||
const int64 pickup = node_pair.first;
|
||||
const int64 delivery = node_pair.second;
|
||||
if (Contains(pickup) || Contains(delivery)) {
|
||||
continue;
|
||||
}
|
||||
for (int vehicle = 0; vehicle < model()->vehicles(); ++vehicle) {
|
||||
std::vector<ValuedPosition> valued_pickup_positions;
|
||||
const int64 start = model()->Start(vehicle);
|
||||
AppendEvaluatedPositionsAfter(pickup, start, Value(start),
|
||||
&valued_pickup_positions);
|
||||
for (const ValuedPosition& valued_pickup_position :
|
||||
valued_pickup_positions) {
|
||||
const int64 pickup_position = valued_pickup_position.second;
|
||||
CHECK(!model()->IsEnd(pickup_position));
|
||||
std::vector<ValuedPosition> valued_delivery_positions;
|
||||
AppendEvaluatedPositionsAfter(delivery, pickup,
|
||||
Value(pickup_position),
|
||||
&valued_delivery_positions);
|
||||
for (const ValuedPosition& valued_delivery_position :
|
||||
valued_delivery_positions) {
|
||||
valued_positions.push_back(std::make_pair(
|
||||
valued_pickup_position.first + valued_delivery_position.first,
|
||||
std::make_pair(std::make_pair(pickup_position, pickup),
|
||||
std::make_pair(valued_delivery_position.second, delivery))));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
SortAndExtractPairSeconds(&valued_insertions, sorted_insertions);
|
||||
SortAndExtractPairSeconds(&valued_positions, sorted_positions);
|
||||
}
|
||||
|
||||
|
||||
// LocalCheapestInsertionFilteredDecisionBuilder
|
||||
|
||||
LocalCheapestInsertionFilteredDecisionBuilder::
|
||||
@@ -1122,23 +1207,6 @@ void LocalCheapestInsertionFilteredDecisionBuilder::
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
LocalCheapestInsertionFilteredDecisionBuilder::AppendEvaluatedPositionsAfter(
|
||||
int64 node_to_insert, int64 start, int64 next_after_start,
|
||||
std::vector<std::pair<int64, int64>>* valued_positions) {
|
||||
CHECK(valued_positions != nullptr);
|
||||
int64 insert_after = start;
|
||||
while (!model()->IsEnd(insert_after)) {
|
||||
const int64 insert_before =
|
||||
(insert_after == start) ? next_after_start : Value(insert_after);
|
||||
valued_positions->push_back(
|
||||
std::make_pair(evaluator_->Run(insert_after, node_to_insert) +
|
||||
evaluator_->Run(node_to_insert, insert_before),
|
||||
insert_after));
|
||||
insert_after = insert_before;
|
||||
}
|
||||
}
|
||||
|
||||
// CheapestAdditionFilteredDecisionBuilder
|
||||
|
||||
CheapestAdditionFilteredDecisionBuilder::
|
||||
|
||||
@@ -380,6 +380,9 @@ void SequenceVar::FillSequence(std::vector<int>* const rank_first,
|
||||
// TODO(user) : treat optional intervals
|
||||
// TODO(user) : Call DecisionVisitor and pass name of variable
|
||||
namespace {
|
||||
//
|
||||
// Forward scheduling.
|
||||
//
|
||||
class ScheduleOrPostpone : public Decision {
|
||||
public:
|
||||
ScheduleOrPostpone(IntervalVar* const var, int64 est, int64* const marker)
|
||||
@@ -467,6 +470,96 @@ class SetTimesForward : public DecisionBuilder {
|
||||
std::vector<int64> markers_;
|
||||
};
|
||||
|
||||
//
|
||||
// Backward scheduling.
|
||||
//
|
||||
class ScheduleOrExpedite : public Decision {
|
||||
public:
|
||||
ScheduleOrExpedite(IntervalVar* const var, int64 est, int64* const marker)
|
||||
: var_(var), est_(est), marker_(marker) {}
|
||||
virtual ~ScheduleOrExpedite() {}
|
||||
|
||||
virtual void Apply(Solver* const s) {
|
||||
var_->SetPerformed(true);
|
||||
if (est_.Value() > var_->EndMax()) {
|
||||
est_.SetValue(s, var_->EndMax());
|
||||
}
|
||||
var_->SetEndRange(est_.Value(), est_.Value());
|
||||
}
|
||||
|
||||
virtual void Refute(Solver* const s) {
|
||||
s->SaveAndSetValue(marker_, est_.Value() - 1);
|
||||
}
|
||||
|
||||
virtual void Accept(DecisionVisitor* const visitor) const {
|
||||
CHECK(visitor != nullptr);
|
||||
visitor->VisitScheduleOrExpedite(var_, est_.Value());
|
||||
}
|
||||
|
||||
virtual std::string DebugString() const {
|
||||
return StringPrintf("ScheduleOrExpedite(%s at %" GG_LL_FORMAT "d)",
|
||||
var_->DebugString().c_str(), est_.Value());
|
||||
}
|
||||
|
||||
private:
|
||||
IntervalVar* const var_;
|
||||
NumericalRev<int64> est_;
|
||||
int64* const marker_;
|
||||
};
|
||||
|
||||
class SetTimesBackward : public DecisionBuilder {
|
||||
public:
|
||||
explicit SetTimesBackward(const std::vector<IntervalVar*>& vars)
|
||||
: vars_(vars), markers_(vars.size(), kint64max) {}
|
||||
|
||||
virtual ~SetTimesBackward() {}
|
||||
|
||||
virtual Decision* Next(Solver* const s) {
|
||||
int64 best_end = kint64min;
|
||||
int64 best_start = kint64min;
|
||||
int support = -1;
|
||||
int refuted = 0;
|
||||
for (int i = 0; i < vars_.size(); ++i) {
|
||||
IntervalVar* const v = vars_[i];
|
||||
if (v->MayBePerformed() && v->EndMax() > v->EndMin()) {
|
||||
if (v->EndMax() <= markers_[i] &&
|
||||
(v->EndMax() > best_end ||
|
||||
(v->EndMax() == best_end && v->StartMin() > best_start))) {
|
||||
best_end = v->EndMax();
|
||||
best_start = v->StartMin();
|
||||
support = i;
|
||||
} else {
|
||||
refuted++;
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO(user) : remove this crude quadratic loop with
|
||||
// reversibles range reduction.
|
||||
if (support == -1) {
|
||||
if (refuted == 0) {
|
||||
return nullptr;
|
||||
} else {
|
||||
s->Fail();
|
||||
}
|
||||
}
|
||||
return s->RevAlloc(new ScheduleOrExpedite(
|
||||
vars_[support], vars_[support]->EndMax(), &markers_[support]));
|
||||
}
|
||||
|
||||
virtual std::string DebugString() const { return "SetTimesBackward()"; }
|
||||
|
||||
virtual void Accept(ModelVisitor* const visitor) const {
|
||||
visitor->BeginVisitExtension(ModelVisitor::kVariableGroupExtension);
|
||||
visitor->VisitIntervalArrayArgument(ModelVisitor::kIntervalsArgument,
|
||||
vars_);
|
||||
visitor->EndVisitExtension(ModelVisitor::kVariableGroupExtension);
|
||||
}
|
||||
|
||||
private:
|
||||
const std::vector<IntervalVar*> vars_;
|
||||
std::vector<int64> markers_;
|
||||
};
|
||||
|
||||
// ----- Decisions and DecisionBuilders on sequences -----
|
||||
|
||||
class RankFirst : public Decision {
|
||||
@@ -724,9 +817,25 @@ Decision* Solver::MakeScheduleOrPostpone(IntervalVar* const var, int64 est,
|
||||
return RevAlloc(new ScheduleOrPostpone(var, est, marker));
|
||||
}
|
||||
|
||||
Decision* Solver::MakeScheduleOrExpedite(IntervalVar* const var, int64 est,
|
||||
int64* const marker) {
|
||||
CHECK(var != nullptr);
|
||||
CHECK(marker != nullptr);
|
||||
return RevAlloc(new ScheduleOrExpedite(var, est, marker));
|
||||
}
|
||||
|
||||
DecisionBuilder* Solver::MakePhase(const std::vector<IntervalVar*>& intervals,
|
||||
IntervalStrategy str) {
|
||||
return RevAlloc(new SetTimesForward(intervals));
|
||||
switch (str) {
|
||||
case Solver::INTERVAL_DEFAULT:
|
||||
case Solver::INTERVAL_SIMPLE:
|
||||
case Solver::INTERVAL_SET_TIMES_FORWARD:
|
||||
return RevAlloc(new SetTimesForward(intervals));
|
||||
case Solver::INTERVAL_SET_TIMES_BACKWARD:
|
||||
return RevAlloc(new SetTimesBackward(intervals));
|
||||
default:
|
||||
LOG(FATAL) << "Unknown strategy " << str;
|
||||
}
|
||||
}
|
||||
|
||||
Decision* Solver::MakeRankFirstInterval(SequenceVar* const sequence,
|
||||
|
||||
Reference in New Issue
Block a user