OR-Tools  9.1
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"
27
28namespace operations_research {
29namespace fz {
30
31struct Constraint;
32class 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.
50struct 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.
119struct 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.
154struct 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
206 std::vector<int64_t> values;
207 std::vector<Variable*> variables;
208 std::vector<Domain> domains;
209 std::vector<double> floats;
210};
211
212// A constraint has a type, some arguments, and a few tags. Typically, a
213// Constraint is on the heap, and owned by the global Model object.
215 Constraint(const std::string& t, std::vector<Argument> args,
216 bool strong_propag)
217 : type(t),
218 arguments(std::move(args)),
219 strong_propagation(strong_propag),
220 active(true),
222
223 std::string DebugString() const;
224
225 // Helpers to be used during presolve.
226 void MarkAsInactive();
227 // Helper method to remove one argument.
228 void RemoveArg(int arg_pos);
229 // Set as a False constraint.
230 void SetAsFalse();
231
232 // The flatzinc type of the constraint (i.e. "int_eq" for integer equality)
233 // stored as a string.
234 std::string type;
235 std::vector<Argument> arguments;
236 // Is true if the constraint should use the strongest level of propagation.
237 // This is a hint in the model. For instance, in the AllDifferent constraint,
238 // there are different algorithms to propagate with different pruning/speed
239 // ratios. When strong_propagation is true, one should use, if possible, the
240 // algorithm with the strongest pruning.
242 // Indicates if the constraint is active. Presolve can make it inactive by
243 // propagating it, or by regrouping it. Once a constraint is inactive, it is
244 // logically removed from the model, it is not extracted, and it is ignored by
245 // presolve.
246 bool active : 1;
247
248 // Indicates if presolve has finished propagating this constraint.
250};
251
252// An annotation is a set of information. It has two use cases. One during
253// parsing to store intermediate information on model objects (i.e. the defines
254// part of a constraint). The other use case is to store all search
255// declarations. This persists after model parsing.
257 enum Type {
266 };
267
268 static Annotation Empty();
269 static Annotation AnnotationList(std::vector<Annotation> list);
270 static Annotation Identifier(const std::string& id);
271 static Annotation FunctionCallWithArguments(const std::string& id,
272 std::vector<Annotation> args);
273 static Annotation FunctionCall(const std::string& id);
274 static Annotation Interval(int64_t interval_min, int64_t interval_max);
275 static Annotation IntegerValue(int64_t value);
276 static Annotation VarRef(Variable* const var);
277 static Annotation VarRefArray(std::vector<Variable*> variables);
278 static Annotation String(const std::string& str);
279
280 std::string DebugString() const;
281 bool IsFunctionCallWithIdentifier(const std::string& identifier) const {
282 return type == FUNCTION_CALL && id == identifier;
283 }
284 // Copy all the variable references contained in this annotation (and its
285 // children). Depending on the type of this annotation, there can be zero,
286 // one, or several.
287 void AppendAllVariables(std::vector<Variable*>* vars) const;
288
292 std::string id;
293 std::vector<Annotation> annotations;
294 std::vector<Variable*> variables;
295 std::string string_value;
296};
297
298// Information on what should be displayed when a solution is found.
299// It follows the flatzinc specification (www.minizinc.org).
301 struct Bounds {
302 Bounds(int64_t min_value_, int64_t max_value_)
303 : min_value(min_value_), max_value(max_value_) {}
304 std::string DebugString() const;
305 int64_t min_value;
306 int64_t max_value;
307 };
308
309 // Will output: name = <variable value>.
310 static SolutionOutputSpecs SingleVariable(const std::string& name,
312 bool display_as_boolean);
313 // Will output (for example):
314 // name = array2d(min1..max1, min2..max2, [list of variable values])
315 // for a 2d array (bounds.size() == 2).
317 const std::string& name, std::vector<Bounds> bounds,
318 std::vector<Variable*> flat_variables, bool display_as_boolean);
319 // Empty output.
321
322 std::string DebugString() const;
323
324 std::string name;
326 std::vector<Variable*> flat_variables;
327 // These are the starts and ends of intervals for displaying (potentially
328 // multi-dimensional) arrays.
329 std::vector<Bounds> bounds;
331};
332
333class Model {
334 public:
335 explicit Model(const std::string& name)
336 : name_(name), objective_(nullptr), maximize_(true) {}
337 ~Model();
338
339 // ----- Builder methods -----
340
341 // The objects returned by AddVariable(), AddConstant(), and AddConstraint()
342 // are owned by the model and will remain live for its lifetime.
343 Variable* AddVariable(const std::string& name, const Domain& domain,
344 bool defined);
345 Variable* AddConstant(int64_t value);
347 // Creates and add a constraint to the model.
348 void AddConstraint(const std::string& id, std::vector<Argument> arguments,
349 bool is_domain);
350 void AddConstraint(const std::string& id, std::vector<Argument> arguments);
352
353 // Set the search annotations and the objective: either simply satisfy the
354 // problem, or minimize or maximize the given variable (which must have been
355 // added with AddVariable() already).
356 void Satisfy(std::vector<Annotation> search_annotations);
357 void Minimize(Variable* obj, std::vector<Annotation> search_annotations);
358 void Maximize(Variable* obj, std::vector<Annotation> search_annotations);
359
360 bool IsInconsistent() const;
361
362 // ----- Accessors and mutators -----
363
364 const std::vector<Variable*>& variables() const { return variables_; }
365 const std::vector<Constraint*>& constraints() const { return constraints_; }
366 const std::vector<Annotation>& search_annotations() const {
367 return search_annotations_;
368 }
369#if !defined(SWIG)
371 return util::MutableVectorIteration<Annotation>(&search_annotations_);
372 }
373#endif
374 const std::vector<SolutionOutputSpecs>& output() const { return output_; }
375#if !defined(SWIG)
378 }
379#endif
380 bool maximize() const { return maximize_; }
381 Variable* objective() const { return objective_; }
382 void SetObjective(Variable* obj) { objective_ = obj; }
383
384 // Services.
385 std::string DebugString() const;
386
387 const std::string& name() const { return name_; }
388
389 private:
390 const std::string name_;
391 // owned.
392 // TODO(user): use unique_ptr
393 std::vector<Variable*> variables_;
394 // owned.
395 // TODO(user): use unique_ptr
396 std::vector<Constraint*> constraints_;
397 // The objective variable (it belongs to variables_).
398 Variable* objective_;
399 bool maximize_;
400 // All search annotations are stored as a vector of Annotation.
401 std::vector<Annotation> search_annotations_;
402 std::vector<SolutionOutputSpecs> output_;
403};
404
405// Stand-alone statistics class on the model.
406// TODO(user): Clean up API to pass a Model* in argument.
408 public:
409 explicit ModelStatistics(const Model& model, SolverLogger* logger)
410 : model_(model), logger_(logger) {}
412 return constraints_per_variables_[var].size();
413 }
414 void BuildStatistics();
415 void PrintStatistics() const;
416
417 private:
418 const Model& model_;
419 SolverLogger* logger_;
420 std::map<std::string, std::vector<Constraint*>> constraints_per_type_;
421 absl::flat_hash_map<const Variable*, std::vector<Constraint*>>
422 constraints_per_variables_;
423};
424
425// Helper method to flatten Search annotations.
426void FlattenAnnotations(const Annotation& ann, std::vector<Annotation>* out);
427
428} // namespace fz
429} // namespace operations_research
430
431#endif // OR_TOOLS_FLATZINC_MODEL_H_
util::MutableVectorIteration< SolutionOutputSpecs > mutable_output()
const std::string & name() const
const std::vector< Annotation > & search_annotations() const
Variable * AddVariable(const std::string &name, const Domain &domain, bool defined)
Definition: model.cc:963
const std::vector< SolutionOutputSpecs > & output() const
Model(const std::string &name)
void SetObjective(Variable *obj)
Variable * AddConstant(int64_t value)
Definition: model.cc:971
void Satisfy(std::vector< Annotation > search_annotations)
Definition: model.cc:1001
std::string DebugString() const
Definition: model.cc:1020
void AddOutput(SolutionOutputSpecs output)
Definition: model.cc:997
util::MutableVectorIteration< Annotation > mutable_search_annotations()
void AddConstraint(const std::string &id, std::vector< Argument > arguments, bool is_domain)
Definition: model.cc:985
void Maximize(Variable *obj, std::vector< Annotation > search_annotations)
Definition: model.cc:1013
void Minimize(Variable *obj, std::vector< Annotation > search_annotations)
Definition: model.cc:1006
Variable * AddFloatConstant(double value)
Definition: model.cc:978
const std::vector< Constraint * > & constraints() const
const std::vector< Variable * > & variables() const
ModelStatistics(const Model &model, SolverLogger *logger)
int64_t value
IntVar * var
Definition: expr_array.cc:1874
GRBmodel * model
void FlattenAnnotations(const Annotation &ann, std::vector< Annotation > *out)
Definition: model.cc:1099
Collection of objects used to extend the Constraint Solver library.
STL namespace.
static Annotation IntegerValue(int64_t value)
Definition: model.cc:833
void AppendAllVariables(std::vector< Variable * > *vars) const
Definition: model.cc:867
std::string DebugString() const
Definition: model.cc:876
static Annotation FunctionCall(const std::string &id)
Definition: model.cc:816
static Annotation AnnotationList(std::vector< Annotation > list)
Definition: model.cc:787
std::vector< Variable * > variables
static Annotation String(const std::string &str)
Definition: model.cc:858
static Annotation Identifier(const std::string &id)
Definition: model.cc:796
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:825
static Annotation VarRefArray(std::vector< Variable * > variables)
Definition: model.cc:849
static Annotation VarRef(Variable *const var)
Definition: model.cc:840
static Annotation Empty()
Definition: model.cc:779
static Annotation FunctionCallWithArguments(const std::string &id, std::vector< Annotation > args)
Definition: model.cc:805
static Argument FloatInterval(double lb, double ub)
Definition: model.cc:559
static Argument DomainList(std::vector< Domain > domains)
Definition: model.cc:512
Variable * VarAt(int pos) const
Definition: model.cc:717
static Argument VarRef(Variable *const var)
Definition: model.cc:519
bool Contains(int64_t value) const
Definition: model.cc:670
static Argument IntegerList(std::vector< int64_t > values)
Definition: model.cc:505
static Argument VoidArgument()
Definition: model.cc:533
static Argument VarRefArray(std::vector< Variable * > vars)
Definition: model.cc:526
static Argument IntegerValue(int64_t value)
Definition: model.cc:490
static Argument Interval(int64_t imin, int64_t imax)
Definition: model.cc:497
std::string DebugString() const
Definition: model.cc:574
std::vector< Variable * > variables
static Argument FloatValue(double value)
Definition: model.cc:552
std::vector< int64_t > values
int64_t ValueAt(int pos) const
Definition: model.cc:688
static Argument FloatList(std::vector< double > floats)
Definition: model.cc:567
Variable * Var() const
Definition: model.cc:713
static Argument FromDomain(const Domain &domain)
Definition: model.cc:539
Constraint(const std::string &t, std::vector< Argument > args, bool strong_propag)
void RemoveArg(int arg_pos)
Definition: model.cc:763
std::string DebugString() const
Definition: model.cc:753
std::vector< Argument > arguments
static Domain IntegerValue(int64_t value)
Definition: model.cc:46
static Domain EmptyDomain()
Definition: model.cc:98
bool Contains(int64_t value) const
Definition: model.cc:356
bool OverlapsDomain(const Domain &other) const
Definition: model.cc:418
static Domain SetOfAllInt64()
Definition: model.cc:74
static Domain Boolean()
Definition: model.cc:60
bool IntersectWithSingleton(int64_t value)
Definition: model.cc:148
static Domain SetOfInterval(int64_t included_min, int64_t included_max)
Definition: model.cc:86
static Domain IntegerList(std::vector< int64_t > values)
Definition: model.cc:33
std::string DebugString() const
Definition: model.cc:461
bool IntersectWithInterval(int64_t interval_min, int64_t interval_max)
Definition: model.cc:152
static Domain AllInt64()
Definition: model.cc:40
bool IntersectWithFloatDomain(const Domain &domain)
Definition: model.cc:247
bool IntersectWithDomain(const Domain &domain)
Definition: model.cc:122
std::vector< double > float_values
static Domain FloatInterval(double lb, double ub)
Definition: model.cc:107
bool OverlapsIntInterval(int64_t lb, int64_t ub) const
Definition: model.cc:404
static Domain SetOfIntegerValue(int64_t value)
Definition: model.cc:80
bool OverlapsIntList(const std::vector< int64_t > &vec) const
Definition: model.cc:380
static Domain Interval(int64_t included_min, int64_t included_max)
Definition: model.cc:52
std::vector< int64_t > values
static Domain SetOfBoolean()
Definition: model.cc:92
static Domain SetOfIntegerList(std::vector< int64_t > values)
Definition: model.cc:68
static Domain FloatValue(double value)
Definition: model.cc:115
bool IntersectWithListOfIntegers(const std::vector< int64_t > &integers)
Definition: model.cc:200
static Domain AllFloats()
Definition: model.cc:100
bool RemoveValue(int64_t value)
Definition: model.cc:430
Bounds(int64_t min_value_, int64_t max_value_)
static SolutionOutputSpecs VoidOutput()
Definition: model.cc:939
static SolutionOutputSpecs SingleVariable(const std::string &name, Variable *variable, bool display_as_boolean)
Definition: model.cc:918
static SolutionOutputSpecs MultiDimensionalArray(const std::string &name, std::vector< Bounds > bounds, std::vector< Variable * > flat_variables, bool display_as_boolean)
Definition: model.cc:927
std::string DebugString() const
Definition: model.cc:741
bool Merge(const std::string &other_name, const Domain &other_domain, bool other_temporary)
Definition: model.cc:731