Google OR-Tools v9.15
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
2d_distances_propagator.cc
Go to the documentation of this file.
1// Copyright 2010-2025 Google LLC
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
15
16#include <algorithm>
17#include <cstdint>
18#include <string>
19#include <utility>
20#include <variant>
21#include <vector>
22
23#include "absl/algorithm/container.h"
24#include "absl/container/flat_hash_map.h"
25#include "absl/container/inlined_vector.h"
26#include "absl/log/check.h"
27#include "absl/log/log.h"
28#include "absl/types/span.h"
31#include "ortools/sat/integer.h"
34#include "ortools/sat/model.h"
40
41namespace operations_research {
42namespace sat {
43
45 NoOverlap2DConstraintHelper* helper, Model* model)
46 : helper_(*helper),
47 linear2_bounds_(model->GetOrCreate<Linear2Bounds>()),
48 linear2_watcher_(model->GetOrCreate<Linear2Watcher>()),
49 shared_stats_(model->GetOrCreate<SharedStatistics>()),
50 lin2_indices_(model->GetOrCreate<Linear2Indices>()),
51 trail_(model->GetOrCreate<Trail>()),
52 integer_trail_(model->GetOrCreate<IntegerTrail>()) {
54}
55
56void Precedences2DPropagator::UpdateVarLookups() {
57 var_to_box_and_coeffs_.clear();
58 for (int dim = 0; dim < 2; ++dim) {
59 const SchedulingConstraintHelper& dim_helper =
60 dim == 0 ? helper_.x_helper() : helper_.y_helper();
61 for (int j = 0; j < 2; ++j) {
62 const absl::Span<const AffineExpression> interval_points =
63 j == 0 ? dim_helper.Starts() : dim_helper.Ends();
64 for (int i = 0; i < helper_.NumBoxes(); ++i) {
65 const IntegerVariable var = interval_points[i].var;
66 if (var != kNoIntegerVariable) {
67 var_to_box_and_coeffs_[PositiveVariable(var)].boxes[dim][j].push_back(
68 i);
69 }
70 }
71 }
72 }
73}
74
75void Precedences2DPropagator::AddOrUpdateDataForPairOfBoxes(int box1,
76 int box2) {
77 if (box1 > box2) std::swap(box1, box2);
78 const auto [it, inserted] = non_trivial_pairs_index_.insert(
79 {std::make_pair(box1, box2), static_cast<int>(pair_data_.size())});
80 absl::InlinedVector<Literal, 4> presence_literals;
81 for (int dim = 0; dim < 2; ++dim) {
82 const SchedulingConstraintHelper& dim_helper =
83 dim == 0 ? helper_.x_helper() : helper_.y_helper();
84 for (const int box : {box1, box2}) {
85 if (dim_helper.IsOptional(box)) {
86 presence_literals.push_back(dim_helper.PresenceLiteral(box));
87 }
88 }
89 }
90 gtl::STLSortAndRemoveDuplicates(&presence_literals);
91 if (inserted) {
92 pair_data_.emplace_back(
93 PairData{.pair_presence_literals = {presence_literals.begin(),
94 presence_literals.end()},
95 .box1 = box1,
96 .box2 = box2});
97 }
98 PairData& pair_data = pair_data_[it->second];
99 for (int dim = 0; dim < 2; ++dim) {
100 const SchedulingConstraintHelper& dim_helper =
101 dim == 0 ? helper_.x_helper() : helper_.y_helper();
102 for (int j = 0; j < 2; ++j) {
103 int b1 = j == 0 ? box1 : box2;
104 int b2 = j == 0 ? box2 : box1;
105 auto [start_minus_end_expr, start_minus_end_ub] =
106 EncodeDifferenceLowerThan(dim_helper.Starts()[b1],
107 dim_helper.Ends()[b2], 0);
108 const LinearExpression2Index start_minus_end_index =
109 lin2_indices_->GetIndex(start_minus_end_expr);
110 pair_data.start_before_end[dim][j].ub = start_minus_end_ub;
111 if (start_minus_end_index != kNoLinearExpression2Index) {
112 pair_data.start_before_end[dim][j].linear2 = start_minus_end_index;
113 } else {
114 pair_data.start_before_end[dim][j].linear2 = start_minus_end_expr;
115 }
116 }
117 }
118}
119
120void Precedences2DPropagator::CollectNewPairsOfBoxesWithNonTrivialDistance() {
121 const absl::Span<const LinearExpression2> exprs =
122 lin2_indices_->GetStoredLinear2Indices();
123 if (exprs.size() == num_known_linear2_) {
124 return;
125 }
126 VLOG(2) << "CollectPairsOfBoxesWithNonTrivialDistance called, num_exprs: "
127 << exprs.size();
128 for (; num_known_linear2_ < exprs.size(); ++num_known_linear2_) {
129 const LinearExpression2& positive_expr = exprs[num_known_linear2_];
130 LinearExpression2 negated_expr = positive_expr;
131 negated_expr.Negate();
132 for (const LinearExpression2& expr : {positive_expr, negated_expr}) {
133 auto it1 = var_to_box_and_coeffs_.find(PositiveVariable(expr.vars[0]));
134 auto it2 = var_to_box_and_coeffs_.find(PositiveVariable(expr.vars[1]));
135 if (it1 == var_to_box_and_coeffs_.end()) {
136 continue;
137 }
138 if (it2 == var_to_box_and_coeffs_.end()) {
139 continue;
140 }
141
142 const VarUsage& usage1 = it1->second;
143 const VarUsage& usage2 = it2->second;
144 for (int dim = 0; dim < 2; ++dim) {
145 for (const int box1 : usage1.boxes[dim][0 /* start */]) {
146 for (const int box2 : usage2.boxes[dim][1 /* end */]) {
147 if (box1 == box2) continue;
148 AddOrUpdateDataForPairOfBoxes(box1, box2);
149 }
150 }
151 }
152 }
153 }
154}
155
156IntegerValue Precedences2DPropagator::UpperBound(
157 std::variant<LinearExpression2, LinearExpression2Index> linear2) const {
158 if (std::holds_alternative<LinearExpression2Index>(linear2)) {
159 return linear2_bounds_->UpperBound(
160 std::get<LinearExpression2Index>(linear2));
161 } else {
162 return integer_trail_->UpperBound(std::get<LinearExpression2>(linear2));
163 }
164}
165
167 if (!helper_.IsEnforced()) return true;
168 if (last_helper_inprocessing_count_ != helper_.InProcessingCount()) {
169 if (!helper_.SynchronizeAndSetDirection()) return false;
170 last_helper_inprocessing_count_ = helper_.InProcessingCount();
171 UpdateVarLookups();
172 num_known_linear2_ = 0;
173 non_trivial_pairs_index_.clear();
174 pair_data_.clear();
175 }
176 CollectNewPairsOfBoxesWithNonTrivialDistance();
177
178 num_calls_++;
179
180 for (const PairData& pair_data : pair_data_) {
181 if (!absl::c_all_of(pair_data.pair_presence_literals,
182 [this](const Literal& literal) {
183 return trail_->Assignment().LiteralIsTrue(literal);
184 })) {
185 continue;
186 }
187
188 bool is_unfeasible = true;
189 for (int dim = 0; dim < 2; dim++) {
190 for (int j = 0; j < 2; j++) {
191 const PairData::Condition& start_before_end =
192 pair_data.start_before_end[dim][j];
193 if (UpperBound(start_before_end.linear2) >= start_before_end.ub) {
194 is_unfeasible = false;
195 break;
196 }
197 }
198 if (!is_unfeasible) break;
199 }
200 if (!is_unfeasible) continue;
201
202 // We have a mandatory overlap on both x and y! Explain and propagate.
203 if (!helper_.SynchronizeAndSetDirection()) return false;
204
205 const int box1 = pair_data.box1;
206 const int box2 = pair_data.box2;
207 helper_.ResetReason();
208 num_conflicts_++;
209
210 helper_.x_helper().AddReasonForBeingBeforeAssumingNoOverlap(box1, box2);
211 helper_.x_helper().AddReasonForBeingBeforeAssumingNoOverlap(box2, box1);
212 helper_.y_helper().AddReasonForBeingBeforeAssumingNoOverlap(box1, box2);
213 helper_.y_helper().AddReasonForBeingBeforeAssumingNoOverlap(box2, box1);
214
215 helper_.AddPresenceReason(box1);
216 helper_.AddPresenceReason(box2);
217 return helper_.ReportConflict();
218 }
219 return true;
220}
221
223 const int id = watcher->Register(this);
224 helper_.WatchAllBoxes(id);
225 linear2_watcher_->WatchAllLinearExpressions2(id);
226 return id;
227}
228
230 if (!VLOG_IS_ON(1)) return;
231 std::vector<std::pair<std::string, int64_t>> stats;
232 stats.push_back({"Precedences2DPropagator/called", num_calls_});
233 stats.push_back({"Precedences2DPropagator/conflicts", num_conflicts_});
234 stats.push_back({"Precedences2DPropagator/pairs", pair_data_.size()});
235
236 shared_stats_->AddStats(stats);
237}
238
239} // namespace sat
240} // namespace operations_research
int Register(PropagatorInterface *propagator)
Definition integer.cc:2674
Precedences2DPropagator(NoOverlap2DConstraintHelper *helper, Model *model)
absl::Span< const AffineExpression > Starts() const
absl::Span< const AffineExpression > Ends() const
void STLSortAndRemoveDuplicates(T *v, const LessFunc &less_func)
Definition stl_util.h:55
const LinearExpression2Index kNoLinearExpression2Index(-1)
const IntegerVariable kNoIntegerVariable(-1)
IntegerVariable PositiveVariable(IntegerVariable i)
std::pair< LinearExpression2, IntegerValue > EncodeDifferenceLowerThan(AffineExpression a, AffineExpression b, IntegerValue ub)
OR-Tools root namespace.
std::variant< LinearExpression2, LinearExpression2Index > linear2