OR-Tools  9.0
flatzinc/model.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_FLATZINC_MODEL_H_
15 #define OR_TOOLS_FLATZINC_MODEL_H_
16 
17 #include <cstdint>
18 #include <map>
19 #include <string>
20 
21 #include "absl/container/flat_hash_map.h"
23 #include "ortools/base/logging.h"
25 #include "ortools/util/logging.h"
27 
28 namespace operations_research {
29 namespace fz {
30 
31 struct Constraint;
32 class Model;
33 
34 // A domain represents the possible values of a variable, and its type
35 // (which carries display information, i.e. a Boolean will be displayed
36 // differently than an integer with domain {0, 1}).
37 // It can be:
38 // - an explicit list of all possible values, in which case is_interval is
39 // false. If the list is empty, then the domain is empty.
40 // - an interval, in which case is_interval is true and values.size() == 2,
41 // and the interval is [values[0], values[1]].
42 // - all integers, in which case values is empty, and is_interval is true.
43 // Note that semi-infinite intervals aren't supported.
44 // - a Boolean domain({ 0, 1 } with Boolean display tag).
45 // TODO(user): Rework domains, all int64_t should be kintmin..kint64max.
46 // It is a bit tricky though as we must take care of overflows.
47 // If is_a_set is true, then this domain has a set semantics. For a set
48 // variable, any subset of the initial set of values is a valid assignment,
49 // instead of exactly one value.
50 struct Domain {
51  // The values will be sorted and duplicate values will be removed.
52  static Domain IntegerList(std::vector<int64_t> values);
53  static Domain AllInt64();
54  static Domain IntegerValue(int64_t value);
55  static Domain Interval(int64_t included_min, int64_t included_max);
56  static Domain Boolean();
57  static Domain SetOfIntegerList(std::vector<int64_t> values);
58  static Domain SetOfAllInt64();
59  static Domain SetOfIntegerValue(int64_t value);
60  static Domain SetOfInterval(int64_t included_min, int64_t included_max);
61  static Domain SetOfBoolean();
62  static Domain EmptyDomain();
63 
64  bool HasOneValue() const;
65  bool empty() const;
66 
67  // Returns the min of the domain.
68  int64_t Min() const;
69 
70  // Returns the max of the domain.
71  int64_t Max() const;
72 
73  // Returns the value of the domain. HasOneValue() must return true.
74  int64_t Value() const;
75 
76  // Returns true if the domain is [kint64min..kint64max]
77  bool IsAllInt64() const;
78 
79  // Various inclusion tests on a domain.
80  bool Contains(int64_t value) const;
81  bool OverlapsIntList(const std::vector<int64_t>& vec) const;
82  bool OverlapsIntInterval(int64_t lb, int64_t ub) const;
83  bool OverlapsDomain(const Domain& other) const;
84 
85  // All the following modifiers change the internal representation
86  // list to interval or interval to list.
87  bool IntersectWithSingleton(int64_t value);
88  bool IntersectWithDomain(const Domain& domain);
89  bool IntersectWithInterval(int64_t interval_min, int64_t interval_max);
90  bool IntersectWithListOfIntegers(const std::vector<int64_t>& integers);
91 
92  // Returns true iff the value did belong to the domain, and was removed.
93  // Try to remove the value. It returns true if it was actually removed.
94  // If the value is inside a large interval, then it will not be removed.
95  bool RemoveValue(int64_t value);
96  std::string DebugString() const;
97 
98  // These should never be modified from outside the class.
99  std::vector<int64_t> values;
102  // Indicates if the domain was created as a set domain.
103  bool is_a_set;
104 };
105 
106 // An int var is a name with a domain of possible values, along with
107 // some tags. Typically, an IntegerVariable is on the heap, and owned by the
108 // global Model object.
110  // This method tries to unify two variables. This can happen during the
111  // parsing of the model or during presolve. This is possible if at least one
112  // of the two variable is not the target of a constraint. (otherwise it
113  // returns false).
114  // The semantic of the merge is the following:
115  // - the resulting domain is the intersection of the two domains.
116  // - if one variable is not temporary, the result is not temporary.
117  // - if one variable is temporary, the name is the name of the other
118  // variable. If both variables are temporary or both variables are not
119  // temporary, the name is chosen arbitrarily between the two names.
120  bool Merge(const std::string& other_name, const Domain& other_domain,
121  bool other_temporary);
122 
123  std::string DebugString() const;
124 
125  std::string name;
127  // Indicates if the variable is a temporary variable created when flattening
128  // the model. For instance, if you write x == y * z + y, then it will be
129  // expanded into y * z == t and x = t + y. And t will be a temporary variable.
130  bool temporary : 1;
131  // Indicates if the variable should be created at all. A temporary variable
132  // can be unreachable in the active model if nobody uses it. In that case,
133  // there is no need to create it.
134  bool active : 1;
135 
136  private:
137  friend class Model;
138 
139  IntegerVariable(const std::string& name_, const Domain& domain_,
140  bool temporary_);
141 };
142 
143 // An argument is either an integer value, an integer domain, a
144 // reference to a variable, or an array of variable references.
145 struct Argument {
146  enum Type {
154  };
155 
156  static Argument IntegerValue(int64_t value);
157  static Argument Interval(int64_t imin, int64_t imax);
158  static Argument IntegerList(std::vector<int64_t> values);
159  static Argument DomainList(std::vector<Domain> domains);
160  static Argument IntVarRef(IntegerVariable* const var);
161  static Argument IntVarRefArray(std::vector<IntegerVariable*> vars);
162  static Argument VoidArgument();
163  static Argument FromDomain(const Domain& domain);
164 
165  std::string DebugString() const;
166 
167  // Returns true if the argument is a variable.
168  bool IsVariable() const;
169  // Returns true if the argument has only one value (integer value, integer
170  // list of size 1, interval of size 1, or variable with a singleton domain).
171  bool HasOneValue() const;
172  // Returns the value of the argument. Does DCHECK(HasOneValue()).
173  int64_t Value() const;
174  // Returns true if it an integer list, or an array of integer
175  // variables (or domain) each having only one value.
176  bool IsArrayOfValues() const;
177  // Returns true if the argument is an integer value, an integer
178  // list, or an interval, and it contains the given value.
179  // It will check that the type is actually one of the above.
180  bool Contains(int64_t value) const;
181  // Returns the value of the pos-th element.
182  int64_t ValueAt(int pos) const;
183  // Returns the variable inside the argument if the type is INT_VAR_REF,
184  // or nullptr otherwise.
185  IntegerVariable* Var() const;
186  // Returns the variable at position pos inside the argument if the type is
187  // INT_VAR_REF_ARRAY or nullptr otherwise.
188  IntegerVariable* VarAt(int pos) const;
189 
191  std::vector<int64_t> values;
192  std::vector<IntegerVariable*> variables;
193  std::vector<Domain> domains;
194 };
195 
196 // A constraint has a type, some arguments, and a few tags. Typically, a
197 // Constraint is on the heap, and owned by the global Model object.
198 struct Constraint {
199  Constraint(const std::string& t, std::vector<Argument> args,
200  bool strong_propag)
201  : type(t),
202  arguments(std::move(args)),
203  strong_propagation(strong_propag),
204  active(true),
205  presolve_propagation_done(false) {}
206 
207  std::string DebugString() const;
208 
209  // Helpers to be used during presolve.
210  void MarkAsInactive();
211  // Helper method to remove one argument.
212  void RemoveArg(int arg_pos);
213  // Set as a False constraint.
214  void SetAsFalse();
215 
216  // The flatzinc type of the constraint (i.e. "int_eq" for integer equality)
217  // stored as a string.
218  std::string type;
219  std::vector<Argument> arguments;
220  // Is true if the constraint should use the strongest level of propagation.
221  // This is a hint in the model. For instance, in the AllDifferent constraint,
222  // there are different algorithms to propagate with different pruning/speed
223  // ratios. When strong_propagation is true, one should use, if possible, the
224  // algorithm with the strongest pruning.
226  // Indicates if the constraint is active. Presolve can make it inactive by
227  // propagating it, or by regrouping it. Once a constraint is inactive, it is
228  // logically removed from the model, it is not extracted, and it is ignored by
229  // presolve.
230  bool active : 1;
231 
232  // Indicates if presolve has finished propagating this constraint.
234 };
235 
236 // An annotation is a set of information. It has two use cases. One during
237 // parsing to store intermediate information on model objects (i.e. the defines
238 // part of a constraint). The other use case is to store all search
239 // declarations. This persists after model parsing.
240 struct Annotation {
241  enum Type {
250  };
251 
252  static Annotation Empty();
253  static Annotation AnnotationList(std::vector<Annotation> list);
254  static Annotation Identifier(const std::string& id);
255  static Annotation FunctionCallWithArguments(const std::string& id,
256  std::vector<Annotation> args);
257  static Annotation FunctionCall(const std::string& id);
258  static Annotation Interval(int64_t interval_min, int64_t interval_max);
259  static Annotation IntegerValue(int64_t value);
260  static Annotation Variable(IntegerVariable* const var);
261  static Annotation VariableList(std::vector<IntegerVariable*> variables);
262  static Annotation String(const std::string& str);
263 
264  std::string DebugString() const;
265  bool IsFunctionCallWithIdentifier(const std::string& identifier) const {
266  return type == FUNCTION_CALL && id == identifier;
267  }
268  // Copy all the variable references contained in this annotation (and its
269  // children). Depending on the type of this annotation, there can be zero,
270  // one, or several.
271  void AppendAllIntegerVariables(std::vector<IntegerVariable*>* vars) const;
272 
274  int64_t interval_min;
275  int64_t interval_max;
276  std::string id;
277  std::vector<Annotation> annotations;
278  std::vector<IntegerVariable*> variables;
279  std::string string_value;
280 };
281 
282 // Information on what should be displayed when a solution is found.
283 // It follows the flatzinc specification (www.minizinc.org).
285  struct Bounds {
286  Bounds(int64_t min_value_, int64_t max_value_)
287  : min_value(min_value_), max_value(max_value_) {}
288  std::string DebugString() const;
289  int64_t min_value;
290  int64_t max_value;
291  };
292 
293  // Will output: name = <variable value>.
294  static SolutionOutputSpecs SingleVariable(const std::string& name,
296  bool display_as_boolean);
297  // Will output (for example):
298  // name = array2d(min1..max1, min2..max2, [list of variable values])
299  // for a 2d array (bounds.size() == 2).
301  const std::string& name, std::vector<Bounds> bounds,
302  std::vector<IntegerVariable*> flat_variables, bool display_as_boolean);
303  // Empty output.
305 
306  std::string DebugString() const;
307 
308  std::string name;
310  std::vector<IntegerVariable*> flat_variables;
311  // These are the starts and ends of intervals for displaying (potentially
312  // multi-dimensional) arrays.
313  std::vector<Bounds> bounds;
315 };
316 
317 class Model {
318  public:
319  explicit Model(const std::string& name)
320  : name_(name), objective_(nullptr), maximize_(true) {}
321  ~Model();
322 
323  // ----- Builder methods -----
324 
325  // The objects returned by AddVariable(), AddConstant(), and AddConstraint()
326  // are owned by the model and will remain live for its lifetime.
327  IntegerVariable* AddVariable(const std::string& name, const Domain& domain,
328  bool defined);
330  // Creates and add a constraint to the model.
331  void AddConstraint(const std::string& id, std::vector<Argument> arguments,
332  bool is_domain);
333  void AddConstraint(const std::string& id, std::vector<Argument> arguments);
335 
336  // Set the search annotations and the objective: either simply satisfy the
337  // problem, or minimize or maximize the given variable (which must have been
338  // added with AddVariable() already).
339  void Satisfy(std::vector<Annotation> search_annotations);
340  void Minimize(IntegerVariable* obj,
341  std::vector<Annotation> search_annotations);
342  void Maximize(IntegerVariable* obj,
343  std::vector<Annotation> search_annotations);
344 
345  bool IsInconsistent() const;
346 
347  // ----- Accessors and mutators -----
348 
349  const std::vector<IntegerVariable*>& variables() const { return variables_; }
350  const std::vector<Constraint*>& constraints() const { return constraints_; }
351  const std::vector<Annotation>& search_annotations() const {
352  return search_annotations_;
353  }
354 #if !defined(SWIG)
356  return util::MutableVectorIteration<Annotation>(&search_annotations_);
357  }
358 #endif
359  const std::vector<SolutionOutputSpecs>& output() const { return output_; }
360 #if !defined(SWIG)
363  }
364 #endif
365  bool maximize() const { return maximize_; }
366  IntegerVariable* objective() const { return objective_; }
367  void SetObjective(IntegerVariable* obj) { objective_ = obj; }
368 
369  // Services.
370  std::string DebugString() const;
371 
372  const std::string& name() const { return name_; }
373 
374  private:
375  const std::string name_;
376  // owned.
377  // TODO(user): use unique_ptr
378  std::vector<IntegerVariable*> variables_;
379  // owned.
380  // TODO(user): use unique_ptr
381  std::vector<Constraint*> constraints_;
382  // The objective variable (it belongs to variables_).
383  IntegerVariable* objective_;
384  bool maximize_;
385  // All search annotations are stored as a vector of Annotation.
386  std::vector<Annotation> search_annotations_;
387  std::vector<SolutionOutputSpecs> output_;
388 };
389 
390 // Stand-alone statistics class on the model.
391 // TODO(user): Clean up API to pass a Model* in argument.
393  public:
394  explicit ModelStatistics(const Model& model, SolverLogger* logger)
395  : model_(model), logger_(logger) {}
397  return constraints_per_variables_[var].size();
398  }
399  void BuildStatistics();
400  void PrintStatistics() const;
401 
402  private:
403  const Model& model_;
404  SolverLogger* logger_;
405  std::map<std::string, std::vector<Constraint*>> constraints_per_type_;
406  absl::flat_hash_map<const IntegerVariable*, std::vector<Constraint*>>
407  constraints_per_variables_;
408 };
409 
410 // Helper method to flatten Search annotations.
411 void FlattenAnnotations(const Annotation& ann, std::vector<Annotation>* out);
412 
413 } // namespace fz
414 } // namespace operations_research
415 
416 #endif // OR_TOOLS_FLATZINC_MODEL_H_
util::MutableVectorIteration< Annotation > mutable_search_annotations()
IntegerVariable * AddVariable(const std::string &name, const Domain &domain, bool defined)
Definition: model.cc:834
util::MutableVectorIteration< SolutionOutputSpecs > mutable_output()
Model(const std::string &name)
IntegerVariable * AddConstant(int64_t value)
Definition: model.cc:842
void Satisfy(std::vector< Annotation > search_annotations)
Definition: model.cc:865
const std::vector< Constraint * > & constraints() const
IntegerVariable * objective() const
void Maximize(IntegerVariable *obj, std::vector< Annotation > search_annotations)
Definition: model.cc:877
std::string DebugString() const
Definition: model.cc:884
const std::vector< Annotation > & search_annotations() const
void AddOutput(SolutionOutputSpecs output)
Definition: model.cc:861
const std::vector< SolutionOutputSpecs > & output() const
void SetObjective(IntegerVariable *obj)
void AddConstraint(const std::string &id, std::vector< Argument > arguments, bool is_domain)
Definition: model.cc:849
void Minimize(IntegerVariable *obj, std::vector< Annotation > search_annotations)
Definition: model.cc:870
const std::vector< IntegerVariable * > & variables() const
bool IsInconsistent() const
Definition: model.cc:911
const std::string & name() const
ModelStatistics(const Model &model, SolverLogger *logger)
int NumVariableOccurrences(IntegerVariable *var)
int64_t value
IntVar * var
Definition: expr_array.cc:1874
GRBmodel * model
void FlattenAnnotations(const Annotation &ann, std::vector< Annotation > *out)
Definition: model.cc:963
Collection of objects used to extend the Constraint Solver library.
static Annotation IntegerValue(int64_t value)
Definition: model.cc:702
std::vector< IntegerVariable * > variables
static Annotation Variable(IntegerVariable *const var)
Definition: model.cc:709
std::string DebugString() const
Definition: model.cc:746
static Annotation FunctionCall(const std::string &id)
Definition: model.cc:685
static Annotation AnnotationList(std::vector< Annotation > list)
Definition: model.cc:656
static Annotation String(const std::string &str)
Definition: model.cc:727
static Annotation Identifier(const std::string &id)
Definition: model.cc:665
bool IsFunctionCallWithIdentifier(const std::string &identifier) const
std::vector< Annotation > annotations
static Annotation Interval(int64_t interval_min, int64_t interval_max)
Definition: model.cc:694
static Annotation Empty()
Definition: model.cc:648
void AppendAllIntegerVariables(std::vector< IntegerVariable * > *vars) const
Definition: model.cc:736
static Annotation FunctionCallWithArguments(const std::string &id, std::vector< Annotation > args)
Definition: model.cc:674
static Annotation VariableList(std::vector< IntegerVariable * > variables)
Definition: model.cc:718
IntegerVariable * Var() const
Definition: model.cc:582
static Argument DomainList(std::vector< Domain > domains)
Definition: model.cc:415
std::vector< IntegerVariable * > variables
bool Contains(int64_t value) const
Definition: model.cc:539
static Argument IntegerList(std::vector< int64_t > values)
Definition: model.cc:408
IntegerVariable * VarAt(int pos) const
Definition: model.cc:586
static Argument VoidArgument()
Definition: model.cc:436
static Argument IntVarRefArray(std::vector< IntegerVariable * > vars)
Definition: model.cc:429
static Argument IntegerValue(int64_t value)
Definition: model.cc:393
static Argument Interval(int64_t imin, int64_t imax)
Definition: model.cc:400
std::string DebugString() const
Definition: model.cc:455
std::vector< int64_t > values
int64_t ValueAt(int pos) const
Definition: model.cc:557
static Argument IntVarRef(IntegerVariable *const var)
Definition: model.cc:422
static Argument FromDomain(const Domain &domain)
Definition: model.cc:442
Constraint(const std::string &t, std::vector< Argument > args, bool strong_propag)
void RemoveArg(int arg_pos)
Definition: model.cc:632
std::string DebugString() const
Definition: model.cc:622
std::vector< Argument > arguments
static Domain IntegerValue(int64_t value)
Definition: model.cc:51
static Domain EmptyDomain()
Definition: model.cc:110
bool Contains(int64_t value) const
Definition: model.cc:272
bool OverlapsDomain(const Domain &other) const
Definition: model.cc:334
static Domain SetOfAllInt64()
Definition: model.cc:86
static Domain Boolean()
Definition: model.cc:70
bool IntersectWithSingleton(int64_t value)
Definition: model.cc:141
static Domain SetOfInterval(int64_t included_min, int64_t included_max)
Definition: model.cc:98
static Domain IntegerList(std::vector< int64_t > values)
Definition: model.cc:33
std::string DebugString() const
Definition: model.cc:377
bool IntersectWithInterval(int64_t interval_min, int64_t interval_max)
Definition: model.cc:145
static Domain AllInt64()
Definition: model.cc:43
bool IntersectWithDomain(const Domain &domain)
Definition: model.cc:118
bool OverlapsIntInterval(int64_t lb, int64_t ub) const
Definition: model.cc:320
static Domain SetOfIntegerValue(int64_t value)
Definition: model.cc:92
bool OverlapsIntList(const std::vector< int64_t > &vec) const
Definition: model.cc:296
static Domain Interval(int64_t included_min, int64_t included_max)
Definition: model.cc:60
std::vector< int64_t > values
static Domain SetOfBoolean()
Definition: model.cc:104
static Domain SetOfIntegerList(std::vector< int64_t > values)
Definition: model.cc:80
bool IntersectWithListOfIntegers(const std::vector< int64_t > &integers)
Definition: model.cc:193
bool RemoveValue(int64_t value)
Definition: model.cc:346
bool Merge(const std::string &other_name, const Domain &other_domain, bool other_temporary)
Definition: model.cc:600
Bounds(int64_t min_value_, int64_t max_value_)
static SolutionOutputSpecs MultiDimensionalArray(const std::string &name, std::vector< Bounds > bounds, std::vector< IntegerVariable * > flat_variables, bool display_as_boolean)
Definition: model.cc:798
std::vector< IntegerVariable * > flat_variables
static SolutionOutputSpecs VoidOutput()
Definition: model.cc:810
static SolutionOutputSpecs SingleVariable(const std::string &name, IntegerVariable *variable, bool display_as_boolean)
Definition: model.cc:788