optimize diffn a little more

This commit is contained in:
Laurent Perron
2019-03-28 16:25:54 +01:00
parent a5d2dc0f1a
commit 92b6096403
8 changed files with 211 additions and 199 deletions

View File

@@ -113,6 +113,7 @@
},
"[python]": {
"editor.tabSize": 4,
},
},
"java.configuration.updateBuildConfiguration": "interactive",
}
}

View File

@@ -1880,14 +1880,23 @@ CpSolverResponse SolvePureSatModel(const CpModelProto& model_proto,
return response;
}
void UpdateDomain(int64 new_lb, int64 new_ub,
namespace {
// Returns false if the new domain is empty. Otherwise updates the domain in the
// 'mutable_var' proto by intersecting the current domain with ['new_lb',
// 'new_ub']
bool UpdateDomain(int64 new_lb, int64 new_ub,
IntegerVariableProto* mutable_var) {
const Domain old_domain = ReadDomainFromProto(*mutable_var);
const Domain new_domain = old_domain.IntersectionWith(Domain(new_lb, new_ub));
CHECK(!new_domain.IsEmpty()) << "Invalid bounds.";
if (new_domain.IsEmpty()) {
return false;
}
FillDomainInProto(new_domain, mutable_var);
return true;
}
} // namespace
CpSolverResponse SolveCpModelWithLNS(
const CpModelProto& model_proto,
@@ -1983,6 +1992,7 @@ CpSolverResponse SolveCpModelWithLNS(
},
[&](int64 seed) {
// Update the bounds on mutable model proto.
bool model_is_unsat = false;
if (shared_bounds_manager != nullptr) {
std::vector<int> model_variables;
std::vector<int64> new_lower_bounds;
@@ -2003,8 +2013,10 @@ CpSolverResponse SolveCpModelWithLNS(
<< ", " << old_ub << "] new domain: [" << new_lb << ", "
<< new_ub << "]";
}
UpdateDomain(new_lb, new_ub,
mutable_model_proto.mutable_variables(var));
if (!UpdateDomain(new_lb, new_ub,
mutable_model_proto.mutable_variables(var))) {
model_is_unsat = true;
}
}
}
AdaptiveParameterValue& difficulty =
@@ -2039,7 +2051,9 @@ CpSolverResponse SolveCpModelWithLNS(
// Presolve and solve the LNS fragment.
CpSolverResponse local_response;
{
if (model_is_unsat) {
local_response.set_status(CpSolverStatus::INFEASIBLE);
} else {
CpModelProto mapping_proto;
std::vector<int> postsolve_mapping;
PresolveOptions options;

View File

@@ -19,6 +19,7 @@
#include "absl/strings/str_join.h"
#include "ortools/base/iterator_adaptors.h"
#include "ortools/base/map_util.h"
#include "ortools/base/stl_util.h"
#include "ortools/sat/cumulative.h"
#include "ortools/sat/disjunctive.h"
#include "ortools/sat/intervals.h"
@@ -98,36 +99,34 @@ IntegerValue FindCanonicalValue(IntegerValue lb, IntegerValue ub) {
}
std::vector<absl::Span<int>> SplitDisjointBoxes(
absl::Span<int> boxes, SchedulingConstraintHelper* x_dim) {
const SchedulingConstraintHelper& x, absl::Span<int> boxes) {
std::vector<absl::Span<int>> result;
std::sort(boxes.begin(), boxes.end(), [x_dim](int a, int b) {
return x_dim->StartMin(a) < x_dim->StartMin(b) ||
(x_dim->StartMin(a) == x_dim->StartMin(b) && a < b);
});
std::sort(boxes.begin(), boxes.end(),
[&x](int a, int b) { return x.StartMin(a) < x.StartMin(b); });
int current_start = 0;
std::size_t current_length = 1;
IntegerValue current_max_end = x_dim->EndMax(boxes[0]);
IntegerValue current_max_end = x.EndMax(boxes[0]);
for (int b = 1; b < boxes.size(); ++b) {
const int box = boxes[b];
if (x_dim->StartMin(box) < current_max_end) {
if (x.StartMin(box) < current_max_end) {
// Merge.
current_length++;
current_max_end = std::max(current_max_end, x_dim->EndMax(box));
current_max_end = std::max(current_max_end, x.EndMax(box));
} else {
if (current_length > 1) { // Ignore lists of size 1.
result.push_back({&boxes[current_start], current_length});
}
current_start = b;
current_length = 1;
current_max_end = x_dim->EndMax(box);
current_max_end = x.EndMax(box);
}
}
// Push last span.
if (current_length > 1) {
result.push_back({&boxes[current_start], current_length});
}
return result;
}
@@ -154,17 +153,14 @@ bool NonOverlappingRectanglesEnergyPropagator::Propagate() {
if (cached_areas_[box] == 0) continue;
active_boxes_.push_back(box);
}
if (active_boxes_.empty()) return true;
if (active_boxes_.size() <= 1) return true;
const std::vector<absl::Span<int>> x_split =
SplitDisjointBoxes(absl::MakeSpan(active_boxes_), &x_);
SplitDisjointBoxes(x_, absl::MakeSpan(active_boxes_));
std::vector<absl::Span<int>> y_split;
for (absl::Span<int> x_boxes : x_split) {
if (x_boxes.size() <= 1) continue;
const std::vector<absl::Span<int>> y_split =
SplitDisjointBoxes(x_boxes, &y_);
y_split = SplitDisjointBoxes(y_, x_boxes);
for (absl::Span<int> y_boxes : y_split) {
if (y_boxes.size() <= 1) continue;
for (const int box : y_boxes) {
RETURN_IF_FALSE(FailWhenEnergyIsTooLarge(box, y_boxes));
}
@@ -177,47 +173,40 @@ bool NonOverlappingRectanglesEnergyPropagator::Propagate() {
int NonOverlappingRectanglesEnergyPropagator::RegisterWith(
GenericLiteralWatcher* watcher) {
const int id = watcher->Register(this);
x_.WatchAllTasks(id, watcher);
y_.WatchAllTasks(id, watcher);
x_.WatchAllTasks(id, watcher, /*watch_start_max=*/false,
/*watch_end_max=*/true);
y_.WatchAllTasks(id, watcher, /*watch_start_max=*/false,
/*watch_end_max=*/true);
return id;
}
void NonOverlappingRectanglesEnergyPropagator::SortBoxesIntoNeighbors(
int box, absl::Span<int> local_boxes) {
auto max_span = [](IntegerValue min_a, IntegerValue max_a, IntegerValue min_b,
IntegerValue max_b) {
return std::max(max_a, max_b) - std::min(min_a, min_b) + 1;
};
cached_distance_to_bounding_box_.assign(x_.NumTasks(), IntegerValue(0));
neighbors_.clear();
int box, absl::Span<const int> local_boxes) {
const IntegerValue box_x_min = x_.StartMin(box);
const IntegerValue box_x_max = x_.EndMax(box);
const IntegerValue box_y_min = y_.StartMin(box);
const IntegerValue box_y_max = y_.EndMax(box);
neighbors_.clear();
for (const int other_box : local_boxes) {
if (other_box == box) continue;
if (cached_areas_[other_box] == 0) continue;
const IntegerValue other_x_min = x_.StartMin(other_box);
const IntegerValue other_x_max = x_.EndMax(other_box);
const IntegerValue other_y_min = y_.StartMin(other_box);
const IntegerValue other_y_max = y_.EndMax(other_box);
neighbors_.push_back(other_box);
cached_distance_to_bounding_box_[other_box] =
max_span(box_x_min, box_x_max, other_x_min, other_x_max) *
max_span(box_y_min, box_y_max, other_y_min, other_y_max);
const IntegerValue span_x =
std::max(box_x_max, other_x_max) - std::min(box_x_min, other_x_min) + 1;
const IntegerValue span_y =
std::max(box_y_max, other_y_max) - std::min(box_y_min, other_y_min) + 1;
neighbors_.push_back({other_box, span_x * span_y});
}
std::sort(neighbors_.begin(), neighbors_.begin(), [this](int i, int j) {
return cached_distance_to_bounding_box_[i] <
cached_distance_to_bounding_box_[j];
});
std::sort(neighbors_.begin(), neighbors_.end());
}
bool NonOverlappingRectanglesEnergyPropagator::FailWhenEnergyIsTooLarge(
int box, absl::Span<int> local_boxes) {
int box, absl::Span<const int> local_boxes) {
// Note that we only consider the smallest dimension of each boxes here.
SortBoxesIntoNeighbors(box, local_boxes);
@@ -229,8 +218,8 @@ bool NonOverlappingRectanglesEnergyPropagator::FailWhenEnergyIsTooLarge(
IntegerValue sum_of_areas = cached_areas_[box];
IntegerValue total_sum_of_areas = sum_of_areas;
for (const int other_box : neighbors_) {
total_sum_of_areas += cached_areas_[other_box];
for (const Neighbor n : neighbors_) {
total_sum_of_areas += cached_areas_[n.box];
}
const auto add_box_energy_in_rectangle_reason = [&](int b) {
@@ -243,7 +232,7 @@ bool NonOverlappingRectanglesEnergyPropagator::FailWhenEnergyIsTooLarge(
};
for (int i = 0; i < neighbors_.size(); ++i) {
const int other_box = neighbors_[i];
const int other_box = neighbors_[i].box;
CHECK_GT(cached_areas_[other_box], 0);
// Update Bounding box.
@@ -266,7 +255,7 @@ bool NonOverlappingRectanglesEnergyPropagator::FailWhenEnergyIsTooLarge(
y_.ClearReason();
add_box_energy_in_rectangle_reason(box);
for (int j = 0; j <= i; ++j) {
add_box_energy_in_rectangle_reason(neighbors_[j]);
add_box_energy_in_rectangle_reason(neighbors_[j].box);
}
x_.ImportOtherReasons(y_);
return x_.ReportConflict();
@@ -275,149 +264,142 @@ bool NonOverlappingRectanglesEnergyPropagator::FailWhenEnergyIsTooLarge(
return true;
}
// Note that x_ and y_ must be initialized with enough intervals when passed
// to the disjunctive propagators.
NonOverlappingRectanglesDisjunctivePropagator::
NonOverlappingRectanglesDisjunctivePropagator(
const std::vector<IntervalVariable>& x,
const std::vector<IntervalVariable>& y, bool strict,
bool slow_propagators, Model* model)
: x_intervals_(x),
y_intervals_(y),
const std::vector<IntervalVariable>& y, bool strict, Model* model)
: global_x_(x, model),
global_y_(y, model),
x_(x, model),
y_(y, model),
strict_(strict),
slow_propagators_(slow_propagators),
watcher_(model->GetOrCreate<GenericLiteralWatcher>()),
overload_checker_(true, &x_),
forward_detectable_precedences_(true, &x_),
backward_detectable_precedences_(false, &x_),
forward_not_last_(true, &x_),
backward_not_last_(false, &x_),
forward_edge_finding_(true, &x_),
backward_edge_finding_(false, &x_) {
CHECK_GT(x_.NumTasks(), 0);
}
backward_edge_finding_(false, &x_) {}
NonOverlappingRectanglesDisjunctivePropagator::
~NonOverlappingRectanglesDisjunctivePropagator() {}
int NonOverlappingRectanglesDisjunctivePropagator::RegisterWith(
GenericLiteralWatcher* watcher) {
const int id = watcher->Register(this);
x_.WatchAllTasks(id, watcher);
y_.WatchAllTasks(id, watcher);
return id;
void NonOverlappingRectanglesDisjunctivePropagator::RegisterWith(
GenericLiteralWatcher* watcher, int fast_priority, int slow_priority) {
fast_id_ = watcher->Register(this);
watcher->SetPropagatorPriority(fast_id_, fast_priority);
global_x_.WatchAllTasks(fast_id_, watcher);
global_y_.WatchAllTasks(fast_id_, watcher);
const int slow_id = watcher->Register(this);
watcher->SetPropagatorPriority(slow_id, slow_priority);
global_x_.WatchAllTasks(slow_id, watcher);
global_y_.WatchAllTasks(slow_id, watcher);
}
bool NonOverlappingRectanglesDisjunctivePropagator::
FindBoxesThatMustOverlapAHorizontalLineAndPropagate(
const std::vector<IntervalVariable>& x_intervals,
const std::vector<IntervalVariable>& y_intervals,
const SchedulingConstraintHelper& x,
const SchedulingConstraintHelper& y,
std::function<bool()> inner_propagate) {
// Restore the two dimensions in a sane state.
x_.SetTimeDirection(true);
x_.ClearOtherHelper();
x_.Init(x_intervals);
y_.SetTimeDirection(true);
y_.ClearOtherHelper();
y_.Init(y_intervals);
// Compute relevant events (line in the y dimension).
event_to_overlapping_boxes_.clear();
events_.clear();
std::vector<int> active_boxes;
for (int box = 0; box < x_intervals.size(); ++box) {
if ((x_.DurationMin(box) == 0 || y_.DurationMin(box) == 0) && !strict_) {
active_boxes_.clear();
events_time_.clear();
for (int box = 0; box < x.NumTasks(); ++box) {
if (!strict_ && (x.DurationMin(box) == 0 || y.DurationMin(box) == 0)) {
continue;
}
const IntegerValue start_max = y_.StartMax(box);
const IntegerValue end_min = y_.EndMin(box);
const IntegerValue start_max = y.StartMax(box);
const IntegerValue end_min = y.EndMin(box);
if (start_max < end_min) {
events_.insert(start_max);
active_boxes.push_back(box);
events_time_.push_back(start_max);
active_boxes_.push_back(box);
}
}
// Less than 2 boxes, no propagation.
if (active_boxes.size() < 2) return true;
if (active_boxes_.size() < 2) return true;
// Add boxes to the event lists they always overlap with.
for (const int box : active_boxes) {
const IntegerValue start_max = y_.StartMax(box);
const IntegerValue end_min = y_.EndMin(box);
gtl::STLSortAndRemoveDuplicates(&events_time_);
events_overlapping_boxes_.assign(events_time_.size(), {});
for (const int box : active_boxes_) {
const IntegerValue start_max = y.StartMax(box);
const IntegerValue end_min = y.EndMin(box);
for (const IntegerValue t : events_) {
for (int i = 0; i < events_time_.size(); ++i) {
const IntegerValue t = events_time_[i];
if (t < start_max) continue;
if (t >= end_min) break;
event_to_overlapping_boxes_[t].push_back(box);
events_overlapping_boxes_[i].push_back(box);
}
}
// Scan events chronologically to remove events where there is only one
// mandatory box, or dominated events lists.
std::vector<IntegerValue> events_to_remove;
std::vector<int> previous_overlapping_boxes;
IntegerValue previous_event(-1);
for (const IntegerValue current_event : events_) {
const std::vector<int>& current_overlapping_boxes =
event_to_overlapping_boxes_[current_event];
if (current_overlapping_boxes.size() < 2) {
events_to_remove.push_back(current_event);
continue;
}
if (!previous_overlapping_boxes.empty()) {
// In case we just add one box to the previous event.
if (std::includes(current_overlapping_boxes.begin(),
current_overlapping_boxes.end(),
previous_overlapping_boxes.begin(),
previous_overlapping_boxes.end())) {
events_to_remove.push_back(previous_event);
continue;
{
int new_size = 0;
for (std::vector<int>& overlapping_boxes : events_overlapping_boxes_) {
if (overlapping_boxes.size() < 2) {
continue; // Remove current event.
}
if (new_size > 0) {
const std::vector<int>& previous_overlapping_boxes =
events_overlapping_boxes_[new_size - 1];
// If the previous set of boxes is included in the current one, replace
// the old one by the new one.
//
// Note that because the events correspond to new boxes, there is no
// need to check for the other side (current set included in previous
// set).
if (std::includes(overlapping_boxes.begin(), overlapping_boxes.end(),
previous_overlapping_boxes.begin(),
previous_overlapping_boxes.end())) {
--new_size;
}
}
std::swap(events_overlapping_boxes_[new_size], overlapping_boxes);
++new_size;
}
previous_event = current_event;
previous_overlapping_boxes = current_overlapping_boxes;
}
for (const IntegerValue event : events_to_remove) {
events_.erase(event);
events_overlapping_boxes_.resize(new_size);
}
// Split lists of boxes into disjoint set of boxes (w.r.t. overlap).
reduced_overlapping_boxes_.clear();
boxes_to_propagate_.clear();
for (const IntegerValue event : events_) {
disjoint_boxes_ = SplitDisjointBoxes(
absl::MakeSpan(event_to_overlapping_boxes_[event]), &x_);
reduced_overlapping_boxes_.clear();
for (std::vector<int>& overlapping_boxes : events_overlapping_boxes_) {
disjoint_boxes_ = SplitDisjointBoxes(x, absl::MakeSpan(overlapping_boxes));
for (absl::Span<int> sub_boxes : disjoint_boxes_) {
if (sub_boxes.size() > 1) {
// Boxes are sorted in a stable manner in the Split method.
const auto& insertion = reduced_overlapping_boxes_.insert(sub_boxes);
if (insertion.second) boxes_to_propagate_.push_back(sub_boxes);
}
// Boxes are sorted in a stable manner in the Split method.
// Note that we do not use reduced_overlapping_boxes_ directly so that
// the order of iteration is deterministic.
const auto& insertion = reduced_overlapping_boxes_.insert(sub_boxes);
if (insertion.second) boxes_to_propagate_.push_back(sub_boxes);
}
}
// And finally propagate.
// TODO(user): Sorting of boxes seems influential on the performance. Test.
for (const absl::Span<int> boxes : boxes_to_propagate_) {
std::vector<IntervalVariable> reduced_x;
std::vector<IntervalVariable> reduced_y;
for (const absl::Span<const int> boxes : boxes_to_propagate_) {
reduced_x_.clear();
reduced_y_.clear();
for (const int box : boxes) {
reduced_x.push_back(x_intervals[box]);
reduced_y.push_back(y_intervals[box]);
reduced_x_.push_back(x.Intervals()[box]);
reduced_y_.push_back(y.Intervals()[box]);
}
x_.Init(reduced_x);
y_.Init(reduced_y);
x_.Init(reduced_x_);
y_.Init(reduced_y_);
// Collect the common overlapping coordinates of all boxes.
IntegerValue lb(kint64min);
IntegerValue ub(kint64max);
for (int i = 0; i < reduced_x.size(); ++i) {
for (int i = 0; i < reduced_x_.size(); ++i) {
lb = std::max(lb, y_.StartMax(i));
ub = std::min(ub, y_.EndMin(i) - 1);
}
@@ -443,44 +425,39 @@ bool NonOverlappingRectanglesDisjunctivePropagator::
}
bool NonOverlappingRectanglesDisjunctivePropagator::Propagate() {
const auto slow_propagate = [this]() {
if (x_.NumTasks() <= 2) return true;
RETURN_IF_FALSE(forward_not_last_.Propagate());
RETURN_IF_FALSE(backward_not_last_.Propagate());
RETURN_IF_FALSE(backward_edge_finding_.Propagate());
RETURN_IF_FALSE(forward_edge_finding_.Propagate());
return true;
};
const auto fast_propagate = [this]() {
if (x_.NumTasks() == 2) {
// In that case, we can use simpler algorithms.
// Note that this case happens frequently (~30% of all calls to this
// method according to our tests).
RETURN_IF_FALSE(PropagateTwoBoxes());
} else {
RETURN_IF_FALSE(overload_checker_.Propagate());
RETURN_IF_FALSE(forward_detectable_precedences_.Propagate());
RETURN_IF_FALSE(backward_detectable_precedences_.Propagate());
}
return true;
};
if (slow_propagators_) {
RETURN_IF_FALSE(FindBoxesThatMustOverlapAHorizontalLineAndPropagate(
x_intervals_, y_intervals_, slow_propagate));
// We can actually swap dimensions to propagate vertically.
RETURN_IF_FALSE(FindBoxesThatMustOverlapAHorizontalLineAndPropagate(
y_intervals_, x_intervals_, slow_propagate));
std::function<bool()> inner_propagate;
if (watcher_->GetCurrentId() == fast_id_) {
inner_propagate = [this]() {
if (x_.NumTasks() == 2) {
// In that case, we can use simpler algorithms.
// Note that this case happens frequently (~30% of all calls to this
// method according to our tests).
RETURN_IF_FALSE(PropagateTwoBoxes());
} else {
RETURN_IF_FALSE(overload_checker_.Propagate());
RETURN_IF_FALSE(forward_detectable_precedences_.Propagate());
RETURN_IF_FALSE(backward_detectable_precedences_.Propagate());
}
return true;
};
} else {
RETURN_IF_FALSE(FindBoxesThatMustOverlapAHorizontalLineAndPropagate(
x_intervals_, y_intervals_, fast_propagate));
// We can actually swap dimensions to propagate vertically.
RETURN_IF_FALSE(FindBoxesThatMustOverlapAHorizontalLineAndPropagate(
y_intervals_, x_intervals_, fast_propagate));
inner_propagate = [this]() {
if (x_.NumTasks() <= 2) return true;
RETURN_IF_FALSE(forward_not_last_.Propagate());
RETURN_IF_FALSE(backward_not_last_.Propagate());
RETURN_IF_FALSE(backward_edge_finding_.Propagate());
RETURN_IF_FALSE(forward_edge_finding_.Propagate());
return true;
};
}
RETURN_IF_FALSE(FindBoxesThatMustOverlapAHorizontalLineAndPropagate(
global_x_, global_y_, inner_propagate));
// We can actually swap dimensions to propagate vertically.
RETURN_IF_FALSE(FindBoxesThatMustOverlapAHorizontalLineAndPropagate(
global_y_, global_x_, inner_propagate));
return true;
}

View File

@@ -44,15 +44,23 @@ class NonOverlappingRectanglesEnergyPropagator : public PropagatorInterface {
int RegisterWith(GenericLiteralWatcher* watcher);
private:
void SortBoxesIntoNeighbors(int box, absl::Span<int> local_boxes);
bool FailWhenEnergyIsTooLarge(int box, absl::Span<int> local_boxes);
void SortBoxesIntoNeighbors(int box, absl::Span<const int> local_boxes);
bool FailWhenEnergyIsTooLarge(int box, absl::Span<const int> local_boxes);
SchedulingConstraintHelper x_;
SchedulingConstraintHelper y_;
std::vector<IntegerValue> cached_areas_;
std::vector<int> neighbors_;
std::vector<IntegerValue> cached_distance_to_bounding_box_;
std::vector<int> active_boxes_;
std::vector<IntegerValue> cached_areas_;
struct Neighbor {
int box;
IntegerValue distance_to_bounding_box;
bool operator<(const Neighbor& o) const {
return distance_to_bounding_box < o.distance_to_bounding_box;
}
};
std::vector<Neighbor> neighbors_;
NonOverlappingRectanglesEnergyPropagator(
const NonOverlappingRectanglesEnergyPropagator&) = delete;
@@ -70,32 +78,39 @@ class NonOverlappingRectanglesDisjunctivePropagator
// The slow_propagators select which disjunctive algorithms to propagate.
NonOverlappingRectanglesDisjunctivePropagator(
const std::vector<IntervalVariable>& x,
const std::vector<IntervalVariable>& y, bool strict,
bool slow_propagators, Model* model);
const std::vector<IntervalVariable>& y, bool strict, Model* model);
~NonOverlappingRectanglesDisjunctivePropagator() override;
bool Propagate() final;
int RegisterWith(GenericLiteralWatcher* watcher);
void RegisterWith(GenericLiteralWatcher* watcher, int fast_priority,
int slow_priority);
private:
bool FindBoxesThatMustOverlapAHorizontalLineAndPropagate(
const std::vector<IntervalVariable>& x_intervals,
const std::vector<IntervalVariable>& y_intervals,
std::function<bool()> inner_propagate);
bool PropagateTwoBoxes();
bool FindBoxesThatMustOverlapAHorizontalLineAndPropagate(
const SchedulingConstraintHelper& x, const SchedulingConstraintHelper& y,
std::function<bool()> inner_propagate);
const std::vector<IntervalVariable> x_intervals_;
const std::vector<IntervalVariable> y_intervals_;
SchedulingConstraintHelper global_x_;
SchedulingConstraintHelper global_y_;
SchedulingConstraintHelper x_;
SchedulingConstraintHelper y_;
const bool strict_;
const bool slow_propagators_;
absl::flat_hash_map<IntegerValue, std::vector<int>>
event_to_overlapping_boxes_;
GenericLiteralWatcher* watcher_;
int fast_id_; // Propagator id of the "fast" version.
std::vector<int> active_boxes_;
std::vector<IntegerValue> events_time_;
std::vector<std::vector<int>> events_overlapping_boxes_;
std::vector<IntervalVariable> reduced_x_;
std::vector<IntervalVariable> reduced_y_;
absl::flat_hash_set<absl::Span<int>> reduced_overlapping_boxes_;
std::vector<absl::Span<int>> boxes_to_propagate_;
std::vector<absl::Span<int>> disjoint_boxes_;
std::set<IntegerValue> events_;
DisjunctiveOverloadChecker overload_checker_;
DisjunctiveDetectablePrecedences forward_detectable_precedences_;
DisjunctiveDetectablePrecedences backward_detectable_precedences_;
@@ -129,21 +144,14 @@ inline std::function<void(Model*)> NonOverlappingRectangles(
NonOverlappingRectanglesEnergyPropagator* energy_constraint =
new NonOverlappingRectanglesEnergyPropagator(x, y, model);
watcher->SetPropagatorPriority(energy_constraint->RegisterWith(watcher), 3);
model->TakeOwnership(energy_constraint);
NonOverlappingRectanglesDisjunctivePropagator* fast_constraint =
new NonOverlappingRectanglesDisjunctivePropagator(
x, y, is_strict, /*slow_propagators=*/false, model);
watcher->SetPropagatorPriority(fast_constraint->RegisterWith(watcher), 3);
model->TakeOwnership(fast_constraint);
NonOverlappingRectanglesDisjunctivePropagator* slow_constraint =
new NonOverlappingRectanglesDisjunctivePropagator(
x, y, is_strict, /*slow_propagators=*/true, model);
watcher->SetPropagatorPriority(slow_constraint->RegisterWith(watcher), 4);
model->TakeOwnership(slow_constraint);
NonOverlappingRectanglesDisjunctivePropagator* constraint =
new NonOverlappingRectanglesDisjunctivePropagator(x, y, is_strict,
model);
constraint->RegisterWith(watcher, /*fast_priority=*/3, /*slow_priority=*/4);
model->TakeOwnership(constraint);
AddCumulativeRelaxation(x, y, model);
AddCumulativeRelaxation(y, x, model);

View File

@@ -1594,6 +1594,7 @@ bool GenericLiteralWatcher::Propagate(Trail* trail) {
std::deque<int>& queue = queue_by_priority_[priority];
while (!queue.empty()) {
const int id = queue.front();
current_id_ = id;
queue.pop_front();
// Before we propagate, make sure any reversible structure are up to date.

View File

@@ -1056,6 +1056,11 @@ class GenericLiteralWatcher : public SatPropagator {
level_zero_modified_variable_callback_.push_back(cb);
}
// Returns the id of the propagator we are currently calling. This is meant
// to be used from inside Propagate() in case a propagator was registered
// more than once at different priority for instance.
int GetCurrentId() const { return current_id_; }
private:
// Updates queue_ and in_queue_ with the propagator ids that need to be
// called.
@@ -1091,6 +1096,9 @@ class GenericLiteralWatcher : public SatPropagator {
// Special propagators that needs to always be called at level zero.
std::vector<int> propagator_ids_to_call_at_level_zero_;
// The id of the propagator we just called.
int current_id_;
std::vector<std::function<void(const std::vector<IntegerVariable>&)>>
level_zero_modified_variable_callback_;

View File

@@ -68,6 +68,7 @@ SchedulingConstraintHelper::SchedulingConstraintHelper(Model* model)
void SchedulingConstraintHelper::Init(
const std::vector<IntervalVariable>& tasks) {
intervals_ = tasks;
start_vars_.clear();
end_vars_.clear();
minus_end_vars_.clear();

View File

@@ -126,7 +126,7 @@ struct TaskTime {
// code.
class SchedulingConstraintHelper {
public:
SchedulingConstraintHelper(Model* model);
explicit SchedulingConstraintHelper(Model* model);
// All the functions below refer to a task by its index t in the tasks
// vector given at construction.
@@ -236,6 +236,7 @@ class SchedulingConstraintHelper {
// Returns the underlying integer variables.
const std::vector<IntegerVariable>& StartVars() const { return start_vars_; }
const std::vector<IntegerVariable>& EndVars() const { return end_vars_; }
const std::vector<IntervalVariable>& Intervals() const { return intervals_; }
// Registers the given propagator id to be called if any of the tasks
// in this class change.
@@ -283,6 +284,7 @@ class SchedulingConstraintHelper {
// All the underlying variables of the tasks.
// The vectors are indexed by the task index t.
std::vector<IntervalVariable> intervals_;
std::vector<IntegerVariable> start_vars_;
std::vector<IntegerVariable> end_vars_;
std::vector<IntegerVariable> duration_vars_;