OR-Tools  9.6
max_hs.h
Go to the documentation of this file.
1 // Copyright 2010-2022 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_MAX_HS_H_
15 #define OR_TOOLS_SAT_MAX_HS_H_
16 
17 #include <stdint.h>
18 
19 #include <cstdint>
20 #include <functional>
21 #include <utility>
22 #include <vector>
23 
24 #include "absl/container/flat_hash_map.h"
26 #include "ortools/linear_solver/linear_solver.pb.h"
27 #include "ortools/sat/cp_model.pb.h"
29 #include "ortools/sat/integer.h"
33 #include "ortools/sat/model.h"
34 #include "ortools/sat/sat_base.h"
35 #include "ortools/sat/sat_parameters.pb.h"
36 #include "ortools/sat/sat_solver.h"
38 #include "ortools/sat/util.h"
40 
41 namespace operations_research {
42 namespace sat {
43 
44 // Generalization of the max-HS algorithm (HS stands for Hitting Set). This is
45 // similar to MinimizeWithCoreAndLazyEncoding() but it uses a hybrid approach
46 // with a MIP solver to handle the discovered infeasibility cores.
47 //
48 // See, Jessica Davies and Fahiem Bacchus, "Solving MAXSAT by Solving a
49 // Sequence of Simpler SAT Instances",
50 // http://www.cs.toronto.edu/~jdavies/daviesCP11.pdf"
51 //
52 // Note that an implementation of this approach won the 2016 max-SAT competition
53 // on the industrial category, see
54 // http://maxsat.ia.udl.cat/results/#wpms-industrial
55 //
56 // TODO(user): This class requires linking with the SCIP MIP solver which is
57 // quite big, maybe we should find a way not to do that.
59  public:
60  HittingSetOptimizer(const CpModelProto& model_proto,
61  const ObjectiveDefinition& objective_definition,
62  const std::function<void()>& feasible_solution_observer,
63  Model* model);
64 
66 
67  private:
68  const int kUnextracted = -1;
69 
70  SatSolver::Status FindMultipleCoresForMaxHs(
71  std::vector<Literal> assumptions,
72  std::vector<std::vector<Literal>>* core);
73 
74  // Extract the objective variables, which is the smallest possible useful set.
75  void ExtractObjectiveVariables();
76 
77  // Calls ComputeAdditionalVariablesToExtract() and extract all new variables.
78  // This must be called after the linear relaxation has been filled.
79  void ExtractAdditionalVariables(
80  const std::vector<IntegerVariable>& to_extract);
81 
82  // Heuristic to decide which variables (in addition to the objective
83  // variables) to extract.
84  // We use a sorted map to have a deterministic model.
85  std::vector<IntegerVariable> ComputeAdditionalVariablesToExtract();
86 
87  // Checks whethers a variable is extracted, and return the index in the MIP
88  // model. It returns the same indef for both the variable and its negation.
89  //
90  // Node that the domain of the MIP variable is equal to the domain of the
91  // positive variable.
92  int GetExtractedIndex(IntegerVariable var) const;
93 
94  // Returns false if the model is unsat.
95  bool ComputeInitialMpModel();
96 
97  // Project the at_most_one constraint on the set of extracted variables.
98  void ProjectAndAddAtMostOne(const std::vector<Literal>& literals);
99 
100  // Project the linear constraint on the set of extracted variables. Non
101  // extracted variables are used to 'extend' the lower and upper bound of the
102  // linear equation.
103  //
104  // It returns a non-null proto if the constraints was successfully extracted.
105  MPConstraintProto* ProjectAndAddLinear(const LinearConstraint& linear);
106 
107  // Auxiliary method used by ProjectAndAddLinear(), and TightenLinear().
108  void ProjectLinear(const LinearConstraint& linear, MPConstraintProto* ct);
109 
110  // Imports variable bounds from the shared bound manager (in parallel),
111  // updates the domains of the SAT variables, lower and upper bounds of
112  // extracted variables. Then it scans the extracted linear constraints and
113  // recompute its lower and upper bounds.
114  void TightenMpModel();
115 
116  // Processes the cores from the SAT solver and add them to the MPModel.
117  void AddCoresToTheMpModel(const std::vector<std::vector<Literal>>& cores);
118 
119  // Builds the assumptions from the current MP solution.
120  std::vector<Literal> BuildAssumptions(
121  IntegerValue stratified_threshold,
122  IntegerValue* next_stratified_threshold);
123 
124  // This will be called each time a feasible solution is found.
125  bool ProcessSolution();
126 
127  // Import shared information. Returns false if the model is unsat.
128  bool ImportFromOtherWorkers();
129 
130  // Problem definition
131  const CpModelProto& model_proto_;
132  const ObjectiveDefinition& objective_definition_;
133  const std::function<void()> feasible_solution_observer_;
134 
135  // Model object.
136  Model* model_;
137  SatSolver* sat_solver_;
138  TimeLimit* time_limit_;
139  const SatParameters& parameters_;
140  ModelRandomGenerator* random_;
141  SharedResponseManager* shared_response_;
142  IntegerTrail* integer_trail_;
143  IntegerEncoder* integer_encoder_;
144 
145  // Linear model.
146  MPConstraintProto* obj_constraint_ = nullptr;
147  MPModelRequest request_;
148  MPSolutionResponse response_;
149 
150  // Linear relaxation of the SAT model.
151  LinearRelaxation relaxation_;
152 
153  // TODO(user): The core is returned in the same order as the assumptions,
154  // so we don't really need this map, we could just do a linear scan to
155  // recover which node are part of the core.
156  absl::flat_hash_map<LiteralIndex, std::vector<int>> assumption_to_indices_;
157 
158  // New Booleans variable in the MIP model to represent X OP cte (OP is => if
159  // the variable of the objective is positive, <= otherwise).
160  absl::flat_hash_map<std::pair<int, int64_t>, int> mp_integer_literals_;
161 
162  // Extraction info used in the projection of the model onto the extracted
163  // variables.
164  // By convention, we always associate the MPVariableProto with both the
165  // positive and the negative SAT variable.
166  absl::StrongVector<IntegerVariable, int> sat_var_to_mp_var_;
167 
168  // The list of <positive sat var, mp var proto> created during the
169  // ExtractVariable() method.
170  std::vector<std::pair<IntegerVariable, MPVariableProto*>>
171  extracted_variables_info_;
172 
173  int num_extracted_at_most_ones_ = 0;
174  std::vector<std::pair<int, MPConstraintProto*>> linear_extract_info_;
175 
176  // Normalized objective definition. All coefficients are positive.
177  std::vector<IntegerVariable> normalized_objective_variables_;
178  std::vector<IntegerValue> normalized_objective_coefficients_;
179 
180  // Temporary vector to store cores.
181  std::vector<std::vector<Literal>> temp_cores_;
182 };
183 
184 } // namespace sat
185 } // namespace operations_research
186 
187 #endif // OR_TOOLS_SAT_MAX_HS_H_
A simple class to enforce both an elapsed time limit and a deterministic time limit in the same threa...
Definition: time_limit.h:106
HittingSetOptimizer(const CpModelProto &model_proto, const ObjectiveDefinition &objective_definition, const std::function< void()> &feasible_solution_observer, Model *model)
Definition: max_hs.cc:63
Class that owns everything related to a particular optimization model.
Definition: sat/model.h:42
CpModelProto const * model_proto
const Constraint * ct
IntVar * var
Definition: expr_array.cc:1874
GRBmodel * model
Collection of objects used to extend the Constraint Solver library.