OR-Tools  9.3
cp_model_search.cc
Go to the documentation of this file.
1// Copyright 2010-2021 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 <functional>
19#include <limits>
20#include <string>
21#include <utility>
22#include <vector>
23
24#include "absl/container/flat_hash_map.h"
25#include "absl/container/flat_hash_set.h"
26#include "absl/flags/flag.h"
27#include "absl/random/distributions.h"
28#include "absl/strings/str_cat.h"
29#include "absl/strings/string_view.h"
31#include "ortools/sat/cp_model.pb.h"
34#include "ortools/sat/integer.h"
36#include "ortools/sat/model.h"
38#include "ortools/sat/sat_parameters.pb.h"
39#include "ortools/sat/util.h"
41
42// TODO(user): remove this when the code is stable and does not use SCIP
43// anymore.
44ABSL_FLAG(bool, cp_model_use_max_hs, false, "Use max_hs in search portfolio.");
45
46namespace operations_research {
47namespace sat {
48
50 : mapping_(*model->GetOrCreate<CpModelMapping>()),
51 boolean_assignment_(model->GetOrCreate<Trail>()->Assignment()),
52 integer_trail_(*model->GetOrCreate<IntegerTrail>()),
53 integer_encoder_(*model->GetOrCreate<IntegerEncoder>()) {}
54
55int CpModelView::NumVariables() const { return mapping_.NumProtoVariables(); }
56
57bool CpModelView::IsFixed(int var) const {
58 if (mapping_.IsBoolean(var)) {
59 return boolean_assignment_.VariableIsAssigned(
60 mapping_.Literal(var).Variable());
61 } else if (mapping_.IsInteger(var)) {
62 return integer_trail_.IsFixed(mapping_.Integer(var));
63 }
64 return true; // Default.
65}
66
68 return mapping_.IsInteger(var) &&
69 integer_trail_.IsCurrentlyIgnored(mapping_.Integer(var));
70}
71
72int64_t CpModelView::Min(int var) const {
73 if (mapping_.IsBoolean(var)) {
74 const Literal l = mapping_.Literal(var);
75 return boolean_assignment_.LiteralIsTrue(l) ? 1 : 0;
76 } else if (mapping_.IsInteger(var)) {
77 return integer_trail_.LowerBound(mapping_.Integer(var)).value();
78 }
79 return 0; // Default.
80}
81
82int64_t CpModelView::Max(int var) const {
83 if (mapping_.IsBoolean(var)) {
84 const Literal l = mapping_.Literal(var);
85 return boolean_assignment_.LiteralIsFalse(l) ? 0 : 1;
86 } else if (mapping_.IsInteger(var)) {
87 return integer_trail_.UpperBound(mapping_.Integer(var)).value();
88 }
89 return 0; // Default.
90}
91
93 int64_t value) const {
96 if (mapping_.IsBoolean(var)) {
97 DCHECK(value == 0 || value == 1);
98 if (value == 1) {
99 result.boolean_literal_index = mapping_.Literal(var).Index();
100 }
101 } else if (mapping_.IsInteger(var)) {
103 mapping_.Integer(var), IntegerValue(value));
104 }
105 return result;
106}
107
109 int64_t value) const {
110 DCHECK(!IsFixed(var));
112 if (mapping_.IsBoolean(var)) {
113 DCHECK(value == 0 || value == 1);
114 if (value == 0) {
115 result.boolean_literal_index = mapping_.Literal(var).NegatedIndex();
116 }
117 } else if (mapping_.IsInteger(var)) {
119 IntegerValue(value));
120 }
121 return result;
122}
123
125 DCHECK(!IsFixed(var));
127 if (mapping_.IsBoolean(var)) {
128 result.boolean_literal_index = mapping_.Literal(var).NegatedIndex();
129 } else if (mapping_.IsInteger(var)) {
130 const IntegerVariable variable = mapping_.Integer(var);
131 CHECK_NE(variable, kNoIntegerVariable);
132 CHECK(integer_encoder_.VariableIsFullyEncoded(variable));
133 std::vector<ValueLiteralPair> encoding =
134 integer_encoder_.RawDomainEncoding(variable);
135 std::sort(encoding.begin(), encoding.end(),
137 std::vector<Literal> unassigned_sorted_literals;
138 for (const auto& p : encoding) {
139 if (!boolean_assignment_.LiteralIsAssigned(p.literal)) {
140 unassigned_sorted_literals.push_back(p.literal);
141 }
142 }
143 // 5 values -> returns the second.
144 // 4 values -> returns the second too.
145 // Array is 0 based.
146 const int target = (unassigned_sorted_literals.size() + 1) / 2 - 1;
147 result.boolean_literal_index = unassigned_sorted_literals[target].Index();
148 }
149 return result;
150}
151
152// Stores one variable and its strategy value.
153struct VarValue {
154 int ref;
155 int64_t value;
156};
157
158namespace {
159
160// TODO(user): Save this somewhere instead of recomputing it.
161bool ModelHasSchedulingConstraints(const CpModelProto& cp_model_proto) {
162 for (const ConstraintProto& ct : cp_model_proto.constraints()) {
163 if (ct.constraint_case() == ConstraintProto::kNoOverlap) return true;
164 if (ct.constraint_case() == ConstraintProto::kCumulative) return true;
165 }
166 return false;
167}
168
169} // namespace
170
172 const std::vector<DecisionStrategyProto>& strategies, Model* model) {
173 const auto& view = *model->GetOrCreate<CpModelView>();
174 const auto& parameters = *model->GetOrCreate<SatParameters>();
175 auto* random = model->GetOrCreate<ModelRandomGenerator>();
176
177 // Note that we copy strategies to keep the return function validity
178 // independently of the life of the passed vector.
179 return [&view, &parameters, random, strategies]() {
180 for (const DecisionStrategyProto& strategy : strategies) {
181 int candidate;
182 int64_t candidate_value = std::numeric_limits<int64_t>::max();
183
184 // TODO(user): Improve the complexity if this becomes an issue which
185 // may be the case if we do a fixed_search.
186
187 // To store equivalent variables in randomized search.
188 std::vector<VarValue> active_refs;
189
190 int t_index = 0; // Index in strategy.transformations().
191 for (int i = 0; i < strategy.variables().size(); ++i) {
192 const int ref = strategy.variables(i);
193 const int var = PositiveRef(ref);
194 if (view.IsFixed(var) || view.IsCurrentlyFree(var)) continue;
195
196 int64_t coeff(1);
197 int64_t offset(0);
198 while (t_index < strategy.transformations().size() &&
199 strategy.transformations(t_index).index() < i) {
200 ++t_index;
201 }
202 if (t_index < strategy.transformations_size() &&
203 strategy.transformations(t_index).index() == i) {
204 coeff = strategy.transformations(t_index).positive_coeff();
205 offset = strategy.transformations(t_index).offset();
206 }
207
208 // TODO(user): deal with integer overflow in case of wrongly specified
209 // coeff? Note that if this is filled by the presolve it shouldn't
210 // happen since any feasible value in the new variable domain should be
211 // a feasible value of the original variable domain.
212 int64_t value(0);
213 int64_t lb = view.Min(var);
214 int64_t ub = view.Max(var);
215 if (!RefIsPositive(ref)) {
216 lb = -view.Max(var);
217 ub = -view.Min(var);
218 }
219 switch (strategy.variable_selection_strategy()) {
220 case DecisionStrategyProto::CHOOSE_FIRST:
221 break;
222 case DecisionStrategyProto::CHOOSE_LOWEST_MIN:
223 value = coeff * lb + offset;
224 break;
225 case DecisionStrategyProto::CHOOSE_HIGHEST_MAX:
226 value = -(coeff * ub + offset);
227 break;
228 case DecisionStrategyProto::CHOOSE_MIN_DOMAIN_SIZE:
229 value = coeff * (ub - lb + 1);
230 break;
231 case DecisionStrategyProto::CHOOSE_MAX_DOMAIN_SIZE:
232 value = -coeff * (ub - lb + 1);
233 break;
234 default:
235 LOG(FATAL) << "Unknown VariableSelectionStrategy "
236 << strategy.variable_selection_strategy();
237 }
238 if (value < candidate_value) {
239 candidate = ref;
240 candidate_value = value;
241 }
242 if (strategy.variable_selection_strategy() ==
243 DecisionStrategyProto::CHOOSE_FIRST &&
244 !parameters.randomize_search()) {
245 break;
246 } else if (parameters.randomize_search()) {
247 if (value <=
248 candidate_value + parameters.search_randomization_tolerance()) {
249 active_refs.push_back({ref, value});
250 }
251 }
252 }
253
254 if (candidate_value == std::numeric_limits<int64_t>::max()) continue;
255 if (parameters.randomize_search()) {
256 CHECK(!active_refs.empty());
257 const IntegerValue threshold(
258 candidate_value + parameters.search_randomization_tolerance());
259 auto is_above_tolerance = [threshold](const VarValue& entry) {
260 return entry.value > threshold;
261 };
262 // Remove all values above tolerance.
263 active_refs.erase(std::remove_if(active_refs.begin(), active_refs.end(),
264 is_above_tolerance),
265 active_refs.end());
266 const int winner = absl::Uniform<int>(*random, 0, active_refs.size());
267 candidate = active_refs[winner].ref;
268 }
269
270 DecisionStrategyProto::DomainReductionStrategy selection =
271 strategy.domain_reduction_strategy();
272 if (!RefIsPositive(candidate)) {
273 switch (selection) {
274 case DecisionStrategyProto::SELECT_MIN_VALUE:
275 selection = DecisionStrategyProto::SELECT_MAX_VALUE;
276 break;
277 case DecisionStrategyProto::SELECT_MAX_VALUE:
278 selection = DecisionStrategyProto::SELECT_MIN_VALUE;
279 break;
280 case DecisionStrategyProto::SELECT_LOWER_HALF:
281 selection = DecisionStrategyProto::SELECT_UPPER_HALF;
282 break;
283 case DecisionStrategyProto::SELECT_UPPER_HALF:
284 selection = DecisionStrategyProto::SELECT_LOWER_HALF;
285 break;
286 default:
287 break;
288 }
289 }
290
291 const int var = PositiveRef(candidate);
292 const int64_t lb = view.Min(var);
293 const int64_t ub = view.Max(var);
294 switch (selection) {
295 case DecisionStrategyProto::SELECT_MIN_VALUE:
296 return view.LowerOrEqual(var, lb);
297 case DecisionStrategyProto::SELECT_MAX_VALUE:
298 return view.GreaterOrEqual(var, ub);
299 case DecisionStrategyProto::SELECT_LOWER_HALF:
300 return view.LowerOrEqual(var, lb + (ub - lb) / 2);
301 case DecisionStrategyProto::SELECT_UPPER_HALF:
302 return view.GreaterOrEqual(var, ub - (ub - lb) / 2);
303 case DecisionStrategyProto::SELECT_MEDIAN_VALUE:
304 return view.MedianValue(var);
305 default:
306 LOG(FATAL) << "Unknown DomainReductionStrategy "
307 << strategy.domain_reduction_strategy();
308 }
309 }
311 };
312}
313
315 const CpModelProto& cp_model_proto,
316 const std::vector<IntegerVariable>& variable_mapping,
317 IntegerVariable objective_var, Model* model) {
318 std::vector<std::function<BooleanOrIntegerLiteral()>> heuristics;
319
320 // We start by the user specified heuristic.
321 {
322 std::vector<DecisionStrategyProto> strategies;
323 for (const DecisionStrategyProto& proto :
324 cp_model_proto.search_strategy()) {
325 strategies.push_back(proto);
326 }
327 heuristics.push_back(ConstructSearchStrategyInternal(strategies, model));
328 }
329
330 // If there are some scheduling constraint, we complete with a custom
331 // "scheduling" strategy.
332 if (ModelHasSchedulingConstraints(cp_model_proto)) {
333 heuristics.push_back(SchedulingSearchHeuristic(model));
334 }
335
336 // If needed, we finish by instantiating anything left.
337 if (model->GetOrCreate<SatParameters>()->instantiate_all_variables()) {
338 std::vector<IntegerVariable> decisions;
339 for (const IntegerVariable var : variable_mapping) {
340 if (var == kNoIntegerVariable) continue;
341
342 // Make sure we try to fix the objective to its lowest value first.
343 if (var == NegationOf(objective_var)) {
344 decisions.push_back(objective_var);
345 } else {
346 decisions.push_back(var);
347 }
348 }
349 heuristics.push_back(FirstUnassignedVarAtItsMinHeuristic(decisions, model));
350 }
351
352 return SequentialSearch(heuristics);
353}
354
356 const CpModelProto& cp_model_proto,
357 const std::vector<IntegerVariable>& variable_mapping,
358 const std::function<BooleanOrIntegerLiteral()>& instrumented_strategy,
359 Model* model) {
360 std::vector<int> ref_to_display;
361 for (int i = 0; i < cp_model_proto.variables_size(); ++i) {
362 if (variable_mapping[i] == kNoIntegerVariable) continue;
363 if (cp_model_proto.variables(i).name().empty()) continue;
364 ref_to_display.push_back(i);
365 }
366 std::sort(ref_to_display.begin(), ref_to_display.end(), [&](int i, int j) {
367 return cp_model_proto.variables(i).name() <
368 cp_model_proto.variables(j).name();
369 });
370
371 std::vector<std::pair<int64_t, int64_t>> old_domains(variable_mapping.size());
372 return [instrumented_strategy, model, variable_mapping, cp_model_proto,
373 old_domains, ref_to_display]() mutable {
374 const BooleanOrIntegerLiteral decision = instrumented_strategy();
375 if (!decision.HasValue()) return decision;
376
377 if (decision.boolean_literal_index != kNoLiteralIndex) {
378 const Literal l = Literal(decision.boolean_literal_index);
379 LOG(INFO) << "Boolean decision " << l;
380 for (const IntegerLiteral i_lit :
382 LOG(INFO) << " - associated with " << i_lit;
383 }
384 } else {
385 LOG(INFO) << "Integer decision " << decision.integer_literal;
386 }
387 const int level = model->Get<Trail>()->CurrentDecisionLevel();
388 std::string to_display =
389 absl::StrCat("Diff since last call, level=", level, "\n");
390 IntegerTrail* integer_trail = model->GetOrCreate<IntegerTrail>();
391 for (const int ref : ref_to_display) {
392 const IntegerVariable var = variable_mapping[ref];
393 const std::pair<int64_t, int64_t> new_domain(
394 integer_trail->LowerBound(var).value(),
395 integer_trail->UpperBound(var).value());
396 if (new_domain != old_domains[ref]) {
397 absl::StrAppend(&to_display, cp_model_proto.variables(ref).name(), " [",
398 old_domains[ref].first, ",", old_domains[ref].second,
399 "] -> [", new_domain.first, ",", new_domain.second,
400 "]\n");
401 old_domains[ref] = new_domain;
402 }
403 }
404 LOG(INFO) << to_display;
405 return decision;
406 };
407}
408
409// Note: in flatzinc setting, we know we always have a fixed search defined.
410//
411// Things to try:
412// - Specialize for purely boolean problems
413// - Disable linearization_level options for non linear problems
414// - Fast restart in randomized search
415// - Different propatation levels for scheduling constraints
416std::vector<SatParameters> GetDiverseSetOfParameters(
417 const SatParameters& base_params, const CpModelProto& cp_model) {
418 // Defines a set of named strategies so it is easier to read in one place
419 // the one that are used. See below.
420 absl::flat_hash_map<std::string, SatParameters> strategies;
421
422 // The "default" name can be used for the base_params unchanged.
423 strategies["default"] = base_params;
424
425 // Lp variations only.
426 {
427 SatParameters new_params = base_params;
428 new_params.set_linearization_level(0);
429 strategies["no_lp"] = new_params;
430 new_params.set_linearization_level(1);
431 strategies["default_lp"] = new_params;
432 new_params.set_linearization_level(2);
433 new_params.set_add_lp_constraints_lazily(false);
434 strategies["max_lp"] = new_params;
435 }
436
437 // Core. Note that we disable the lp here because it is faster on the minizinc
438 // benchmark.
439 //
440 // TODO(user): Do more experiments, the LP with core could be useful, but we
441 // probably need to incorporate the newly created integer variables from the
442 // core algorithm into the LP.
443 {
444 SatParameters new_params = base_params;
445 new_params.set_search_branching(SatParameters::AUTOMATIC_SEARCH);
446 new_params.set_optimize_with_core(true);
447 new_params.set_linearization_level(0);
448 strategies["core"] = new_params;
449 }
450
451 // It can be interesting to try core and lp.
452 {
453 SatParameters new_params = base_params;
454 new_params.set_search_branching(SatParameters::AUTOMATIC_SEARCH);
455 new_params.set_optimize_with_core(true);
456 new_params.set_linearization_level(1);
457 strategies["core_default_lp"] = new_params;
458 }
459
460 {
461 SatParameters new_params = base_params;
462 new_params.set_search_branching(SatParameters::AUTOMATIC_SEARCH);
463 new_params.set_optimize_with_core(true);
464 new_params.set_linearization_level(2);
465 strategies["core_max_lp"] = new_params;
466 }
467
468 {
469 SatParameters new_params = base_params;
470 new_params.set_search_branching(SatParameters::AUTOMATIC_SEARCH);
471 new_params.set_optimize_with_core(true);
472 new_params.set_optimize_with_max_hs(true);
473 strategies["max_hs"] = new_params;
474 }
475
476 {
477 SatParameters new_params = base_params;
478 new_params.set_optimize_with_lb_tree_search(true);
479 new_params.set_linearization_level(2);
480
481 // We do not want to change the objective_var lb from outside as it gives
482 // better result to only use locally derived reason in that algo.
483 new_params.set_share_objective_bounds(false);
484 strategies["lb_tree_search"] = new_params;
485 }
486
487 {
488 SatParameters new_params = base_params;
489 new_params.set_search_branching(SatParameters::AUTOMATIC_SEARCH);
490 new_params.set_use_probing_search(true);
491 strategies["probing"] = new_params;
492 }
493
494 // Search variation.
495 {
496 SatParameters new_params = base_params;
497 new_params.set_search_branching(SatParameters::AUTOMATIC_SEARCH);
498 strategies["auto"] = new_params;
499
500 new_params.set_search_branching(SatParameters::FIXED_SEARCH);
501 strategies["fixed"] = new_params;
502
503 new_params.set_search_branching(
504 SatParameters::PORTFOLIO_WITH_QUICK_RESTART_SEARCH);
505 strategies["quick_restart"] = new_params;
506
507 new_params.set_search_branching(
508 SatParameters::PORTFOLIO_WITH_QUICK_RESTART_SEARCH);
509 new_params.set_linearization_level(0);
510 strategies["quick_restart_no_lp"] = new_params;
511
512 // We force the max lp here too.
513 new_params.set_linearization_level(2);
514 new_params.set_search_branching(SatParameters::LP_SEARCH);
515 strategies["reduced_costs"] = new_params;
516
517 // For this one, we force other param too.
518 new_params.set_linearization_level(2);
519 new_params.set_search_branching(SatParameters::PSEUDO_COST_SEARCH);
520 new_params.set_exploit_best_solution(true);
521 strategies["pseudo_costs"] = new_params;
522 }
523
524 // Less encoding.
525 {
526 SatParameters new_params = base_params;
527 new_params.set_boolean_encoding_level(0);
528 strategies["less_encoding"] = new_params;
529 }
530
531 // Add user defined ones.
532 for (const SatParameters& params : base_params.subsolver_params()) {
533 strategies[params.name()] = params;
534 }
535
536 // We only use a "fixed search" worker if some strategy is specified or
537 // if we have a scheduling model.
538 //
539 // TODO(user): For scheduling, this is important to find good first solution
540 // but afterwards it is not really great and should probably be replaced by a
541 // LNS worker.
542 const bool use_fixed_strategy = !cp_model.search_strategy().empty() ||
543 ModelHasSchedulingConstraints(cp_model);
544
545 // Our current set of strategies
546 //
547 // TODO(user, fdid): Avoid launching two strategies if they are the same,
548 // like if there is no lp, or everything is already linearized at level 1.
549 std::vector<std::string> names;
550
551 if (base_params.reduce_memory_usage_in_interleave_mode() &&
552 base_params.interleave_search()) {
553 // Low memory mode for interleaved search in single thread.
554 if (cp_model.has_objective()) {
555 names.push_back("default_lp");
556 names.push_back(use_fixed_strategy ? "fixed" : "pseudo_costs");
557 names.push_back(cp_model.objective().vars_size() > 1 ? "core" : "no_lp");
558 names.push_back("max_lp");
559 } else {
560 names.push_back("default_lp");
561 names.push_back(use_fixed_strategy ? "fixed" : "no_lp");
562 names.push_back("less_encoding");
563 names.push_back("max_lp");
564 names.push_back("quick_restart");
565 }
566 } else {
567 // We use the default if empty.
568 if (base_params.subsolvers().empty()) {
569 names.push_back("default_lp");
570 names.push_back("fixed");
571 names.push_back("less_encoding");
572
573 names.push_back("no_lp");
574 names.push_back("max_lp");
575 names.push_back("core");
576
577 names.push_back("reduced_costs");
578 names.push_back("pseudo_costs");
579
580 names.push_back("quick_restart");
581 names.push_back("quick_restart_no_lp");
582 names.push_back("lb_tree_search");
583 names.push_back("probing");
584#if !defined(__PORTABLE_PLATFORM__) && defined(USE_SCIP)
585 if (absl::GetFlag(FLAGS_cp_model_use_max_hs)) names.push_back("max_hs");
586#endif // !defined(__PORTABLE_PLATFORM__) && defined(USE_SCIP)
587 } else {
588 for (const std::string& name : base_params.subsolvers()) {
589 names.push_back(name);
590 }
591 }
592
593 // Remove the names that should be ignored.
594 absl::flat_hash_set<std::string> to_ignore;
595 for (const std::string& name : base_params.ignore_subsolvers()) {
596 to_ignore.insert(name);
597 }
598 int new_size = 0;
599 for (const std::string& name : names) {
600 if (to_ignore.contains(name)) continue;
601 names[new_size++] = name;
602 }
603 names.resize(new_size);
604 }
605
606 // Creates the diverse set of parameters with names and seed.
607 std::vector<SatParameters> result;
608 for (const std::string& name : names) {
609 if (!strategies.contains(name)) {
610 // TODO(user): Check that at parameter validation and return nice error
611 // instead.
612 LOG(WARNING) << "Unknown parameter name '" << name << "'";
613 continue;
614 }
615 SatParameters params = strategies.at(name);
616
617 // Do some filtering.
618 if (!use_fixed_strategy &&
619 params.search_branching() == SatParameters::FIXED_SEARCH) {
620 continue;
621 }
622 if (cp_model.has_objective()) {
623 if (cp_model.objective().vars_size() <= 1 &&
624 params.optimize_with_core()) {
625 continue;
626 }
627 if (name == "less_encoding") continue;
628 } else {
629 if (params.optimize_with_core()) continue;
630 if (params.search_branching() == SatParameters::LP_SEARCH) continue;
631 if (params.search_branching() == SatParameters::PSEUDO_COST_SEARCH) {
632 continue;
633 }
634 }
635
636 // Add this strategy.
637 //
638 // TODO(user): Find a better randomization for the seed so that changing
639 // random_seed() has more impact?
640 params.set_name(name);
641 params.set_random_seed(base_params.random_seed() + result.size() + 1);
642 result.push_back(params);
643 }
644
645 if (cp_model.has_objective()) {
646 // If there is an objective, the extra workers will use LNS.
647 // Make sure we have at least min_num_lns_workers() of them.
648 const int target = std::max(
649 1, base_params.num_workers() - base_params.min_num_lns_workers());
650 if (!base_params.interleave_search() && result.size() > target) {
651 result.resize(target);
652 }
653 } else {
654 // If there is no objective, we complete with randomized fixed search.
655 //
656 // If strategies that do not require a full worker are present, leave one
657 // worker for them.
658 int target = base_params.num_workers();
659 if (!base_params.interleave_search() &&
660 (base_params.use_rins_lns() || base_params.use_relaxation_lns() ||
661 base_params.use_feasibility_pump())) {
662 target = std::max(1, base_params.num_workers() - 1);
663 }
664 if (!base_params.interleave_search() && result.size() > target) {
665 result.resize(target);
666 }
667
668 int index = 1;
669 while (result.size() < target) {
670 // TODO(user): This doesn't make sense if there is no fixed search.
671 SatParameters new_params = base_params;
672 new_params.set_search_branching(SatParameters::FIXED_SEARCH);
673 new_params.set_randomize_search(true);
674 new_params.set_search_randomization_tolerance(index);
675 new_params.set_random_seed(base_params.random_seed() + result.size() + 1);
676 new_params.set_name(absl::StrCat("random_", index));
677 result.push_back(new_params);
678 ++index;
679 }
680 }
681
682 return result;
683}
684
685} // namespace sat
686} // namespace operations_research
int64_t max
Definition: alldiff_cst.cc:140
#define CHECK(condition)
Definition: base/logging.h:495
#define CHECK_NE(val1, val2)
Definition: base/logging.h:704
#define LOG(severity)
Definition: base/logging.h:420
#define DCHECK(condition)
Definition: base/logging.h:890
An Assignment is a variable -> domains mapping, used to report solutions to the user.
IntegerVariable Integer(int ref) const
sat::Literal Literal(int ref) const
BooleanOrIntegerLiteral GreaterOrEqual(int var, int64_t value) const
BooleanOrIntegerLiteral MedianValue(int var) const
BooleanOrIntegerLiteral LowerOrEqual(int var, int64_t value) const
const InlinedIntegerLiteralVector & GetAllIntegerLiterals(Literal lit) const
Definition: integer.h:479
bool VariableIsFullyEncoded(IntegerVariable var) const
Definition: integer.cc:96
std::vector< ValueLiteralPair > RawDomainEncoding(IntegerVariable var) const
Definition: integer.cc:167
bool IsCurrentlyIgnored(IntegerVariable i) const
Definition: integer.h:705
bool IsFixed(IntegerVariable i) const
Definition: integer.h:1453
IntegerValue UpperBound(IntegerVariable i) const
Definition: integer.h:1449
IntegerValue LowerBound(IntegerVariable i) const
Definition: integer.h:1445
LiteralIndex NegatedIndex() const
Definition: sat_base.h:88
LiteralIndex Index() const
Definition: sat_base.h:87
BooleanVariable Variable() const
Definition: sat_base.h:83
Class that owns everything related to a particular optimization model.
Definition: sat/model.h:42
bool LiteralIsAssigned(Literal literal) const
Definition: sat_base.h:156
bool VariableIsAssigned(BooleanVariable var) const
Definition: sat_base.h:161
bool LiteralIsTrue(Literal literal) const
Definition: sat_base.h:153
bool LiteralIsFalse(Literal literal) const
Definition: sat_base.h:150
SatParameters parameters
CpModelProto proto
ABSL_FLAG(bool, cp_model_use_max_hs, false, "Use max_hs in search portfolio.")
const std::string name
const Constraint * ct
int64_t value
IntVar * var
Definition: expr_array.cc:1874
GRBmodel * model
int index
const int WARNING
Definition: log_severity.h:31
const int INFO
Definition: log_severity.h:31
const int FATAL
Definition: log_severity.h:32
const std::function< BooleanOrIntegerLiteral()> ConstructSearchStrategyInternal(const std::vector< DecisionStrategyProto > &strategies, Model *model)
std::function< BooleanOrIntegerLiteral()> FirstUnassignedVarAtItsMinHeuristic(const std::vector< IntegerVariable > &vars, Model *model)
bool RefIsPositive(int ref)
std::function< BooleanOrIntegerLiteral()> SequentialSearch(std::vector< std::function< BooleanOrIntegerLiteral()> > heuristics)
const LiteralIndex kNoLiteralIndex(-1)
const IntegerVariable kNoIntegerVariable(-1)
std::function< BooleanOrIntegerLiteral()> SchedulingSearchHeuristic(Model *model)
std::vector< SatParameters > GetDiverseSetOfParameters(const SatParameters &base_params, const CpModelProto &cp_model)
std::vector< IntegerVariable > NegationOf(const std::vector< IntegerVariable > &vars)
Definition: integer.cc:47
std::function< BooleanOrIntegerLiteral()> ConstructSearchStrategy(const CpModelProto &cp_model_proto, const std::vector< IntegerVariable > &variable_mapping, IntegerVariable objective_var, Model *model)
std::function< BooleanOrIntegerLiteral()> InstrumentSearchStrategy(const CpModelProto &cp_model_proto, const std::vector< IntegerVariable > &variable_mapping, const std::function< BooleanOrIntegerLiteral()> &instrumented_strategy, Model *model)
Collection of objects used to extend the Constraint Solver library.
static IntegerLiteral LowerOrEqual(IntegerVariable i, IntegerValue bound)
Definition: integer.h:1393
static IntegerLiteral GreaterOrEqual(IntegerVariable i, IntegerValue bound)
Definition: integer.h:1387
const double coeff