diff --git a/ortools/sat/BUILD.bazel b/ortools/sat/BUILD.bazel index a9bcbc3534..af49ba4534 100644 --- a/ortools/sat/BUILD.bazel +++ b/ortools/sat/BUILD.bazel @@ -253,6 +253,7 @@ cc_library( ":cp_model_search", ":sat_parameters_cc_proto", "@com_google_absl//absl/strings", + "@com_google_protobuf//:protobuf", ], ) @@ -280,6 +281,7 @@ cc_library( "@com_google_absl//absl/log:check", "@com_google_absl//absl/random:distributions", "@com_google_absl//absl/strings", + "@com_google_protobuf//:protobuf", ], ) @@ -1210,6 +1212,7 @@ cc_library( "@com_google_absl//absl/algorithm:container", "@com_google_absl//absl/log", "@com_google_absl//absl/log:check", + "@com_google_absl//absl/types:span", ], ) diff --git a/ortools/sat/cp_model_search.cc b/ortools/sat/cp_model_search.cc index 401a81379a..ca0198d5f6 100644 --- a/ortools/sat/cp_model_search.cc +++ b/ortools/sat/cp_model_search.cc @@ -28,6 +28,7 @@ #include "absl/random/distributions.h" #include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" +#include "google/protobuf/text_format.h" #include "ortools/base/logging.h" #include "ortools/sat/cp_model.pb.h" #include "ortools/sat/cp_model_mapping.h" @@ -916,6 +917,13 @@ std::vector GetWorkSharingParams( if (!cp_model.assumptions().empty()) return result; if (num_params_to_generate <= 0) return result; int num_workers = 0; + + SatParameters extra_params; + if (!base_params.shared_tree_extra_parameters_as_string().empty()) { + CHECK(google::protobuf::TextFormat::ParseFromString( + base_params.shared_tree_extra_parameters_as_string(), &extra_params)); + } + while (result.size() < num_params_to_generate) { // TODO(user): Make the base parameters configurable. SatParameters new_params = base_params; @@ -931,6 +939,8 @@ std::vector GetWorkSharingParams( new_params.set_optimize_with_lb_tree_search(false); new_params.set_optimize_with_max_hs(false); + new_params.MergeFrom(extra_params); + std::string lp_tags[] = {"no", "default", "max"}; absl::StrAppend(&name, lp_tags[std::min(new_params.linearization_level(), 2)], diff --git a/ortools/sat/cp_model_solver.cc b/ortools/sat/cp_model_solver.cc index 5efad4a775..be438e2c7d 100644 --- a/ortools/sat/cp_model_solver.cc +++ b/ortools/sat/cp_model_solver.cc @@ -3885,9 +3885,9 @@ CpSolverResponse SolveCpModel(const CpModelProto& model_proto, Model* model) { // large messages. google::protobuf::Arena arena; CpModelProto* new_cp_model_proto = - google::protobuf::Arena::CreateMessage(&arena); + google::protobuf::Arena::Create(&arena); CpModelProto* mapping_proto = - google::protobuf::Arena::CreateMessage(&arena); + google::protobuf::Arena::Create(&arena); auto context = std::make_unique(model, new_cp_model_proto, mapping_proto); diff --git a/ortools/sat/diffn_cuts.cc b/ortools/sat/diffn_cuts.cc index 9e133b2cea..10b49b9289 100644 --- a/ortools/sat/diffn_cuts.cc +++ b/ortools/sat/diffn_cuts.cc @@ -136,7 +136,7 @@ struct DiffnEnergyEvent : DiffnBaseEvent { }; void GenerateNoOverlap2dEnergyCut( - const std::vector>& energies, + absl::Span> energies, absl::Span rectangles, absl::string_view cut_name, Model* model, LinearConstraintManager* manager, SchedulingConstraintHelper* x_helper, SchedulingConstraintHelper* y_helper, diff --git a/ortools/sat/diffn_util.cc b/ortools/sat/diffn_util.cc index 9922ce3b96..3ef304e03d 100644 --- a/ortools/sat/diffn_util.cc +++ b/ortools/sat/diffn_util.cc @@ -49,8 +49,7 @@ bool Rectangle::IsDisjoint(const Rectangle& other) const { } std::vector> GetOverlappingRectangleComponents( - const std::vector& rectangles, - absl::Span active_rectangles) { + absl::Span rectangles, absl::Span active_rectangles) { if (active_rectangles.empty()) return {}; std::vector> result; @@ -174,8 +173,8 @@ bool BoxesAreInEnergyConflict(const std::vector& rectangles, } bool AnalyzeIntervals(bool transpose, absl::Span local_boxes, - const std::vector& rectangles, - const std::vector& rectangle_energies, + absl::Span rectangles, + absl::Span rectangle_energies, IntegerValue* x_threshold, IntegerValue* y_threshold, Rectangle* conflict) { // First, we compute the possible x_min values (removing duplicates). @@ -326,7 +325,7 @@ bool AnalyzeIntervals(bool transpose, absl::Span local_boxes, } absl::Span FilterBoxesAndRandomize( - const std::vector& cached_rectangles, absl::Span boxes, + absl::Span cached_rectangles, absl::Span boxes, IntegerValue threshold_x, IntegerValue threshold_y, absl::BitGenRef random) { size_t new_size = 0; @@ -581,8 +580,8 @@ void AppendPairwiseRestrictions( } void AppendPairwiseRestrictions( - const std::vector& items, - const std::vector& other_items, + absl::Span items, + absl::Span other_items, std::vector* result) { for (int i1 = 0; i1 < items.size(); ++i1) { for (int i2 = 0; i2 < other_items.size(); ++i2) { diff --git a/ortools/sat/diffn_util.h b/ortools/sat/diffn_util.h index 227163f761..9b6c351347 100644 --- a/ortools/sat/diffn_util.h +++ b/ortools/sat/diffn_util.h @@ -113,8 +113,7 @@ inline IntegerValue Rectangle::IntersectArea(const Rectangle& other) const { // This method removes all singleton components. It will modify the // active_rectangle span in place. std::vector> GetOverlappingRectangleComponents( - const std::vector& rectangles, - absl::Span active_rectangles); + absl::Span rectangles, absl::Span active_rectangles); // Visible for testing. The algo is in O(n^4) so shouldn't be used directly. // Returns true if there exist a bounding box with too much energy. @@ -142,8 +141,8 @@ bool ReportEnergyConflict(Rectangle bounding_box, absl::Span boxes, // // If transpose is true, we analyze the relevant Y intervals instead. bool AnalyzeIntervals(bool transpose, absl::Span boxes, - const std::vector& rectangles, - const std::vector& rectangle_energies, + absl::Span rectangles, + absl::Span rectangle_energies, IntegerValue* x_threshold, IntegerValue* y_threshold, Rectangle* conflict = nullptr); @@ -151,7 +150,7 @@ bool AnalyzeIntervals(bool transpose, absl::Span boxes, // Because we rely on various heuristic, this allow to change the order from // one call to the next. absl::Span FilterBoxesAndRandomize( - const std::vector& cached_rectangles, absl::Span boxes, + absl::Span cached_rectangles, absl::Span boxes, IntegerValue threshold_x, IntegerValue threshold_y, absl::BitGenRef random); // Given the total energy of all rectangles (sum of energies[box]) we know that @@ -254,8 +253,8 @@ void AppendPairwiseRestrictions( // Same as above, but test `items` against `other_items` and append the // restrictions found to `result`. void AppendPairwiseRestrictions( - const std::vector& items, - const std::vector& other_items, + absl::Span items, + absl::Span other_items, std::vector* result); // This class is used by the no_overlap_2d constraint to maintain the envelope diff --git a/ortools/sat/disjunctive.cc b/ortools/sat/disjunctive.cc index 39e4340f83..13ee11f025 100644 --- a/ortools/sat/disjunctive.cc +++ b/ortools/sat/disjunctive.cc @@ -19,6 +19,7 @@ #include "absl/algorithm/container.h" #include "absl/log/check.h" +#include "absl/types/span.h" #include "ortools/base/logging.h" #include "ortools/sat/all_different.h" #include "ortools/sat/integer.h" @@ -321,7 +322,7 @@ CombinedDisjunctive::CombinedDisjunctive(Model* model) template void CombinedDisjunctive::AddNoOverlap( - const std::vector& vars) { + absl::Span vars) { const int index = task_sets_.size(); task_sets_.emplace_back(vars.size()); end_mins_.push_back(kMinIntegerValue); diff --git a/ortools/sat/disjunctive.h b/ortools/sat/disjunctive.h index c1328cf986..9ee6863723 100644 --- a/ortools/sat/disjunctive.h +++ b/ortools/sat/disjunctive.h @@ -19,6 +19,7 @@ #include #include +#include "absl/types/span.h" #include "ortools/base/macros.h" #include "ortools/sat/integer.h" #include "ortools/sat/intervals.h" @@ -196,7 +197,7 @@ class CombinedDisjunctive : public PropagatorInterface { // After creation, this must be called for all the disjunctive constraints // in the model. - void AddNoOverlap(const std::vector& var); + void AddNoOverlap(absl::Span var); bool Propagate() final; diff --git a/ortools/sat/linear_relaxation.cc b/ortools/sat/linear_relaxation.cc index 3a252ea20a..24decff7ed 100644 --- a/ortools/sat/linear_relaxation.cc +++ b/ortools/sat/linear_relaxation.cc @@ -829,7 +829,7 @@ void AddCumulativeRelaxation(const AffineExpression& capacity, for (int index = 0; index < num_intervals; ++index) { if (helper->IsAbsent(index)) continue; if (helper->IsOptional(index)) { - if (demands_helper->EnergyMin(index) >= 0) { + if (demands_helper->EnergyMin(index) > 0) { num_optionals++; } else { continue; @@ -1230,8 +1230,13 @@ void AppendLinearConstraintRelaxation(const ConstraintProto& ct, if (!linearize_enforced_constraints) return; // We linearize fully reified constraints of size 1 all together for a given - // variable. But we need to process half-reified ones. - if (!mapping->IsHalfEncodingConstraint(&ct) && ct.linear().vars_size() <= 1) { + // variable. But we need to process half-reified ones or constraint with + // more than one enforcement. + // + // TODO(user): Use cleaner "already loaded" logic, and mark as such constraint + // already encoded by code like AppendRelaxationForEqualityEncoding(). + if (!mapping->IsHalfEncodingConstraint(&ct) && ct.linear().vars_size() <= 1 && + ct.enforcement_literal().size() <= 1) { return; } diff --git a/ortools/sat/parameters_validation.cc b/ortools/sat/parameters_validation.cc index 5d46526df0..595da7fce4 100644 --- a/ortools/sat/parameters_validation.cc +++ b/ortools/sat/parameters_validation.cc @@ -21,6 +21,7 @@ #include #include "absl/strings/str_cat.h" +#include "google/protobuf/text_format.h" #include "ortools/sat/cp_model_search.h" #include "ortools/sat/sat_parameters.pb.h" @@ -171,6 +172,14 @@ std::string ValidateParameters(const SatParameters& params) { return "use_shared_tree_search must only be set on workers' parameters"; } + if (!params.shared_tree_extra_parameters_as_string().empty()) { + SatParameters extra_params; + if (!google::protobuf::TextFormat::ParseFromString( + params.shared_tree_extra_parameters_as_string(), &extra_params)) { + return "cannot parse shared_tree_extra_parameters_as_string parameter"; + } + } + if (params.enumerate_all_solutions() && params.interleave_search()) { return "Enumerating all solutions does not work with interleaved search"; } diff --git a/ortools/sat/sat_parameters.proto b/ortools/sat/sat_parameters.proto index d7a09e5b0e..85fcc9f580 100644 --- a/ortools/sat/sat_parameters.proto +++ b/ortools/sat/sat_parameters.proto @@ -23,7 +23,7 @@ option csharp_namespace = "Google.OrTools.Sat"; // Contains the definitions for all the sat algorithm parameters and their // default values. // -// NEXT TAG: 279 +// NEXT TAG: 281 message SatParameters { // In some context, like in a portfolio of search, it makes sense to name a // given parameters set for logging purpose. @@ -1042,6 +1042,8 @@ message SatParameters { optional SharedTreeSplitStrategy shared_tree_split_strategy = 239 [default = SPLIT_STRATEGY_AUTO]; + optional string shared_tree_extra_parameters_as_string = 280 [default = ""]; + // Whether we enumerate all solutions of a problem without objective. Note // that setting this to true automatically disable some presolve reduction // that can remove feasible solution. That is it has the same effect as diff --git a/ortools/sat/sat_runner.cc b/ortools/sat/sat_runner.cc index ba6f0d3f99..0e19d7a042 100644 --- a/ortools/sat/sat_runner.cc +++ b/ortools/sat/sat_runner.cc @@ -152,7 +152,7 @@ int Run() { // Read the problem. google::protobuf::Arena arena; CpModelProto* cp_model = - google::protobuf::Arena::CreateMessage(&arena); + google::protobuf::Arena::Create(&arena); if (!LoadProblem(absl::GetFlag(FLAGS_input), absl::GetFlag(FLAGS_hint_file), cp_model)) { CpSolverResponse response;