OR-Tools  9.2
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  static Domain AllFloats();
64  static Domain FloatValue(double value);
65  static Domain FloatInterval(double lb, double ub);
66  // TODO(user): Do we need SetOfFloats() ?
67 
68  bool HasOneValue() const;
69  bool empty() const;
70 
71  // Returns the min of the domain.
72  int64_t Min() const;
73 
74  // Returns the max of the domain.
75  int64_t Max() const;
76 
77  // Returns the value of the domain. HasOneValue() must return true.
78  int64_t Value() const;
79 
80  // Returns true if the domain is [kint64min..kint64max]
81  bool IsAllInt64() const;
82 
83  // Various inclusion tests on a domain.
84  bool Contains(int64_t value) const;
85  bool OverlapsIntList(const std::vector<int64_t>& vec) const;
86  bool OverlapsIntInterval(int64_t lb, int64_t ub) const;
87  bool OverlapsDomain(const Domain& other) const;
88 
89  // All the following modifiers change the internal representation
90  // list to interval or interval to list.
91  bool IntersectWithSingleton(int64_t value);
92  bool IntersectWithDomain(const Domain& domain);
93  bool IntersectWithInterval(int64_t interval_min, int64_t interval_max);
94  bool IntersectWithListOfIntegers(const std::vector<int64_t>& integers);
95  bool IntersectWithFloatDomain(const Domain& domain);
96 
97  // Returns true iff the value did belong to the domain, and was removed.
98  // Try to remove the value. It returns true if it was actually removed.
99  // If the value is inside a large interval, then it will not be removed.
100  bool RemoveValue(int64_t value);
101  // Sets the empty float domain. Returns true.
102  bool SetEmptyFloatDomain();
103  std::string DebugString() const;
104 
105  // These should never be modified from outside the class.
106  std::vector<int64_t> values;
107  bool is_interval = false;
108  bool display_as_boolean = false;
109  // Indicates if the domain was created as a set domain.
110  bool is_a_set = false;
111  // Float domain.
112  bool is_float = false;
113  std::vector<double> float_values;
114 };
115 
116 // An int var is a name with a domain of possible values, along with
117 // some tags. Typically, an Variable is on the heap, and owned by the
118 // global Model object.
119 struct Variable {
120  // This method tries to unify two variables. This can happen during the
121  // parsing of the model or during presolve. This is possible if at least one
122  // of the two variable is not the target of a constraint. (otherwise it
123  // returns false).
124  // The semantic of the merge is the following:
125  // - the resulting domain is the intersection of the two domains.
126  // - if one variable is not temporary, the result is not temporary.
127  // - if one variable is temporary, the name is the name of the other
128  // variable. If both variables are temporary or both variables are not
129  // temporary, the name is chosen arbitrarily between the two names.
130  bool Merge(const std::string& other_name, const Domain& other_domain,
131  bool other_temporary);
132 
133  std::string DebugString() const;
134 
135  std::string name;
137  // Indicates if the variable is a temporary variable created when flattening
138  // the model. For instance, if you write x == y * z + y, then it will be
139  // expanded into y * z == t and x = t + y. And t will be a temporary variable.
140  bool temporary : 1;
141  // Indicates if the variable should be created at all. A temporary variable
142  // can be unreachable in the active model if nobody uses it. In that case,
143  // there is no need to create it.
144  bool active : 1;
145 
146  private:
147  friend class Model;
148 
149  Variable(const std::string& name_, const Domain& domain_, bool temporary_);
150 };
151 
152 // An argument is either an integer value, an integer domain, a
153 // reference to a variable, or an array of variable references.
154 struct Argument {
155  enum Type {
166  };
167 
168  static Argument IntegerValue(int64_t value);
169  static Argument Interval(int64_t imin, int64_t imax);
170  static Argument IntegerList(std::vector<int64_t> values);
171  static Argument DomainList(std::vector<Domain> domains);
172  static Argument FloatValue(double value);
173  static Argument FloatInterval(double lb, double ub);
174  static Argument FloatList(std::vector<double> floats);
175  static Argument VarRef(Variable* const var);
176  static Argument VarRefArray(std::vector<Variable*> vars);
177  static Argument VoidArgument();
178  static Argument FromDomain(const Domain& domain);
179 
180  std::string DebugString() const;
181 
182  // Returns true if the argument is a variable.
183  bool IsVariable() const;
184  // Returns true if the argument has only one value (integer value, integer
185  // list of size 1, interval of size 1, or variable with a singleton domain).
186  bool HasOneValue() const;
187  // Returns the value of the argument. Does DCHECK(HasOneValue()).
188  int64_t Value() const;
189  // Returns true if it an integer list, or an array of integer
190  // variables (or domain) each having only one value.
191  bool IsArrayOfValues() const;
192  // Returns true if the argument is an integer value, an integer
193  // list, or an interval, and it contains the given value.
194  // It will check that the type is actually one of the above.
195  bool Contains(int64_t value) const;
196  // Returns the value of the pos-th element.
197  int64_t ValueAt(int pos) const;
198  // Returns the variable inside the argument if the type is VAR_REF,
199  // or nullptr otherwise.
200  Variable* Var() const;
201  // Returns the variable at position pos inside the argument if the type is
202  // VAR_REF_ARRAY or nullptr otherwise.
203  Variable* VarAt(int pos) const;
204  // Returns true is the pos-th argument is fixed.
205  bool HasOneValueAt(int pos) const;
206  // Returns the number of object in the argument.
207  int Size() const;
208 
210  std::vector<int64_t> values;
211  std::vector<Variable*> variables;
212  std::vector<Domain> domains;
213  std::vector<double> floats;
214 };
215 
216 // A constraint has a type, some arguments, and a few tags. Typically, a
217 // Constraint is on the heap, and owned by the global Model object.
218 struct Constraint {
219  Constraint(const std::string& t, std::vector<Argument> args,
220  bool strong_propag)
221  : type(t),
222  arguments(std::move(args)),
223  strong_propagation(strong_propag),
224  active(true),
225  presolve_propagation_done(false) {}
226 
227  std::string DebugString() const;
228 
229  // Helpers to be used during presolve.
230  void MarkAsInactive();
231  // Helper method to remove one argument.
232  void RemoveArg(int arg_pos);
233  // Set as a False constraint.
234  void SetAsFalse();
235 
236  // The flatzinc type of the constraint (i.e. "int_eq" for integer equality)
237  // stored as a string.
238  std::string type;
239  std::vector<Argument> arguments;
240  // Is true if the constraint should use the strongest level of propagation.
241  // This is a hint in the model. For instance, in the AllDifferent constraint,
242  // there are different algorithms to propagate with different pruning/speed
243  // ratios. When strong_propagation is true, one should use, if possible, the
244  // algorithm with the strongest pruning.
246  // Indicates if the constraint is active. Presolve can make it inactive by
247  // propagating it, or by regrouping it. Once a constraint is inactive, it is
248  // logically removed from the model, it is not extracted, and it is ignored by
249  // presolve.
250  bool active : 1;
251 
252  // Indicates if presolve has finished propagating this constraint.
254 };
255 
256 // An annotation is a set of information. It has two use cases. One during
257 // parsing to store intermediate information on model objects (i.e. the defines
258 // part of a constraint). The other use case is to store all search
259 // declarations. This persists after model parsing.
260 struct Annotation {
261  enum Type {
270  };
271 
272  static Annotation Empty();
273  static Annotation AnnotationList(std::vector<Annotation> list);
274  static Annotation Identifier(const std::string& id);
275  static Annotation FunctionCallWithArguments(const std::string& id,
276  std::vector<Annotation> args);
277  static Annotation FunctionCall(const std::string& id);
278  static Annotation Interval(int64_t interval_min, int64_t interval_max);
279  static Annotation IntegerValue(int64_t value);
280  static Annotation VarRef(Variable* const var);
281  static Annotation VarRefArray(std::vector<Variable*> variables);
282  static Annotation String(const std::string& str);
283 
284  std::string DebugString() const;
285  bool IsFunctionCallWithIdentifier(const std::string& identifier) const {
286  return type == FUNCTION_CALL && id == identifier;
287  }
288  // Copy all the variable references contained in this annotation (and its
289  // children). Depending on the type of this annotation, there can be zero,
290  // one, or several.
291  void AppendAllVariables(std::vector<Variable*>* vars) const;
292 
294  int64_t interval_min;
295  int64_t interval_max;
296  std::string id;
297  std::vector<Annotation> annotations;
298  std::vector<Variable*> variables;
299  std::string string_value;
300 };
301 
302 // Information on what should be displayed when a solution is found.
303 // It follows the flatzinc specification (www.minizinc.org).
305  struct Bounds {
306  Bounds(int64_t min_value_, int64_t max_value_)
307  : min_value(min_value_), max_value(max_value_) {}
308  std::string DebugString() const;
309  int64_t min_value;
310  int64_t max_value;
311  };
312 
313  // Will output: name = <variable value>.
314  static SolutionOutputSpecs SingleVariable(const std::string& name,
316  bool display_as_boolean);
317  // Will output (for example):
318  // name = array2d(min1..max1, min2..max2, [list of variable values])
319  // for a 2d array (bounds.size() == 2).
321  const std::string& name, std::vector<Bounds> bounds,
322  std::vector<Variable*> flat_variables, bool display_as_boolean);
323  // Empty output.
325 
326  std::string DebugString() const;
327 
328  std::string name;
330  std::vector<Variable*> flat_variables;
331  // These are the starts and ends of intervals for displaying (potentially
332  // multi-dimensional) arrays.
333  std::vector<Bounds> bounds;
335 };
336 
337 class Model {
338  public:
339  explicit Model(const std::string& name)
340  : name_(name), objective_(nullptr), maximize_(true) {}
341  ~Model();
342 
343  // ----- Builder methods -----
344 
345  // The objects returned by AddVariable(), AddConstant(), and AddConstraint()
346  // are owned by the model and will remain live for its lifetime.
347  Variable* AddVariable(const std::string& name, const Domain& domain,
348  bool defined);
349  Variable* AddConstant(int64_t value);
351  // Creates and add a constraint to the model.
352  void AddConstraint(const std::string& id, std::vector<Argument> arguments,
353  bool is_domain);
354  void AddConstraint(const std::string& id, std::vector<Argument> arguments);
356 
357  // Set the search annotations and the objective: either simply satisfy the
358  // problem, or minimize or maximize the given variable (which must have been
359  // added with AddVariable() already).
360  void Satisfy(std::vector<Annotation> search_annotations);
361  void Minimize(Variable* obj, std::vector<Annotation> search_annotations);
362  void Maximize(Variable* obj, std::vector<Annotation> search_annotations);
363 
364  bool IsInconsistent() const;
365 
366  // ----- Accessors and mutators -----
367 
368  const std::vector<Variable*>& variables() const { return variables_; }
369  const std::vector<Constraint*>& constraints() const { return constraints_; }
370  const std::vector<Annotation>& search_annotations() const {
371  return search_annotations_;
372  }
373 #if !defined(SWIG)
375  return util::MutableVectorIteration<Annotation>(&search_annotations_);
376  }
377 #endif
378  const std::vector<SolutionOutputSpecs>& output() const { return output_; }
379 #if !defined(SWIG)
382  }
383 #endif
384  bool maximize() const { return maximize_; }
385  Variable* objective() const { return objective_; }
386  void SetObjective(Variable* obj) { objective_ = obj; }
387 
388  // Services.
389  std::string DebugString() const;
390 
391  const std::string& name() const { return name_; }
392 
393  private:
394  const std::string name_;
395  // owned.
396  // TODO(user): use unique_ptr
397  std::vector<Variable*> variables_;
398  // owned.
399  // TODO(user): use unique_ptr
400  std::vector<Constraint*> constraints_;
401  // The objective variable (it belongs to variables_).
402  Variable* objective_;
403  bool maximize_;
404  // All search annotations are stored as a vector of Annotation.
405  std::vector<Annotation> search_annotations_;
406  std::vector<SolutionOutputSpecs> output_;
407 };
408 
409 // Stand-alone statistics class on the model.
410 // TODO(user): Clean up API to pass a Model* in argument.
412  public:
413  explicit ModelStatistics(const Model& model, SolverLogger* logger)
414  : model_(model), logger_(logger) {}
416  return constraints_per_variables_[var].size();
417  }
418  void BuildStatistics();
419  void PrintStatistics() const;
420 
421  private:
422  const Model& model_;
423  SolverLogger* logger_;
424  std::map<std::string, std::vector<Constraint*>> constraints_per_type_;
425  absl::flat_hash_map<const Variable*, std::vector<Constraint*>>
426  constraints_per_variables_;
427 };
428 
429 // Helper method to flatten Search annotations.
430 void FlattenAnnotations(const Annotation& ann, std::vector<Annotation>* out);
431 
432 } // namespace fz
433 } // namespace operations_research
434 
435 #endif // OR_TOOLS_FLATZINC_MODEL_H_
Constraint(const std::string &t, std::vector< Argument > args, bool strong_propag)
static Argument FromDomain(const Domain &domain)
Definition: model.cc:539
static Argument FloatInterval(double lb, double ub)
Definition: model.cc:559
std::vector< double > float_values
static Argument FloatList(std::vector< double > floats)
Definition: model.cc:567
std::string DebugString() const
Definition: model.cc:794
bool IntersectWithInterval(int64_t interval_min, int64_t interval_max)
Definition: model.cc:152
static Domain IntegerValue(int64_t value)
Definition: model.cc:46
Variable * AddConstant(int64_t value)
Definition: model.cc:1012
bool OverlapsIntInterval(int64_t lb, int64_t ub) const
Definition: model.cc:404
static Domain SetOfInterval(int64_t included_min, int64_t included_max)
Definition: model.cc:86
static Annotation Identifier(const std::string &id)
Definition: model.cc:837
void FlattenAnnotations(const Annotation &ann, std::vector< Annotation > *out)
Definition: model.cc:1140
std::string DebugString() const
Definition: model.cc:461
static SolutionOutputSpecs SingleVariable(const std::string &name, Variable *variable, bool display_as_boolean)
Definition: model.cc:959
void Minimize(Variable *obj, std::vector< Annotation > search_annotations)
Definition: model.cc:1047
bool HasOneValueAt(int pos) const
Definition: model.cc:711
void Maximize(Variable *obj, std::vector< Annotation > search_annotations)
Definition: model.cc:1054
int64_t ValueAt(int pos) const
Definition: model.cc:688
bool IntersectWithSingleton(int64_t value)
Definition: model.cc:148
GRBmodel * model
bool Contains(int64_t value) const
Definition: model.cc:356
static Domain SetOfIntegerList(std::vector< int64_t > values)
Definition: model.cc:68
std::string DebugString() const
Definition: model.cc:917
Bounds(int64_t min_value_, int64_t max_value_)
static Domain SetOfAllInt64()
Definition: model.cc:74
static Domain Interval(int64_t included_min, int64_t included_max)
Definition: model.cc:52
void AppendAllVariables(std::vector< Variable * > *vars) const
Definition: model.cc:908
std::string DebugString() const
Definition: model.cc:782
static Domain Boolean()
Definition: model.cc:60
std::string DebugString() const
Definition: model.cc:574
bool OverlapsIntList(const std::vector< int64_t > &vec) const
Definition: model.cc:380
static Domain AllInt64()
Definition: model.cc:40
const std::vector< SolutionOutputSpecs > & output() const
bool IsFunctionCallWithIdentifier(const std::string &identifier) const
static Annotation FunctionCall(const std::string &id)
Definition: model.cc:857
static Annotation Interval(int64_t interval_min, int64_t interval_max)
Definition: model.cc:866
bool IntersectWithListOfIntegers(const std::vector< int64_t > &integers)
Definition: model.cc:200
static Domain EmptyDomain()
Definition: model.cc:98
static Argument IntegerValue(int64_t value)
Definition: model.cc:490
const std::string & name() const
static Annotation IntegerValue(int64_t value)
Definition: model.cc:874
static Annotation VarRefArray(std::vector< Variable * > variables)
Definition: model.cc:890
static Annotation AnnotationList(std::vector< Annotation > list)
Definition: model.cc:828
void AddOutput(SolutionOutputSpecs output)
Definition: model.cc:1038
bool Contains(int64_t value) const
Definition: model.cc:670
std::vector< Variable * > variables
bool Merge(const std::string &other_name, const Domain &other_domain, bool other_temporary)
Definition: model.cc:772
const std::vector< Constraint * > & constraints() const
Variable * VarAt(int pos) const
Definition: model.cc:738
ModelStatistics(const Model &model, SolverLogger *logger)
static Argument VarRefArray(std::vector< Variable * > vars)
Definition: model.cc:526
std::vector< int64_t > values
static Domain SetOfBoolean()
Definition: model.cc:92
static SolutionOutputSpecs MultiDimensionalArray(const std::string &name, std::vector< Bounds > bounds, std::vector< Variable * > flat_variables, bool display_as_boolean)
Definition: model.cc:968
util::MutableVectorIteration< SolutionOutputSpecs > mutable_output()
static Domain IntegerList(std::vector< int64_t > values)
Definition: model.cc:33
static Argument VoidArgument()
Definition: model.cc:533
static SolutionOutputSpecs VoidOutput()
Definition: model.cc:980
Model(const std::string &name)
static Annotation VarRef(Variable *const var)
Definition: model.cc:881
static Argument VarRef(Variable *const var)
Definition: model.cc:519
static Domain AllFloats()
Definition: model.cc:100
static Argument DomainList(std::vector< Domain > domains)
Definition: model.cc:512
Variable * AddFloatConstant(double value)
Definition: model.cc:1019
util::MutableVectorIteration< Annotation > mutable_search_annotations()
bool RemoveValue(int64_t value)
Definition: model.cc:430
void Satisfy(std::vector< Annotation > search_annotations)
Definition: model.cc:1042
std::vector< Annotation > annotations
Collection of objects used to extend the Constraint Solver library.
void SetObjective(Variable *obj)
static Annotation Empty()
Definition: model.cc:820
static Domain FloatInterval(double lb, double ub)
Definition: model.cc:107
std::vector< Variable * > variables
static Argument FloatValue(double value)
Definition: model.cc:552
std::vector< Argument > arguments
static Domain FloatValue(double value)
Definition: model.cc:115
IntVar * var
Definition: expr_array.cc:1874
Variable * AddVariable(const std::string &name, const Domain &domain, bool defined)
Definition: model.cc:1004
bool IntersectWithFloatDomain(const Domain &domain)
Definition: model.cc:247
static Annotation FunctionCallWithArguments(const std::string &id, std::vector< Annotation > args)
Definition: model.cc:846
const std::vector< Annotation > & search_annotations() const
static Argument Interval(int64_t imin, int64_t imax)
Definition: model.cc:497
bool IntersectWithDomain(const Domain &domain)
Definition: model.cc:122
void RemoveArg(int arg_pos)
Definition: model.cc:804
static Argument IntegerList(std::vector< int64_t > values)
Definition: model.cc:505
const std::vector< Variable * > & variables() const
static Domain SetOfIntegerValue(int64_t value)
Definition: model.cc:80
static Annotation String(const std::string &str)
Definition: model.cc:899
std::string DebugString() const
Definition: model.cc:1061
int64_t value
std::vector< int64_t > values
Variable * Var() const
Definition: model.cc:734
void AddConstraint(const std::string &id, std::vector< Argument > arguments, bool is_domain)
Definition: model.cc:1026
bool OverlapsDomain(const Domain &other) const
Definition: model.cc:418