Skip to content

Commit c292221

Browse files
committed
[CP-SAT] experiment with prefered linearization_level in lns; fuzzer bugs fixed
1 parent fe838d0 commit c292221

File tree

5 files changed

+45
-24
lines changed

5 files changed

+45
-24
lines changed

ortools/sat/cp_model_copy.cc

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,9 @@ bool ModelCopy::ImportAndSimplifyConstraints(
119119
}
120120
break;
121121
case ConstraintProto::kLinear:
122-
if (!CopyLinear(ct)) return CreateUnsatModel(c, ct);
122+
if (!CopyLinear(ct, /*canonicalize=*/first_copy)) {
123+
return CreateUnsatModel(c, ct);
124+
}
123125
break;
124126
case ConstraintProto::kIntProd:
125127
if (!CopyIntProd(ct, ignore_names)) return CreateUnsatModel(c, ct);
@@ -407,8 +409,9 @@ bool ModelCopy::CopyBoolAndWithDupSupport(const ConstraintProto& ct) {
407409
return true;
408410
}
409411

410-
bool ModelCopy::CopyLinearExpression(const LinearExpressionProto& expr,
411-
LinearExpressionProto* dst) {
412+
bool ModelCopy::CopyLinearExpression(
413+
const LinearExpressionProto& expr, LinearExpressionProto* dst,
414+
absl::Span<const int> enforcement_literals) {
412415
non_fixed_variables_.clear();
413416
non_fixed_coefficients_.clear();
414417
int64_t offset = expr.offset();
@@ -436,10 +439,13 @@ bool ModelCopy::CopyLinearExpression(const LinearExpressionProto& expr,
436439
non_fixed_variables_.end());
437440
dst->mutable_coeffs()->Add(non_fixed_coefficients_.begin(),
438441
non_fixed_coefficients_.end());
442+
// TODO(user): We could save work by only doing this if this is the first
443+
// copy.
444+
context_->CanonicalizeLinearExpression(enforcement_literals, dst);
439445
return true;
440446
}
441447

442-
bool ModelCopy::CopyLinear(const ConstraintProto& ct) {
448+
bool ModelCopy::CopyLinear(const ConstraintProto& ct, bool canonicalize) {
443449
non_fixed_variables_.clear();
444450
non_fixed_coefficients_.clear();
445451
int64_t offset = 0;
@@ -516,6 +522,9 @@ bool ModelCopy::CopyLinear(const ConstraintProto& ct) {
516522
linear->mutable_coeffs()->Add(non_fixed_coefficients_.begin(),
517523
non_fixed_coefficients_.end());
518524
FillDomainInProto(tight_domain, linear);
525+
if (canonicalize) {
526+
context_->CanonicalizeLinearConstraint(new_ct);
527+
}
519528
return true;
520529
}
521530

@@ -708,11 +717,14 @@ bool ModelCopy::CopyInterval(const ConstraintProto& ct, int c,
708717
}
709718
*new_ct->mutable_enforcement_literal() = ct.enforcement_literal();
710719
CopyLinearExpression(ct.interval().start(),
711-
new_ct->mutable_interval()->mutable_start());
720+
new_ct->mutable_interval()->mutable_start(),
721+
ct.enforcement_literal());
712722
CopyLinearExpression(ct.interval().size(),
713-
new_ct->mutable_interval()->mutable_size());
723+
new_ct->mutable_interval()->mutable_size(),
724+
ct.enforcement_literal());
714725
CopyLinearExpression(ct.interval().end(),
715-
new_ct->mutable_interval()->mutable_end());
726+
new_ct->mutable_interval()->mutable_end(),
727+
ct.enforcement_literal());
716728
return true;
717729
}
718730

