OR-Tools  9.3
synchronization.h
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
14#ifndef OR_TOOLS_SAT_SYNCHRONIZATION_H_
15#define OR_TOOLS_SAT_SYNCHRONIZATION_H_
16
17#include <cstdint>
18#include <deque>
19#include <functional>
20#include <limits>
21#include <string>
22#include <utility>
23#include <vector>
24
25#include "absl/base/thread_annotations.h"
26#include "absl/container/btree_map.h"
27#include "absl/container/flat_hash_map.h"
28#include "absl/container/flat_hash_set.h"
29#include "absl/random/bit_gen_ref.h"
30#include "absl/random/random.h"
31#include "absl/synchronization/mutex.h"
32#include "absl/time/time.h"
36#include "ortools/base/timer.h"
37#include "ortools/sat/cp_model.pb.h"
38#include "ortools/sat/integer.h"
39#include "ortools/sat/model.h"
41#include "ortools/sat/sat_parameters.pb.h"
42#include "ortools/sat/util.h"
43#include "ortools/util/bitset.h"
46
47namespace operations_research {
48namespace sat {
49
50// Thread-safe. Keeps a set of n unique best solution found so far.
51//
52// TODO(user): Maybe add some criteria to only keep solution with an objective
53// really close to the best solution.
54template <typename ValueType>
56 public:
57 explicit SharedSolutionRepository(int num_solutions_to_keep)
58 : num_solutions_to_keep_(num_solutions_to_keep) {
60 }
61
62 // The solution format used by this class.
63 struct Solution {
64 // Solution with lower "rank" will be preferred
65 //
66 // TODO(user): Some LNS code assume that for the SharedSolutionRepository
67 // this rank is actually the unscaled internal minimization objective.
68 // Remove this assumptions by simply recomputing this value since it is not
69 // too costly to do so.
70 int64_t rank = 0;
71
72 std::vector<ValueType> variable_values;
73
74 // Number of time this was returned by GetRandomBiasedSolution(). We use
75 // this information during the selection process.
76 //
77 // Should be private: only SharedSolutionRepository should modify this.
78 mutable int num_selected = 0;
79
80 bool operator==(const Solution& other) const {
81 return rank == other.rank && variable_values == other.variable_values;
82 }
83 bool operator<(const Solution& other) const {
84 if (rank != other.rank) {
85 return rank < other.rank;
86 }
87 return variable_values < other.variable_values;
88 }
89 };
90
91 // Returns the number of current solution in the pool. This will never
92 // decrease.
93 int NumSolutions() const;
94
95 // Returns the solution #i where i must be smaller than NumSolutions().
96 Solution GetSolution(int index) const;
97
98 // Returns the variable value of variable 'var_index' from solution
99 // 'solution_index' where solution_index must be smaller than NumSolutions()
100 // and 'var_index' must be smaller than number of variables.
101 ValueType GetVariableValueInSolution(int var_index, int solution_index) const;
102
103 // Returns a random solution biased towards good solutions.
104 Solution GetRandomBiasedSolution(absl::BitGenRef random) const;
105
106 // Add a new solution. Note that it will not be added to the pool of solution
107 // right away. One must call Synchronize for this to happen.
108 //
109 // Works in O(num_solutions_to_keep_).
110 void Add(const Solution& solution);
111
112 // Updates the current pool of solution with the one recently added. Note that
113 // we use a stable ordering of solutions, so the final pool will be
114 // independent on the order of the calls to AddSolution() provided that the
115 // set of added solutions is the same.
116 //
117 // Works in O(num_solutions_to_keep_).
119
120 protected:
121 // Helper method for adding the solutions once the mutex is acquired.
122 void AddInternal(const Solution& solution)
123 ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
124
126 mutable absl::Mutex mutex_;
127 int64_t num_synchronization_ ABSL_GUARDED_BY(mutex_) = 0;
128
129 // Our two solutions pools, the current one and the new one that will be
130 // merged into the current one on each Synchronize() calls.
131 mutable std::vector<int> tmp_indices_ ABSL_GUARDED_BY(mutex_);
132 std::vector<Solution> solutions_ ABSL_GUARDED_BY(mutex_);
133 std::vector<Solution> new_solutions_ ABSL_GUARDED_BY(mutex_);
134};
135
136// This is currently only used to store feasible solution from our 'relaxation'
137// LNS generators which in turn are used to generate some RINS neighborhood.
139 : public SharedSolutionRepository<int64_t> {
140 public:
141 explicit SharedRelaxationSolutionRepository(int num_solutions_to_keep)
142 : SharedSolutionRepository<int64_t>(num_solutions_to_keep) {}
143
144 void NewRelaxationSolution(const CpSolverResponse& response);
145};
146
148 public:
149 explicit SharedLPSolutionRepository(int num_solutions_to_keep)
150 : SharedSolutionRepository<double>(num_solutions_to_keep) {}
151
152 void NewLPSolution(std::vector<double> lp_solution);
153};
154
155// Set of partly filled solutions. They are meant to be finished by some lns
156// worker.
157//
158// The solutions are stored as a vector of doubles. The value at index i
159// represents the solution value of model variable indexed i. Note that some
160// values can be infinity which should be interpreted as 'unknown' solution
161// value for that variable. These solutions can not necessarily be completed to
162// complete feasible solutions.
164 public:
165 bool HasNewSolution() const;
166 std::vector<double> GetNewSolution();
167
168 void AddNewSolution(const std::vector<double>& lp_solution);
169
170 private:
171 // New solutions are added and removed from the back.
172 std::vector<std::vector<double>> solutions_;
173 mutable absl::Mutex mutex_;
174};
175
176// Manages the global best response kept by the solver. This class is
177// responsible for logging the progress of the solutions and bounds as they are
178// found.
179//
180// All functions are thread-safe except if specified otherwise.
182 public:
184
185 // Loads the initial objective bounds and keep a reference to the objective to
186 // properly display the scaled bounds. This is optional if the model has no
187 // objective.
188 //
189 // This function is not thread safe.
190 void InitializeObjective(const CpModelProto& cp_model);
191
192 // Reports OPTIMAL and stop the search if any gap limit are specified and
193 // crossed. By default, we only stop when we have the true optimal, which is
194 // well defined since we are solving our pure integer problem exactly.
195 void SetGapLimitsFromParameters(const SatParameters& parameters);
196
197 // Returns the current solver response. That is the best known response at the
198 // time of the call with the best feasible solution and objective bounds.
199 //
200 // Note that the solver statistics correspond to the last time a better
201 // solution was found or SetStatsFromModel() was called.
202 //
203 // If full response is true, we will do more postprocessing by calling all the
204 // AddFinalSolutionPostprocessor() postprocesors. Note that the response given
205 // to the AddSolutionCallback() will not call them.
206 CpSolverResponse GetResponse(bool full_response = true);
207
208 // These will be called in REVERSE order on any feasible solution returned
209 // to the user.
211 std::function<void(std::vector<int64_t>*)> postprocessor);
212
213 // These "postprocessing" steps will be applied in REVERSE order of
214 // registration to all solution passed to the callbacks.
216 std::function<void(CpSolverResponse*)> postprocessor);
217
218 // These "postprocessing" steps will only be applied after the others to the
219 // solution returned by GetResponse().
221 std::function<void(CpSolverResponse*)> postprocessor);
222
223 // Adds a callback that will be called on each new solution (for
224 // statisfiablity problem) or each improving new solution (for an optimization
225 // problem). Returns its id so it can be unregistered if needed.
226 //
227 // Note that adding a callback is not free since the solution will be
228 // postsolved before this is called.
229 //
230 // Note that currently the class is waiting for the callback to finish before
231 // accepting any new updates. That could be changed if needed.
233 std::function<void(const CpSolverResponse&)> callback);
234 void UnregisterCallback(int callback_id);
235
236 // The "inner" objective is the CpModelProto objective without scaling/offset.
237 // Note that these bound correspond to valid bound for the problem of finding
238 // a strictly better objective than the current one. Thus the lower bound is
239 // always a valid bound for the global problem, but the upper bound is NOT.
240 IntegerValue GetInnerObjectiveLowerBound();
241 IntegerValue GetInnerObjectiveUpperBound();
242
243 // These functions return the same as the non-synchronized() version but
244 // only the values at the last time Synchronize() was called.
245 void Synchronize();
248
249 // Returns the current best solution inner objective value or kInt64Max if
250 // there is no solution.
251 IntegerValue BestSolutionInnerObjectiveValue();
252
253 // Returns the integral of the log of the absolute gap over deterministic
254 // time. This is mainly used to compare how fast the gap closes on a
255 // particular instance. Or to evaluate how efficient our LNS code is improving
256 // solution.
257 //
258 // Note: The integral will start counting on the first UpdateGapIntegral()
259 // call, since before the difference is assumed to be zero.
260 //
261 // Important: To report a proper deterministic integral, we only update it
262 // on UpdateGapIntegral() which should be called in the main subsolver
263 // synchronization loop.
264 //
265 // Note(user): In the litterature, people use the relative gap to the optimal
266 // solution (or the best known one), but this is ill defined in many case
267 // (like if the optimal cost is zero), so I prefer this version.
268 double GapIntegral() const;
269 void UpdateGapIntegral();
270
271 // Sets this to true to have the "real" but non-deterministic primal integral.
272 // If this is true, then there is no need to manually call
273 // UpdateGapIntegral() but it is not an issue to do so.
275
276 // Updates the inner objective bounds.
277 void UpdateInnerObjectiveBounds(const std::string& update_info,
278 IntegerValue lb, IntegerValue ub);
279
280 // Reads the new solution from the response and update our state. For an
281 // optimization problem, we only do something if the solution is strictly
282 // improving.
283 //
284 // TODO(user): Only the following fields from response are accessed here, we
285 // might want a tighter API:
286 // - solution_info
287 // - solution
288 void NewSolution(const CpSolverResponse& response, Model* model);
289
290 // Changes the solution to reflect the fact that the "improving" problem is
291 // infeasible. This means that if we have a solution, we have proven
292 // optimality, otherwise the global problem is infeasible.
293 //
294 // Note that this shouldn't be called before the solution is actually
295 // reported. We check for this case in NewSolution().
296 void NotifyThatImprovingProblemIsInfeasible(const std::string& worker_info);
297
298 // Adds to the shared response a subset of assumptions that are enough to
299 // make the problem infeasible.
300 void AddUnsatCore(const std::vector<int>& core);
301
302 // Sets the statistics in the response to the one of the solver inside the
303 // given in-memory model. This does nothing if the model is nullptr.
304 //
305 // TODO(user): Also support merging statistics together.
307
308 // Returns true if we found the optimal solution or the problem was proven
309 // infeasible. Note that if the gap limit is reached, we will also report
310 // OPTIMAL and consider the problem solved.
311 bool ProblemIsSolved() const;
312
313 // Returns the underlying solution repository where we keep a set of best
314 // solutions.
316 return solutions_;
317 }
319 return &solutions_;
320 }
321
322 // This should be called after the model is loaded. It will read the file
323 // specified by --cp_model_load_debug_solution and properly fill the
324 // model->Get<DebugSolution>() vector.
325 //
326 // TODO(user): Note that for now, only the IntegerVariable value are loaded,
327 // not the value of the pure Booleans variables.
329
330 // Debug only. Set dump prefix for solutions written to file.
331 void set_dump_prefix(const std::string& dump_prefix) {
332 dump_prefix_ = dump_prefix;
333 }
334
335 // Display improvement stats.
337
338 void LogMessage(const std::string& prefix, const std::string& message);
339 void LogPeriodicMessage(const std::string& prefix, const std::string& message,
340 absl::Time* last_logging_time);
341 bool LoggingIsEnabled() const { return logger_->LoggingIsEnabled(); }
342
343 // This is here for the few codepath that needs to modify the returned
344 // response directly. Note that this do not work in parallel.
345 //
346 // TODO(user): This can probably be removed.
347 CpSolverResponse* MutableResponse() {
348 absl::MutexLock mutex_lock(&mutex_);
349 return &best_response_;
350 }
351
352 private:
353 void TestGapLimitsIfNeeded() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
354 void FillObjectiveValuesInBestResponse()
355 ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
356 void SetStatsFromModelInternal(Model* model)
357 ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
358 void UpdateGapIntegralInternal() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
359
360 void RegisterSolutionFound(const std::string& improvement_info)
361 ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
362 void RegisterObjectiveBoundImprovement(const std::string& improvement_info)
363 ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
364
365 // Generates a response for callbacks and GetResponse().
366 CpSolverResponse GetResponseInternal() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
367
368 const SatParameters& parameters_;
369 const WallTimer& wall_timer_;
370 ModelSharedTimeLimit* shared_time_limit_;
371 CpObjectiveProto const* objective_or_null_ = nullptr;
372
373 mutable absl::Mutex mutex_;
374
375 // Gap limits.
376 double absolute_gap_limit_ ABSL_GUARDED_BY(mutex_) = 0.0;
377 double relative_gap_limit_ ABSL_GUARDED_BY(mutex_) = 0.0;
378
379 CpSolverResponse best_response_ ABSL_GUARDED_BY(mutex_);
380 SharedSolutionRepository<int64_t> solutions_ ABSL_GUARDED_BY(mutex_);
381
382 int num_solutions_ ABSL_GUARDED_BY(mutex_) = 0;
383 int64_t inner_objective_lower_bound_ ABSL_GUARDED_BY(mutex_) =
384 std::numeric_limits<int64_t>::min();
385 int64_t inner_objective_upper_bound_ ABSL_GUARDED_BY(mutex_) =
386 std::numeric_limits<int64_t>::max();
387 int64_t best_solution_objective_value_ ABSL_GUARDED_BY(mutex_) =
388 std::numeric_limits<int64_t>::max();
389
390 IntegerValue synchronized_inner_objective_lower_bound_ ABSL_GUARDED_BY(
391 mutex_) = IntegerValue(std::numeric_limits<int64_t>::min());
392 IntegerValue synchronized_inner_objective_upper_bound_ ABSL_GUARDED_BY(
393 mutex_) = IntegerValue(std::numeric_limits<int64_t>::max());
394
395 bool update_integral_on_each_change_ ABSL_GUARDED_BY(mutex_) = false;
396 double gap_integral_ ABSL_GUARDED_BY(mutex_) = 0.0;
397 double last_absolute_gap_ ABSL_GUARDED_BY(mutex_) = 0.0;
398 double last_gap_integral_time_stamp_ ABSL_GUARDED_BY(mutex_) = 0.0;
399
400 int next_callback_id_ ABSL_GUARDED_BY(mutex_) = 0;
401 std::vector<std::pair<int, std::function<void(const CpSolverResponse&)>>>
402 callbacks_ ABSL_GUARDED_BY(mutex_);
403
404 std::vector<std::function<void(std::vector<int64_t>*)>>
405 solution_postprocessors_ ABSL_GUARDED_BY(mutex_);
406 std::vector<std::function<void(CpSolverResponse*)>> postprocessors_
407 ABSL_GUARDED_BY(mutex_);
408 std::vector<std::function<void(CpSolverResponse*)>> final_postprocessors_
409 ABSL_GUARDED_BY(mutex_);
410
411 // Dump prefix.
412 std::string dump_prefix_;
413
414 // Used for statistics of the improvements found by workers.
415 absl::btree_map<std::string, int> primal_improvements_count_
416 ABSL_GUARDED_BY(mutex_);
417 absl::btree_map<std::string, int> dual_improvements_count_
418 ABSL_GUARDED_BY(mutex_);
419
420 SolverLogger* logger_;
421};
422
423// This class manages a pool of lower and upper bounds on a set of variables in
424// a parallel context.
426 public:
427 explicit SharedBoundsManager(const CpModelProto& model_proto);
428
429 // Reports a set of locally improved variable bounds to the shared bounds
430 // manager. The manager will compare these bounds changes against its
431 // global state, and incorporate the improving ones.
432 void ReportPotentialNewBounds(const CpModelProto& model_proto,
433 const std::string& worker_name,
434 const std::vector<int>& variables,
435 const std::vector<int64_t>& new_lower_bounds,
436 const std::vector<int64_t>& new_upper_bounds);
437
438 // If we solved a small independent component of the full problem, then we can
439 // in most situation fix the solution on this subspace.
440 //
441 // Note that because there can be more than one optimal solution on an
442 // independent subproblem, it is important to do that in a locked fashion, and
443 // reject future incompatible fixing.
444 void FixVariablesFromPartialSolution(
445 const std::vector<int64_t>& solution,
446 const std::vector<int>& variables_to_fix);
447
448 // Returns a new id to be used in GetChangedBounds(). This is just an ever
449 // increasing sequence starting from zero. Note that the class is not designed
450 // to have too many of these.
451 int RegisterNewId();
452
453 // When called, returns the set of bounds improvements since
454 // the last time this method was called with the same id.
455 void GetChangedBounds(int id, std::vector<int>* variables,
456 std::vector<int64_t>* new_lower_bounds,
457 std::vector<int64_t>* new_upper_bounds);
458
459 // Publishes any new bounds so that GetChangedBounds() will reflect the latest
460 // state.
461 void Synchronize();
462
463 void LogStatistics(SolverLogger* logger);
464 int NumBoundsExported(const std::string& worker_name);
465
466 private:
467 const int num_variables_;
468 const CpModelProto& model_proto_;
469
470 absl::Mutex mutex_;
471
472 // These are always up to date.
473 std::vector<int64_t> lower_bounds_ ABSL_GUARDED_BY(mutex_);
474 std::vector<int64_t> upper_bounds_ ABSL_GUARDED_BY(mutex_);
475 SparseBitset<int> changed_variables_since_last_synchronize_
476 ABSL_GUARDED_BY(mutex_);
477
478 // These are only updated on Synchronize().
479 std::vector<int64_t> synchronized_lower_bounds_ ABSL_GUARDED_BY(mutex_);
480 std::vector<int64_t> synchronized_upper_bounds_ ABSL_GUARDED_BY(mutex_);
481 std::deque<SparseBitset<int>> id_to_changed_variables_
482 ABSL_GUARDED_BY(mutex_);
483 absl::btree_map<std::string, int> bounds_exported_ ABSL_GUARDED_BY(mutex_);
484};
485
486// This class holds all the binary clauses that were found and shared by the
487// workers.
488//
489// It is thread-safe.
490//
491// Note that this uses literal as encoded in a cp_model.proto. The literals can
492// thus be negative numbers.
494 public:
495 void AddBinaryClause(int id, int lit1, int lit2);
496
497 // Fills flat_clauses with
498 // (lit1 of clause1, lit2 of clause1, lit1 of clause 2, lit2 of clause2 ...)
499 void GetUnseenBinaryClauses(int id,
500 std::vector<std::pair<int, int>>* new_clauses);
501
502 int RegisterNewId();
503 void SetWorkerNameForId(int id, const std::string& worker_name);
504
505 // Search statistics.
506 void LogStatistics(SolverLogger* logger);
507
508 private:
509 absl::Mutex mutex_;
510 // Cache to avoid adding the same clause twice.
511 absl::flat_hash_set<std::pair<int, int>> added_binary_clauses_set_
512 ABSL_GUARDED_BY(mutex_);
513 std::vector<std::pair<int, int>> added_binary_clauses_
514 ABSL_GUARDED_BY(mutex_);
515 std::vector<int64_t> id_to_last_processed_binary_clause_
516 ABSL_GUARDED_BY(mutex_);
517 std::vector<int64_t> id_to_clauses_exported_;
518
519 // Used for reporting statistics.
520 absl::flat_hash_map<int, std::string> id_to_worker_name_;
521};
522
523template <typename ValueType>
525 absl::MutexLock mutex_lock(&mutex_);
526 return solutions_.size();
527}
528
529template <typename ValueType>
532 absl::MutexLock mutex_lock(&mutex_);
533 return solutions_[i];
534}
535
536template <typename ValueType>
538 int var_index, int solution_index) const {
539 absl::MutexLock mutex_lock(&mutex_);
540 return solutions_[solution_index].variable_values[var_index];
541}
542
543// TODO(user): Experiments on the best distribution.
544template <typename ValueType>
547 absl::BitGenRef random) const {
548 absl::MutexLock mutex_lock(&mutex_);
549 const int64_t best_rank = solutions_[0].rank;
550
551 // As long as we have solution with the best objective that haven't been
552 // explored too much, we select one uniformly. Otherwise, we select a solution
553 // from the pool uniformly.
554 //
555 // Note(user): Because of the increase of num_selected, this is dependent on
556 // the order of call. It should be fine for "determinism" because we do
557 // generate the task of a batch always in the same order.
558 const int kExplorationThreshold = 100;
559
560 // Select all the best solution with a low enough selection count.
561 tmp_indices_.clear();
562 for (int i = 0; i < solutions_.size(); ++i) {
563 const auto& solution = solutions_[i];
564 if (solution.rank == best_rank &&
565 solution.num_selected <= kExplorationThreshold) {
566 tmp_indices_.push_back(i);
567 }
568 }
569
570 int index = 0;
571 if (tmp_indices_.empty()) {
572 index = absl::Uniform<int>(random, 0, solutions_.size());
573 } else {
574 index = tmp_indices_[absl::Uniform<int>(random, 0, tmp_indices_.size())];
575 }
576 solutions_[index].num_selected++;
577 return solutions_[index];
578}
579
580template <typename ValueType>
582 if (num_solutions_to_keep_ == 0) return;
583 absl::MutexLock mutex_lock(&mutex_);
584 AddInternal(solution);
585}
586
587template <typename ValueType>
589 const Solution& solution) {
590 int worse_solution_index = 0;
591 for (int i = 0; i < new_solutions_.size(); ++i) {
592 // Do not add identical solution.
593 if (new_solutions_[i] == solution) return;
594 if (new_solutions_[worse_solution_index] < new_solutions_[i]) {
595 worse_solution_index = i;
596 }
597 }
598 if (new_solutions_.size() < num_solutions_to_keep_) {
599 new_solutions_.push_back(solution);
600 } else if (solution < new_solutions_[worse_solution_index]) {
601 new_solutions_[worse_solution_index] = solution;
602 }
603}
604
605template <typename ValueType>
607 absl::MutexLock mutex_lock(&mutex_);
608 if (new_solutions_.empty()) return;
609
610 solutions_.insert(solutions_.end(), new_solutions_.begin(),
611 new_solutions_.end());
612 new_solutions_.clear();
613
614 // We use a stable sort to keep the num_selected count for the already
615 // existing solutions.
616 //
617 // TODO(user): Introduce a notion of orthogonality to diversify the pool?
619 if (solutions_.size() > num_solutions_to_keep_) {
620 solutions_.resize(num_solutions_to_keep_);
621 }
622
623 if (!solutions_.empty()) {
624 VLOG(2) << "Solution pool update:"
625 << " num_solutions=" << solutions_.size()
626 << " min_rank=" << solutions_[0].rank
627 << " max_rank=" << solutions_.back().rank;
628 }
629
630 num_synchronization_++;
631}
632
633} // namespace sat
634} // namespace operations_research
635
636#endif // OR_TOOLS_SAT_SYNCHRONIZATION_H_
int64_t max
Definition: alldiff_cst.cc:140
int64_t min
Definition: alldiff_cst.cc:139
#define CHECK_GE(val1, val2)
Definition: base/logging.h:707
#define VLOG(verboselevel)
Definition: base/logging.h:984
Class that owns everything related to a particular optimization model.
Definition: sat/model.h:42
void AddNewSolution(const std::vector< double > &lp_solution)
void NewLPSolution(std::vector< double > lp_solution)
void NewRelaxationSolution(const CpSolverResponse &response)
void InitializeObjective(const CpModelProto &cp_model)
CpSolverResponse GetResponse(bool full_response=true)
void AddSolutionPostprocessor(std::function< void(std::vector< int64_t > *)> postprocessor)
SharedSolutionRepository< int64_t > * MutableSolutionsRepository()
void AddFinalResponsePostprocessor(std::function< void(CpSolverResponse *)> postprocessor)
void set_dump_prefix(const std::string &dump_prefix)
void LogPeriodicMessage(const std::string &prefix, const std::string &message, absl::Time *last_logging_time)
void NewSolution(const CpSolverResponse &response, Model *model)
void NotifyThatImprovingProblemIsInfeasible(const std::string &worker_info)
void AddUnsatCore(const std::vector< int > &core)
void SetGapLimitsFromParameters(const SatParameters &parameters)
const SharedSolutionRepository< int64_t > & SolutionsRepository() const
void AddResponsePostprocessor(std::function< void(CpSolverResponse *)> postprocessor)
int AddSolutionCallback(std::function< void(const CpSolverResponse &)> callback)
void LogMessage(const std::string &prefix, const std::string &message)
void UpdateInnerObjectiveBounds(const std::string &update_info, IntegerValue lb, IntegerValue ub)
std::vector< Solution > new_solutions_ ABSL_GUARDED_BY(mutex_)
Solution GetRandomBiasedSolution(absl::BitGenRef random) const
std::vector< int > tmp_indices_ ABSL_GUARDED_BY(mutex_)
std::vector< Solution > solutions_ ABSL_GUARDED_BY(mutex_)
int64_t num_synchronization_ ABSL_GUARDED_BY(mutex_)=0
void AddInternal(const Solution &solution) ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_)
ValueType GetVariableValueInSolution(int var_index, int solution_index) const
SatParameters parameters
CpModelProto const * model_proto
SharedResponseManager * response
GRBmodel * model
MPCallback * callback
int index
Definition: cleanup.h:22
void STLStableSortAndRemoveDuplicates(T *v, const LessFunc &less_func)
Definition: stl_util.h:75
Collection of objects used to extend the Constraint Solver library.
STL namespace.
std::string message
Definition: trace.cc:398