Skip to content

Commit f4f3974

Browse files
committed
minor optims
1 parent f362122 commit f4f3974

18 files changed

Lines changed: 3809 additions & 79 deletions

ortools/flatzinc/fz.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ int main(int argc, char** argv) {
194194
std::string currentLine;
195195
while (std::getline(std::cin, currentLine)) {
196196
input.append(currentLine);
197+
input.append("\n");
197198
}
198199
} else {
199200
if (residual_flags.empty()) {

ortools/graph/minimum_spanning_tree.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,16 +134,21 @@ std::vector<typename Graph::ArcIndex> BuildPrimMinimumSpanningTree(
134134
int GetHeapIndex() const { return heap_index; }
135135
bool operator<(const Entry& other) const { return value > other.value; }
136136

137-
NodeIndex node;
137+
// In the typical case, `NodeIndex` is 4 bytes, so having fields in this
138+
// order is optimal in terms of memory usage and cache locality across all
139+
// values of `sizeof(ArcValueType)`.
138140
ArcValueType value;
141+
NodeIndex node;
139142
int heap_index;
140143
};
141144

142145
AdjustablePriorityQueue<Entry> pq;
143146
std::vector<Entry> entries;
144147
std::vector<bool> touched_entry(graph.num_nodes(), false);
145148
for (NodeIndex node : graph.AllNodes()) {
146-
entries.push_back({node, std::numeric_limits<ArcValueType>::max(), -1});
149+
entries.push_back({.value = std::numeric_limits<ArcValueType>::max(),
150+
.node = node,
151+
.heap_index = -1});
147152
}
148153
entries[0].value = 0;
149154
pq.Add(&entries[0]);

ortools/sat/BUILD.bazel

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3509,11 +3509,13 @@ cc_library(
35093509
":synchronization",
35103510
":timetable",
35113511
":util",
3512+
"//ortools/base:stl_util",
35123513
"//ortools/util:bitset",
35133514
"//ortools/util:saturated_arithmetic",
35143515
"//ortools/util:strong_integers",
35153516
"//ortools/util:time_limit",
35163517
"@abseil-cpp//absl/container:flat_hash_set",
3518+
"@abseil-cpp//absl/container:inlined_vector",
35173519
"@abseil-cpp//absl/log",
35183520
"@abseil-cpp//absl/log:check",
35193521
"@abseil-cpp//absl/log:vlog_is_on",

ortools/sat/cp_model.cc

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -610,6 +610,9 @@ LinearExpr IntervalVar::EndExpr() const {
610610
BoolVar IntervalVar::PresenceBoolVar() const {
611611
DCHECK(builder_ != nullptr);
612612
if (builder_ == nullptr) return BoolVar();
613+
if (builder_->Proto().constraints(index_).enforcement_literal_size() == 0) {
614+
return builder_->TrueVar();
615+
}
613616
return BoolVar(builder_->Proto().constraints(index_).enforcement_literal(0),
614617
builder_);
615618
}
@@ -712,12 +715,25 @@ BoolVar CpModelBuilder::FalseVar() {
712715
IntervalVar CpModelBuilder::NewIntervalVar(const LinearExpr& start,
713716
const LinearExpr& size,
714717
const LinearExpr& end) {
715-
return NewOptionalIntervalVar(start, size, end, TrueVar());
718+
const int index = cp_model_.constraints_size();
719+
ConstraintProto* const ct = cp_model_.add_constraints();
720+
IntervalConstraintProto* const interval = ct->mutable_interval();
721+
*interval->mutable_start() = LinearExprToProto(start);
722+
*interval->mutable_size() = LinearExprToProto(size);
723+
*interval->mutable_end() = LinearExprToProto(end);
724+
return IntervalVar(index, this);
716725
}
717726

718727
IntervalVar CpModelBuilder::NewFixedSizeIntervalVar(const LinearExpr& start,
719728
int64_t size) {
720-
return NewOptionalFixedSizeIntervalVar(start, size, TrueVar());
729+
const int index = cp_model_.constraints_size();
730+
ConstraintProto* const ct = cp_model_.add_constraints();
731+
IntervalConstraintProto* const interval = ct->mutable_interval();
732+
*interval->mutable_start() = LinearExprToProto(start);
733+
interval->mutable_size()->set_offset(size);
734+
*interval->mutable_end() = LinearExprToProto(start);
735+
interval->mutable_end()->set_offset(interval->end().offset() + size);
736+
return IntervalVar(index, this);
721737
}
722738

723739
IntervalVar CpModelBuilder::NewOptionalIntervalVar(const LinearExpr& start,

ortools/sat/cp_model_solver.cc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2407,7 +2407,8 @@ CpSolverResponse SolveCpModel(const CpModelProto& model_proto, Model* model) {
24072407
// Always add the timing information to a response. Note that it is important
24082408
// to add this after the log/dump postprocessor since we execute them in
24092409
// reverse order.
2410-
auto* shared_time_limit = model->GetOrCreate<ModelSharedTimeLimit>();
2410+
ModelSharedTimeLimit* shared_time_limit =
2411+
model->GetOrCreate<ModelSharedTimeLimit>();
24112412
shared_response_manager->AddResponsePostprocessor(
24122413
[&wall_timer, &user_timer,
24132414
&shared_time_limit](CpSolverResponse* response) {
@@ -2446,7 +2447,7 @@ CpSolverResponse SolveCpModel(const CpModelProto& model_proto, Model* model) {
24462447
// Register SIGINT handler if requested by the parameters.
24472448
if (params.catch_sigint_signal()) {
24482449
model->GetOrCreate<SigintHandler>()->Register(
2449-
[&shared_time_limit]() { shared_time_limit->Stop(); });
2450+
[shared_time_limit]() { shared_time_limit->Stop(); });
24502451
}
24512452
#endif // __PORTABLE_PLATFORM__
24522453

ortools/sat/cp_model_test.cc

Lines changed: 16 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1196,37 +1196,32 @@ TEST(CpModelTest, TestNoOverlap) {
11961196
const CpModelProto expected_model = ParseTestProto(R"pb(
11971197
variables { domain: 0 domain: 20 }
11981198
variables { domain: 0 domain: 20 }
1199-
variables { domain: 1 domain: 1 }
12001199
variables { domain: 0 domain: 20 }
12011200
variables { domain: 0 domain: 20 }
12021201
variables { domain: 0 domain: 20 }
12031202
variables { domain: 0 domain: 20 }
12041203
constraints {
1205-
enforcement_literal: 2
12061204
interval {
12071205
start { vars: 0 coeffs: 1 }
12081206
end { vars: 1 coeffs: 1 }
12091207
size { offset: 5 }
12101208
}
12111209
}
12121210
constraints {
1213-
enforcement_literal: 2
12141211
interval {
1215-
start { vars: 3 coeffs: 1 }
1216-
end { vars: 4 coeffs: 1 }
1212+
start { vars: 2 coeffs: 1 }
1213+
end { vars: 3 coeffs: 1 }
12171214
size { offset: 5 }
12181215
}
12191216
}
12201217
constraints {
1221-
enforcement_literal: 2
12221218
interval {
1223-
start { vars: 5 coeffs: 1 }
1224-
end { vars: 6 coeffs: 1 }
1219+
start { vars: 4 coeffs: 1 }
1220+
end { vars: 5 coeffs: 1 }
12251221
size { offset: 5 }
12261222
}
12271223
}
1228-
constraints { no_overlap { intervals: 0 intervals: 1 intervals: 2 } }
1229-
)pb");
1224+
constraints { no_overlap { intervals: 0 intervals: 1 intervals: 2 } })pb");
12301225
EXPECT_THAT(cp_model.Proto(), EqualsProto(expected_model));
12311226
}
12321227

@@ -1257,42 +1252,37 @@ TEST(CpModelTest, TestNoOverlap2D) {
12571252
variables { domain: 0 domain: 20 }
12581253
variables { domain: 0 domain: 20 }
12591254
variables { domain: 5 domain: 5 }
1260-
variables { domain: 1 domain: 1 }
12611255
variables { domain: 0 domain: 20 }
12621256
variables { domain: 0 domain: 20 }
12631257
variables { domain: 0 domain: 20 }
12641258
variables { domain: 0 domain: 20 }
12651259
variables { domain: 0 domain: 20 }
12661260
variables { domain: 0 domain: 20 }
12671261
constraints {
1268-
enforcement_literal: 3
12691262
interval {
12701263
start { vars: 0 coeffs: 1 }
12711264
end { vars: 1 coeffs: 1 }
12721265
size { vars: 2 coeffs: 1 }
12731266
}
12741267
}
12751268
constraints {
1276-
enforcement_literal: 3
12771269
interval {
1278-
start { vars: 4 coeffs: 1 }
1279-
end { vars: 5 coeffs: 1 }
1270+
start { vars: 3 coeffs: 1 }
1271+
end { vars: 4 coeffs: 1 }
12801272
size { vars: 2 coeffs: 1 }
12811273
}
12821274
}
12831275
constraints {
1284-
enforcement_literal: 3
12851276
interval {
1286-
start { vars: 6 coeffs: 1 }
1287-
end { vars: 7 coeffs: 1 }
1277+
start { vars: 5 coeffs: 1 }
1278+
end { vars: 6 coeffs: 1 }
12881279
size { vars: 2 coeffs: 1 }
12891280
}
12901281
}
12911282
constraints {
1292-
enforcement_literal: 3
12931283
interval {
1294-
start { vars: 8 coeffs: 1 }
1295-
end { vars: 9 coeffs: 1 }
1284+
start { vars: 7 coeffs: 1 }
1285+
end { vars: 8 coeffs: 1 }
12961286
size { vars: 2 coeffs: 1 }
12971287
}
12981288
}
@@ -1325,37 +1315,33 @@ TEST(CpModelTest, TestCumulative) {
13251315
const CpModelProto expected_model = ParseTestProto(R"pb(
13261316
variables { domain: 0 domain: 20 }
13271317
variables { domain: 0 domain: 20 }
1328-
variables { domain: 1 domain: 1 }
13291318
variables { domain: 0 domain: 20 }
13301319
variables { domain: 0 domain: 20 }
13311320
variables { domain: 5 domain: 10 }
13321321
variables { domain: 5 domain: 10 }
13331322
constraints {
1334-
enforcement_literal: 2
13351323
interval {
13361324
start { vars: 0 coeffs: 1 }
13371325
end { vars: 1 coeffs: 1 }
13381326
size { offset: 5 }
13391327
}
13401328
}
13411329
constraints {
1342-
enforcement_literal: 2
13431330
interval {
1344-
start { vars: 3 coeffs: 1 }
1345-
end { vars: 4 coeffs: 1 }
1331+
start { vars: 2 coeffs: 1 }
1332+
end { vars: 3 coeffs: 1 }
13461333
size { offset: 5 }
13471334
}
13481335
}
13491336
constraints {
13501337
cumulative {
1351-
capacity: { vars: 5 coeffs: 1 }
1338+
capacity { vars: 4 coeffs: 1 }
13521339
intervals: 0
13531340
intervals: 1
1354-
demands { vars: 6 coeffs: 1 }
1341+
demands { vars: 5 coeffs: 1 }
13551342
demands { offset: 8 }
13561343
}
1357-
}
1358-
)pb");
1344+
})pb");
13591345
EXPECT_THAT(cp_model.Proto(), EqualsProto(expected_model));
13601346
}
13611347

ortools/sat/cuts.cc

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2063,9 +2063,10 @@ ImpliedBoundsProcessor::ComputeBestImpliedBound(
20632063
// and slack in [0, ub - lb].
20642064
const IntegerValue diff = entry.lower_bound - lb;
20652065
CHECK_GE(diff, 0);
2066-
const double bool_lp_value = entry.is_positive
2067-
? lp_values[entry.literal_view]
2068-
: 1.0 - lp_values[entry.literal_view];
2066+
const double bool_lp_value =
2067+
VariableIsPositive(entry.literal_view)
2068+
? lp_values[entry.literal_view]
2069+
: 1.0 - lp_values[PositiveVariable(entry.literal_view)];
20692070
const double slack_lp_value =
20702071
lp_values[var] - ToDouble(lb) - bool_lp_value * ToDouble(diff);
20712072

@@ -2075,14 +2076,14 @@ ImpliedBoundsProcessor::ComputeBestImpliedBound(
20752076
LinearConstraint ib_cut;
20762077
ib_cut.lb = kMinIntegerValue;
20772078
std::vector<std::pair<IntegerVariable, IntegerValue>> terms;
2078-
if (entry.is_positive) {
2079+
if (VariableIsPositive(entry.literal_view)) {
20792080
// X >= Indicator * (bound - lb) + lb
20802081
terms.push_back({entry.literal_view, diff});
20812082
terms.push_back({var, IntegerValue(-1)});
20822083
ib_cut.ub = -lb;
20832084
} else {
20842085
// X >= -Indicator * (bound - lb) + bound
2085-
terms.push_back({entry.literal_view, -diff});
2086+
terms.push_back({PositiveVariable(entry.literal_view), -diff});
20862087
terms.push_back({var, IntegerValue(-1)});
20872088
ib_cut.ub = -entry.lower_bound;
20882089
}
@@ -2100,7 +2101,6 @@ ImpliedBoundsProcessor::ComputeBestImpliedBound(
21002101
result.var_lp_value = lp_values[var];
21012102
result.bool_lp_value = bool_lp_value;
21022103
result.implied_bound = entry.lower_bound;
2103-
result.is_positive = entry.is_positive;
21042104
result.bool_var = entry.literal_view;
21052105
}
21062106
}
@@ -2153,11 +2153,11 @@ bool ImpliedBoundsProcessor::DecomposeWithImpliedLowerBound(
21532153

21542154
// We have X/-X = info.diff * Boolean + slack.
21552155
bool_term.coeff = term.coeff * bound_diff;
2156-
bool_term.expr_vars[0] = info.bool_var;
2156+
bool_term.expr_vars[0] = PositiveVariable(info.bool_var);
21572157
bool_term.expr_coeffs[1] = 0;
21582158
bool_term.bound_diff = IntegerValue(1);
21592159
bool_term.lp_value = info.bool_lp_value;
2160-
if (info.is_positive) {
2160+
if (VariableIsPositive(info.bool_var)) {
21612161
bool_term.expr_coeffs[0] = IntegerValue(1);
21622162
bool_term.expr_offset = IntegerValue(0);
21632163
} else {

ortools/sat/cuts.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,8 +263,10 @@ class ImpliedBoundsProcessor {
263263
struct BestImpliedBoundInfo {
264264
double var_lp_value = 0.0;
265265
double bool_lp_value = 0.0;
266-
bool is_positive;
267266
IntegerValue implied_bound;
267+
268+
// When VariableIsPositive(bool_var) then it is when this is one that the
269+
// bound is implied. Otherwise it is when this is zero.
268270
IntegerVariable bool_var = kNoIntegerVariable;
269271

270272
double SlackLpValue(IntegerValue lb) const {

ortools/sat/diffn.cc

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,13 @@
2626
#include <vector>
2727

2828
#include "absl/container/flat_hash_set.h"
29+
#include "absl/container/inlined_vector.h"
2930
#include "absl/log/check.h"
3031
#include "absl/log/log.h"
3132
#include "absl/log/vlog_is_on.h"
3233
#include "absl/numeric/bits.h"
3334
#include "absl/types/span.h"
35+
#include "ortools/base/stl_util.h"
3436
#include "ortools/sat/2d_mandatory_overlap_propagator.h"
3537
#include "ortools/sat/2d_orthogonal_packing.h"
3638
#include "ortools/sat/2d_try_edge_propagator.h"
@@ -287,11 +289,11 @@ void AddNonOverlappingRectangles(const std::vector<IntervalVariable>& x,
287289
};
288290

289291
for (int i = 0; i < num_boxes; ++i) {
290-
if (repository->IsOptional(x[i])) continue;
291-
if (repository->IsOptional(y[i])) continue;
292+
if (repository->IsAbsent(x[i])) continue;
293+
if (repository->IsAbsent(y[i])) continue;
292294
for (int j = i + 1; j < num_boxes; ++j) {
293-
if (repository->IsOptional(x[j])) continue;
294-
if (repository->IsOptional(y[j])) continue;
295+
if (repository->IsAbsent(x[j])) continue;
296+
if (repository->IsAbsent(y[j])) continue;
295297

296298
// At most one of these two x options is true.
297299
const Literal x_ij = f(repository->End(x[i]), repository->Start(x[j]));
@@ -314,7 +316,21 @@ void AddNonOverlappingRectangles(const std::vector<IntervalVariable>& x,
314316
}
315317

316318
// At least one of the 4 options is true.
317-
if (!sat_solver->AddProblemClause({x_ij, x_ji, y_ij, y_ji})) {
319+
std::vector<Literal> clause = {x_ij, x_ji, y_ij, y_ji};
320+
if (repository->IsOptional(x[i])) {
321+
clause.push_back(repository->PresenceLiteral(x[i]).Negated());
322+
}
323+
if (repository->IsOptional(y[i])) {
324+
clause.push_back(repository->PresenceLiteral(y[i]).Negated());
325+
}
326+
if (repository->IsOptional(x[j])) {
327+
clause.push_back(repository->PresenceLiteral(x[j]).Negated());
328+
}
329+
if (repository->IsOptional(y[j])) {
330+
clause.push_back(repository->PresenceLiteral(y[j]).Negated());
331+
}
332+
gtl::STLSortAndRemoveDuplicates(&clause);
333+
if (!sat_solver->AddProblemClause(clause)) {
318334
return;
319335
}
320336
}

ortools/sat/fuzz_testdata/EnumerateAllSolutions

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,20 @@ variables {
2020
constraints {
2121
all_diff {
2222
exprs {
23-
vars: [0, 1, 2, 3]
24-
coeffs: [1, 1, 1, 1]
23+
vars: [0]
24+
coeffs: [1]
25+
}
26+
exprs {
27+
vars: [1]
28+
coeffs: [1]
29+
}
30+
exprs {
31+
vars: [2]
32+
coeffs: [1]
33+
}
34+
exprs {
35+
vars: [3]
36+
coeffs: [1]
2537
}
2638
}
2739
}

0 commit comments

Comments
 (0)