@@ -778,10 +790,10 @@ bool ModelCopy::AddLinearConstraintForInterval(const ConstraintProto& ct) {
778790
AddLinearExpressionToLinearConstraint(itv.start(), 1, mutable_linear);
779791
AddLinearExpressionToLinearConstraint(itv.size(), 1, mutable_linear);
780792
AddLinearExpressionToLinearConstraint(itv.end(), -1, mutable_linear);
781-
if (!CopyLinear(tmp_constraint_)) return false;
793+
if (!CopyLinear(tmp_constraint_, true)) return false;
782794
}
783795

784-
// An enforced interval must have is size non-negative.
796+
// An enforced interval must have its size non-negative.
785797
const LinearExpressionProto& size_expr = itv.size();
786798
if (context_->MinOf(size_expr) < 0) {
787799
tmp_constraint_.Clear();
@@ -791,7 +803,7 @@ bool ModelCopy::AddLinearConstraintForInterval(const ConstraintProto& ct) {
791803
tmp_constraint_.mutable_linear()->add_domain(-size_expr.offset());
792804
tmp_constraint_.mutable_linear()->add_domain(
793805
std::numeric_limits<int64_t>::max());
794-
if (!CopyLinear(tmp_constraint_)) return false;
806+
if (!CopyLinear(tmp_constraint_, true)) return false;
795807
}
796808

797809
return true;

ortools/sat/cp_model_copy.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,10 @@ class ModelCopy {
9090
bool CopyIntProd(const ConstraintProto& ct, bool ignore_names);
9191
bool CopyIntDiv(const ConstraintProto& ct, bool ignore_names);
9292
bool CopyIntMod(const ConstraintProto& ct, bool ignore_names);
93-
bool CopyLinear(const ConstraintProto& ct);
93+
bool CopyLinear(const ConstraintProto& ct, bool canonicalize);
9494
bool CopyLinearExpression(const LinearExpressionProto& expr,
95-
LinearExpressionProto* dst);
95+
LinearExpressionProto* dst,
96+
absl::Span<const int> enforcement_literals = {});
9697
bool CopyAutomaton(const ConstraintProto& ct);
9798
bool CopyTable(const ConstraintProto& ct);
9899
bool CopyAllDiff(const ConstraintProto& ct);

ortools/sat/cp_model_presolve.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5866,8 +5866,8 @@ bool CpModelPresolver::PresolveNoOverlap2DFramed(
58665866
// Something can be outside of the frame.
58675867
return false;
58685868
}
5869-
if (2 * box.bounding_area.SizeX() <= framed_region.SizeX() ||
5870-
2 * box.bounding_area.SizeY() <= framed_region.SizeY()) {
5869+
if (2 * box.x_size <= framed_region.SizeX() ||
5870+
2 * box.y_size <= framed_region.SizeY()) {
58715871
// We can fit two boxes in the delimited space between the fixed boxes, so
58725872
// we cannot replace it by an at-most-one.
58735873
return false;

ortools/sat/cp_model_solver.cc

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1192,8 +1192,10 @@ class LnsSolver : public SubSolver {
11921192
public:
11931193
LnsSolver(std::unique_ptr<NeighborhoodGenerator> generator,
11941194
const SatParameters& lns_parameters,
1195-
NeighborhoodGeneratorHelper* helper, SharedClasses* shared)
1195+
NeighborhoodGeneratorHelper* helper, SharedClasses* shared,
1196+
int preferred_linearization_level = 0)
11961197
: SubSolver(generator->name(), INCOMPLETE),
1198+
preferred_linearization_level_(preferred_linearization_level),
11971199
generator_(std::move(generator)),
11981200
helper_(helper),
11991201
lns_parameters_(lns_parameters),
@@ -1274,13 +1276,13 @@ class LnsSolver : public SubSolver {
12741276
// TODO(user): Tune these.
12751277
// TODO(user): This could be a good candidate for bandits.
12761278
const int64_t stall = generator_->num_consecutive_non_improving_calls();
1279+
std::string search_info;
12771280
const int search_index = stall < 10 ? 0 : task_id % 2;
1278-
absl::string_view search_info;
12791281
switch (search_index) {
12801282
case 0:
12811283
local_params.set_search_branching(SatParameters::AUTOMATIC_SEARCH);
1282-
local_params.set_linearization_level(0);
1283-
search_info = "auto_l0";
1284+
local_params.set_linearization_level(preferred_linearization_level_);
1285+
search_info = absl::StrCat("auto_l", preferred_linearization_level_);
12841286
break;
12851287
default:
12861288
local_params.set_search_branching(SatParameters::PORTFOLIO_SEARCH);
@@ -1616,6 +1618,7 @@ class LnsSolver : public SubSolver {
16161618
}
16171619

16181620
private:
1621+
int preferred_linearization_level_ = 0;
16191622
std::unique_ptr<NeighborhoodGenerator> generator_;
16201623
NeighborhoodGeneratorHelper* helper_;
16211624
const SatParameters lns_parameters_;
@@ -1881,6 +1884,9 @@ void SolveCpModelParallel(SharedClasses* shared, Model* global_model) {
18811884
}
18821885
}
18831886

1887+
// For routing, the LP relaxation seems pretty important, so we prefer an
1888+
// high linearization level to solve LNS subproblems.
1889+
const int routing_lin_level = 2;
18841890
const int num_circuit = static_cast<int>(
18851891
helper->TypeToConstraints(ConstraintProto::kCircuit).size());
18861892
const int num_routes = static_cast<int>(
@@ -1890,21 +1896,21 @@ void SolveCpModelParallel(SharedClasses* shared, Model* global_model) {
18901896
reentrant_interleaved_subsolvers.push_back(std::make_unique<LnsSolver>(
18911897
std::make_unique<RoutingRandomNeighborhoodGenerator>(
18921898
helper, name_filter.LastName()),
1893-
lns_params, helper, shared));
1899+
lns_params, helper, shared, routing_lin_level));
18941900
}
18951901
if (name_filter.Keep("routing_path_lns")) {
18961902
reentrant_interleaved_subsolvers.push_back(std::make_unique<LnsSolver>(
18971903
std::make_unique<RoutingPathNeighborhoodGenerator>(
18981904
helper, name_filter.LastName()),
1899-
lns_params, helper, shared));
1905+
lns_params, helper, shared, routing_lin_level));
19001906
}
19011907
}
19021908
if (num_routes > 0 || num_circuit > 1) {
19031909
if (name_filter.Keep("routing_full_path_lns")) {
19041910
reentrant_interleaved_subsolvers.push_back(std::make_unique<LnsSolver>(
19051911
std::make_unique<RoutingFullPathNeighborhoodGenerator>(
19061912
helper, name_filter.LastName()),
1907-
lns_params, helper, shared));
1913+
lns_params, helper, shared, routing_lin_level));
19081914
}
19091915
}
19101916
}

ortools/sat/linear_relaxation.cc

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1056,10 +1056,12 @@ void AppendNoOverlap2dRelaxation(const ConstraintProto& ct, Model* model,
10561056
intervals_repository->IsPresent(x_intervals[i])
10571057
? intervals_repository->PresenceLiteral(y_intervals[i])
10581058
: intervals_repository->PresenceLiteral(x_intervals[i]);
1059-
const IntegerValue area_min =
1060-
integer_trail->LevelZeroLowerBound(x_sizes[i]) *
1059+
const IntegerValue x_size =
1060+
integer_trail->LevelZeroLowerBound(x_sizes[i]);
1061+
const IntegerValue y_size =
10611062
integer_trail->LevelZeroLowerBound(y_sizes[i]);
1062-
if (area_min > 0) {
1063+
if (x_size > 0 && y_size > 0) {
1064+
const IntegerValue area_min = x_size * y_size;
10631065
// Note that intervals that must be absent can have negative sizes.
10641066
// Not including the term if we don't have a view is ok.
10651067
(void)lc.AddLiteralTerm(presence_literal, area_min);

0 commit comments

Comments
 (0)