Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
model.h
Go to the documentation of this file.
1// Copyright 2010-2024 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#include <utility>
21#include <vector>
22
23#include "absl/container/flat_hash_map.h"
24#include "absl/strings/string_view.h"
25#include "absl/types/span.h"
28
29namespace operations_research {
30namespace fz {
31
32struct Constraint;
33class Model;
34
35// A domain represents the possible values of a variable, and its type
36// (which carries display information, i.e. a Boolean will be displayed
37// differently than an integer with domain {0, 1}).
38// It can be:
39// - an explicit list of all possible values, in which case is_interval is
40// false. If the list is empty, then the domain is empty.
41// - an interval, in which case is_interval is true and values.size() == 2,
42// and the interval is [values[0], values[1]].
43// - all integers, in which case values is empty, and is_interval is true.
44// Note that semi-infinite intervals aren't supported.
45// - a Boolean domain({ 0, 1 } with Boolean display tag).
46// TODO(user): Rework domains, all int64_t should be kintmin..kint64max.
47// It is a bit tricky though as we must take care of overflows.
48// If is_a_set is true, then this domain has a set semantics. For a set
49// variable, any subset of the initial set of values is a valid assignment,
50// instead of exactly one value.
51struct Domain {
52 // The values will be sorted and duplicate values will be removed.
53 static Domain IntegerList(std::vector<int64_t> values);
54 static Domain AllInt64();
55 static Domain IntegerValue(int64_t value);
56 static Domain Interval(int64_t included_min, int64_t included_max);
57 static Domain Boolean();
58 static Domain SetOfIntegerList(std::vector<int64_t> values);
59 static Domain SetOfAllInt64();
60 static Domain SetOfIntegerValue(int64_t value);
61 static Domain SetOfInterval(int64_t included_min, int64_t included_max);
62 static Domain SetOfBoolean();
63 static Domain EmptyDomain();
64 static Domain AllFloats();
65 static Domain FloatValue(double value);
66 static Domain FloatInterval(double lb, double ub);
67 // TODO(user): Do we need SetOfFloats() ?
68
69 bool HasOneValue() const;
70 bool empty() const;
71
72 // Returns the min of the domain.
73 int64_t Min() const;
74
75 // Returns the max of the domain.
76 int64_t Max() const;
77
78 // Returns the value of the domain. HasOneValue() must return true.
79 int64_t Value() const;
80
81 // Returns true if the domain is [kint64min..kint64max]
82 bool IsAllInt64() const;
83
84 // Various inclusion tests on a domain.
85 bool Contains(int64_t value) const;
86 bool OverlapsIntList(const std::vector<int64_t>& vec) const;
87 bool OverlapsIntInterval(int64_t lb, int64_t ub) const;
88 bool OverlapsDomain(const Domain& other) const;
89
90 // All the following modifiers change the internal representation
91 // list to interval or interval to list.
92 bool IntersectWithSingleton(int64_t value);
93 bool IntersectWithDomain(const Domain& domain);
94 bool IntersectWithInterval(int64_t interval_min, int64_t interval_max);
95 bool IntersectWithListOfIntegers(absl::Span<const int64_t> integers);
96 bool IntersectWithFloatDomain(const Domain& domain);
97
98 // Returns true iff the value did belong to the domain, and was removed.
99 // Try to remove the value. It returns true if it was actually removed.
100 // If the value is inside a large interval, then it will not be removed.
101 bool RemoveValue(int64_t value);
102 // Sets the empty float domain. Returns true.
103 bool SetEmptyFloatDomain();
104 std::string DebugString() const;
105
106 // These should never be modified from outside the class.
107 std::vector<int64_t> values;
108 bool is_interval = false;
109 bool display_as_boolean = false;
110 // Indicates if the domain was created as a set domain.
111 bool is_a_set = false;
112 // Float domain.
113 bool is_float = false;
114 std::vector<double> float_values;
115};
116
117// An int var is a name with a domain of possible values, along with
118// some tags. Typically, a Variable is on the heap, and owned by the
119// global Model object.
120struct Variable {
121 // This method tries to unify two variables. This can happen during the
122 // parsing of the model or during presolve. This is possible if at least one
123 // of the two variable is not the target of a constraint. (otherwise it
124 // returns false).
125 // The semantic of the merge is the following:
126 // - the resulting domain is the intersection of the two domains.
127 // - if one variable is not temporary, the result is not temporary.
128 // - if one variable is temporary, the name is the name of the other
129 // variable. If both variables are temporary or both variables are not
130 // temporary, the name is chosen arbitrarily between the two names.
131 bool Merge(absl::string_view other_name, const Domain& other_domain,
132 bool other_temporary);
133
134 std::string DebugString() const;
135
136 std::string name;
138 // Indicates if the variable is a temporary variable created when flattening
139 // the model. For instance, if you write x == y * z + y, then it will be
140 // expanded into y * z == t and x = t + y. And t will be a temporary variable.
141 bool temporary : 1;
142 // Indicates if the variable should be created at all. A temporary variable
143 // can be unreachable in the active model if nobody uses it. In that case,
144 // there is no need to create it.
145 bool active : 1;
146
147 private:
148 friend class Model;
149
150 Variable(absl::string_view name_, const Domain& domain_, bool temporary_);
151};
152
153// An argument is either an integer value, an integer domain, a
154// reference to a variable, or an array of variable references.
155struct Argument {
168
169 static Argument IntegerValue(int64_t value);
170 static Argument Interval(int64_t imin, int64_t imax);
171 static Argument IntegerList(std::vector<int64_t> values);
172 static Argument DomainList(std::vector<Domain> domains);
173 static Argument FloatValue(double value);
174 static Argument FloatInterval(double lb, double ub);
175 static Argument FloatList(std::vector<double> floats);
176 static Argument VarRef(Variable* var);
177 static Argument VarRefArray(std::vector<Variable*> vars);
178 static Argument VoidArgument();
179 static Argument FromDomain(const Domain& domain);
180
181 std::string DebugString() const;
182
183 // Returns true if the argument is a variable.
184 bool IsVariable() const;
185 // Returns true if the argument has only one value (integer value, integer
186 // list of size 1, interval of size 1, or variable with a singleton domain).
187 bool HasOneValue() const;
188 // Returns the value of the argument. Does DCHECK(HasOneValue()).
189 int64_t Value() const;
190 // Returns true if it an integer list, or an array of integer
191 // variables (or domain) each having only one value.
192 bool IsArrayOfValues() const;
193 // Returns true if the argument is an integer value, an integer
194 // list, or an interval, and it contains the given value.
195 // It will check that the type is actually one of the above.
196 bool Contains(int64_t value) const;
197 // Returns the value of the pos-th element.
198 int64_t ValueAt(int pos) const;
199 // Returns the variable inside the argument if the type is VAR_REF,
200 // or nullptr otherwise.
201 Variable* Var() const;
202 // Returns the variable at position pos inside the argument if the type is
203 // VAR_REF_ARRAY or nullptr otherwise.
204 Variable* VarAt(int pos) const;
205 // Returns true is the pos-th argument is fixed.
206 bool HasOneValueAt(int pos) const;
207 // Returns the number of object in the argument.
208 int Size() const;
209
211 std::vector<int64_t> values;
212 std::vector<Variable*> variables;
213 std::vector<Domain> domains;
214 std::vector<double> floats;
215};
216
217// A constraint has a type, some arguments, and a few tags. Typically, a
218// Constraint is on the heap, and owned by the global Model object.
220 Constraint(absl::string_view t, std::vector<Argument> args,
221 bool strong_propag)
222 : type(t),
223 arguments(std::move(args)),
224 strong_propagation(strong_propag),
225 active(true),
227
228 std::string DebugString() const;
229
230 // Helpers to be used during presolve.
231 void MarkAsInactive();
232 // Helper method to remove one argument.
233 void RemoveArg(int arg_pos);
234 // Set as a False constraint.
235 void SetAsFalse();
236
237 // The flatzinc type of the constraint (i.e. "int_eq" for integer equality)
238 // stored as a string.
239 std::string type;
240 std::vector<Argument> arguments;
241 // Is true if the constraint should use the strongest level of propagation.
242 // This is a hint in the model. For instance, in the AllDifferent constraint,
243 // there are different algorithms to propagate with different pruning/speed
244 // ratios. When strong_propagation is true, one should use, if possible, the
245 // algorithm with the strongest pruning.
247 // Indicates if the constraint is active. Presolve can make it inactive by
248 // propagating it, or by regrouping it. Once a constraint is inactive, it is
249 // logically removed from the model, it is not extracted, and it is ignored by
250 // presolve.
251 bool active : 1;
252
253 // Indicates if presolve has finished propagating this constraint.
255};
256
257// An annotation is a set of information. It has two use cases. One during
258// parsing to store intermediate information on model objects (i.e. the defines
259// part of a constraint). The other use case is to store all search
260// declarations. This persists after model parsing.
273
274 static Annotation Empty();
275 static Annotation AnnotationList(std::vector<Annotation> list);
276 static Annotation Identifier(absl::string_view id);
277 static Annotation FunctionCallWithArguments(absl::string_view id,
278 std::vector<Annotation> args);
279 static Annotation FunctionCall(absl::string_view id);
280 static Annotation Interval(int64_t interval_min, int64_t interval_max);
281 static Annotation IntegerValue(int64_t value);
282 static Annotation IntegerList(const std::vector<int64_t>& values);
283 static Annotation VarRef(Variable* var);
284 static Annotation VarRefArray(std::vector<Variable*> variables);
285 static Annotation String(absl::string_view str);
286
287 std::string DebugString() const;
288 bool IsFunctionCallWithIdentifier(absl::string_view identifier) const {
289 return type == FUNCTION_CALL && id == identifier;
290 }
291 // Copy all the variable references contained in this annotation (and its
292 // children). Depending on the type of this annotation, there can be zero,
293 // one, or several.
294 void AppendAllVariables(std::vector<Variable*>* vars) const;
295
299 std::string id;
300 std::vector<Annotation> annotations;
301 std::vector<Variable*> variables;
302 std::vector<int64_t> values;
303 std::string string_value;
304};
305
306// Information on what should be displayed when a solution is found.
307// It follows the flatzinc specification (www.minizinc.org).
309 struct Bounds {
310 Bounds(int64_t min_value_, int64_t max_value_)
311 : min_value(min_value_), max_value(max_value_) {}
312 std::string DebugString() const;
313 int64_t min_value;
314 int64_t max_value;
315 };
316
317 // Will output: name = <variable value>.
318 static SolutionOutputSpecs SingleVariable(absl::string_view name,
320 bool display_as_boolean);
321 // Will output (for example):
322 // name = array2d(min1..max1, min2..max2, [list of variable values])
323 // for a 2d array (bounds.size() == 2).
325 absl::string_view name, std::vector<Bounds> bounds,
326 std::vector<Variable*> flat_variables, bool display_as_boolean);
327 // Empty output.
329
330 std::string DebugString() const;
331
332 std::string name;
334 std::vector<Variable*> flat_variables;
335 // These are the starts and ends of intervals for displaying (potentially
336 // multi-dimensional) arrays.
337 std::vector<Bounds> bounds;
339};
340
341class Model {
342 public:
343 explicit Model(absl::string_view name)
344 : name_(name), objective_(nullptr), maximize_(true) {}
345 ~Model();
346
347 // ----- Builder methods -----
348
349 // The objects returned by AddVariable(), AddConstant(), and AddConstraint()
350 // are owned by the model and will remain live for its lifetime.
351 Variable* AddVariable(absl::string_view name, const Domain& domain,
352 bool defined);
353 Variable* AddConstant(int64_t value);
355 // Creates and add a constraint to the model.
356 void AddConstraint(absl::string_view id, std::vector<Argument> arguments,
357 bool is_domain);
358 void AddConstraint(absl::string_view id, std::vector<Argument> arguments);
360
361 // Set the search annotations and the objective: either simply satisfy the
362 // problem, or minimize or maximize the given variable (which must have been
363 // added with AddVariable() already).
364 void Satisfy(std::vector<Annotation> search_annotations);
365 void Minimize(Variable* obj, std::vector<Annotation> search_annotations);
366 void Maximize(Variable* obj, std::vector<Annotation> search_annotations);
367
368 bool IsInconsistent() const;
369
370 // ----- Accessors and mutators -----
371
372 const std::vector<Variable*>& variables() const { return variables_; }
373 const std::vector<Constraint*>& constraints() const { return constraints_; }
374 const std::vector<Annotation>& search_annotations() const {
375 return search_annotations_;
376 }
377#if !defined(SWIG)
381#endif
382 const std::vector<SolutionOutputSpecs>& output() const { return output_; }
383#if !defined(SWIG)
387#endif
388 bool maximize() const { return maximize_; }
389 Variable* objective() const { return objective_; }
390 const std::vector<Variable*>& float_objective_variables() const {
391 return float_objective_variables_;
392 }
393 const std::vector<double>& float_objective_coefficients() const {
394 return float_objective_coefficients_;
395 }
396 double float_objective_offset() const { return float_objective_offset_; }
397 void SetObjective(Variable* obj) { objective_ = obj; }
398 void ClearObjective() { objective_ = nullptr; }
400 float_objective_variables_.push_back(var);
401 float_objective_coefficients_.push_back(coeff);
402 }
404 float_objective_offset_ = offset;
405 }
406
407 // Services.
408 std::string DebugString() const;
409
410 const std::string& name() const { return name_; }
411
412 private:
413 const std::string name_;
414 // owned.
415 // TODO(user): use unique_ptr
416 std::vector<Variable*> variables_;
417 // owned.
418 // TODO(user): use unique_ptr
419 std::vector<Constraint*> constraints_;
420 // The objective variable (it belongs to variables_).
421 Variable* objective_;
422 bool maximize_;
423 std::vector<Variable*> float_objective_variables_;
424 std::vector<double> float_objective_coefficients_;
425 double float_objective_offset_ = 0.0;
426 // All search annotations are stored as a vector of Annotation.
427 std::vector<Annotation> search_annotations_;
428 std::vector<SolutionOutputSpecs> output_;
429};
430
431// Stand-alone statistics class on the model.
432// TODO(user): Clean up API to pass a Model* in argument.
434 public:
435 explicit ModelStatistics(const Model& model, SolverLogger* logger)
436 : model_(model), logger_(logger) {}
438 return constraints_per_variables_[var].size();
439 }
440 void BuildStatistics();
441 void PrintStatistics() const;
442
443 private:
444 const Model& model_;
445 SolverLogger* logger_;
446 std::map<std::string, std::vector<Constraint*>> constraints_per_type_;
447 absl::flat_hash_map<const Variable*, std::vector<Constraint*>>
448 constraints_per_variables_;
449};
450
451// Helper method to flatten Search annotations.
452void FlattenAnnotations(const Annotation& ann, std::vector<Annotation>* out);
453
454} // namespace fz
455} // namespace operations_research
456
457#endif // OR_TOOLS_FLATZINC_MODEL_H_
int NumVariableOccurrences(Variable *var)
Definition model.h:437
ModelStatistics(const Model &model, SolverLogger *logger)
Definition model.h:435
void PrintStatistics() const
--— Model statistics --—
Definition model.cc:1134
void AddConstraint(absl::string_view id, std::vector< Argument > arguments, bool is_domain)
Creates and add a constraint to the model.
Definition model.cc:1047
const std::vector< double > & float_objective_coefficients() const
Definition model.h:393
void AddFloatingPointObjectiveTerm(Variable *var, double coeff)
Definition model.h:399
const std::vector< Variable * > & float_objective_variables() const
Definition model.h:390
util::MutableVectorIteration< SolutionOutputSpecs > mutable_output()
Definition model.h:384
Model(absl::string_view name)
Definition model.h:343
const std::vector< Constraint * > & constraints() const
Definition model.h:373
void SetObjective(Variable *obj)
Definition model.h:397
void SetFloatingPointObjectiveOffset(double offset)
Definition model.h:403
~Model()
--— Model --—
Definition model.cc:1020
const std::vector< SolutionOutputSpecs > & output() const
Definition model.h:382
const std::vector< Variable * > & variables() const
--— Accessors and mutators --—
Definition model.h:372
Variable * AddFloatConstant(double value)
Definition model.cc:1040
std::string DebugString() const
Services.
Definition model.cc:1082
void AddOutput(SolutionOutputSpecs output)
Definition model.cc:1059
void Maximize(Variable *obj, std::vector< Annotation > search_annotations)
Definition model.cc:1075
double float_objective_offset() const
Definition model.h:396
void Satisfy(std::vector< Annotation > search_annotations)
Definition model.cc:1063
const std::string & name() const
Definition model.h:410
const std::vector< Annotation > & search_annotations() const
Definition model.h:374
Variable * objective() const
Definition model.h:389
Variable * AddVariable(absl::string_view name, const Domain &domain, bool defined)
--— Builder methods --—
Definition model.cc:1025
util::MutableVectorIteration< Annotation > mutable_search_annotations()
Definition model.h:378
void Minimize(Variable *obj, std::vector< Annotation > search_annotations)
Definition model.cc:1068
Variable * AddConstant(int64_t value)
Definition model.cc:1033
int64_t value
IntVar * var
GRBmodel * model
void FlattenAnnotations(const Annotation &ann, std::vector< Annotation > *out)
Flatten Search annotations.
Definition model.cc:1169
In SWIG mode, we don't want anything besides these top-level includes.
STL namespace.
static Annotation String(absl::string_view str)
Definition model.cc:917
static Annotation FunctionCall(absl::string_view id)
Definition model.cc:867
void AppendAllVariables(std::vector< Variable * > *vars) const
Definition model.cc:926
static Annotation FunctionCallWithArguments(absl::string_view id, std::vector< Annotation > args)
Definition model.cc:856
static Annotation Empty()
--— Annotation --—
Definition model.cc:830
static Annotation AnnotationList(std::vector< Annotation > list)
Definition model.cc:838
static Annotation IntegerList(const std::vector< int64_t > &values)
Definition model.cc:891
static Annotation VarRefArray(std::vector< Variable * > variables)
Definition model.cc:908
static Annotation Identifier(absl::string_view id)
Definition model.cc:847
std::vector< Variable * > variables
Definition model.h:301
std::vector< int64_t > values
Definition model.h:302
bool IsFunctionCallWithIdentifier(absl::string_view identifier) const
Definition model.h:288
static Annotation VarRef(Variable *var)
Definition model.cc:899
static Annotation IntegerValue(int64_t value)
Definition model.cc:884
static Annotation Interval(int64_t interval_min, int64_t interval_max)
Definition model.cc:876
std::vector< Annotation > annotations
Definition model.h:300
std::string DebugString() const
Definition model.cc:935
std::vector< Variable * > variables
Definition model.h:212
static Argument FloatList(std::vector< double > floats)
Definition model.cc:574
int Size() const
Returns the number of object in the argument.
Definition model.cc:749
static Argument FloatValue(double value)
Definition model.cc:559
bool IsVariable() const
Returns true if the argument is a variable.
Definition model.cc:614
std::vector< Domain > domains
Definition model.h:213
bool HasOneValueAt(int pos) const
Returns true is the pos-th argument is fixed.
Definition model.cc:718
Variable * VarAt(int pos) const
Definition model.cc:745
std::string DebugString() const
Definition model.cc:581
static Argument VoidArgument()
Definition model.cc:540
static Argument IntegerValue(int64_t value)
--— Argument --—
Definition model.cc:497
int64_t ValueAt(int pos) const
Returns the value of the pos-th element.
Definition model.cc:695
static Argument Interval(int64_t imin, int64_t imax)
Definition model.cc:504
static Argument FromDomain(const Domain &domain)
Definition model.cc:546
int64_t Value() const
Returns the value of the argument. Does DCHECK(HasOneValue()).
Definition model.cc:622
static Argument IntegerList(std::vector< int64_t > values)
Definition model.cc:512
static Argument VarRef(Variable *var)
Definition model.cc:526
static Argument FloatInterval(double lb, double ub)
Definition model.cc:566
std::vector< double > floats
Definition model.h:214
bool Contains(int64_t value) const
Definition model.cc:677
static Argument DomainList(std::vector< Domain > domains)
Definition model.cc:519
static Argument VarRefArray(std::vector< Variable * > vars)
Definition model.cc:533
std::vector< int64_t > values
Definition model.h:211
std::string DebugString() const
--— Constraint --—
Definition model.cc:804
Constraint(absl::string_view t, std::vector< Argument > args, bool strong_propag)
Definition model.h:220
void MarkAsInactive()
Helpers to be used during presolve.
Definition model.cc:818
void RemoveArg(int arg_pos)
Helper method to remove one argument.
Definition model.cc:814
void SetAsFalse()
Set as a False constraint.
Definition model.cc:823
bool presolve_propagation_done
Indicates if presolve has finished propagating this constraint.
Definition model.h:254
std::vector< Argument > arguments
Definition model.h:240
static Domain Boolean()
Definition model.cc:67
static Domain AllFloats()
Definition model.cc:107
bool IntersectWithSingleton(int64_t value)
Definition model.cc:155
static Domain IntegerList(std::vector< int64_t > values)
The values will be sorted and duplicate values will be removed.
Definition model.cc:40
bool OverlapsDomain(const Domain &other) const
Definition model.cc:425
static Domain IntegerValue(int64_t value)
Definition model.cc:53
int64_t Max() const
Returns the max of the domain.
Definition model.cc:346
std::string DebugString() const
Definition model.cc:468
static Domain FloatValue(double value)
Definition model.cc:122
bool IntersectWithInterval(int64_t interval_min, int64_t interval_max)
Definition model.cc:159
bool IntersectWithDomain(const Domain &domain)
Definition model.cc:129
bool SetEmptyFloatDomain()
Sets the empty float domain. Returns true.
Definition model.cc:324
bool is_a_set
Indicates if the domain was created as a set domain.
Definition model.h:111
static Domain EmptyDomain()
Definition model.cc:105
bool IntersectWithFloatDomain(const Domain &domain)
Definition model.cc:254
bool RemoveValue(int64_t value)
Definition model.cc:437
static Domain FloatInterval(double lb, double ub)
Definition model.cc:114
int64_t Min() const
Returns the min of the domain.
Definition model.cc:340
std::vector< int64_t > values
These should never be modified from outside the class.
Definition model.h:107
bool is_float
Float domain.
Definition model.h:113
static Domain SetOfBoolean()
Definition model.cc:99
static Domain Interval(int64_t included_min, int64_t included_max)
Definition model.cc:59
static Domain SetOfAllInt64()
Definition model.cc:81
static Domain SetOfInterval(int64_t included_min, int64_t included_max)
Definition model.cc:93
bool Contains(int64_t value) const
Various inclusion tests on a domain.
Definition model.cc:363
bool OverlapsIntInterval(int64_t lb, int64_t ub) const
Definition model.cc:411
std::vector< double > float_values
Definition model.h:114
static Domain SetOfIntegerList(std::vector< int64_t > values)
Definition model.cc:75
static Domain SetOfIntegerValue(int64_t value)
Definition model.cc:87
int64_t Value() const
Returns the value of the domain. HasOneValue() must return true.
Definition model.cc:352
static Domain AllInt64()
Definition model.cc:47
bool IntersectWithListOfIntegers(absl::Span< const int64_t > integers)
Definition model.cc:207
bool IsAllInt64() const
Returns true if the domain is [kint64min..kint64max].
Definition model.cc:357
bool OverlapsIntList(const std::vector< int64_t > &vec) const
Definition model.cc:387
std::string DebugString() const
--— SolutionOutputSpecs --—
Definition model.cc:976
Bounds(int64_t min_value_, int64_t max_value_)
Definition model.h:310
std::vector< Variable * > flat_variables
Definition model.h:334
static SolutionOutputSpecs MultiDimensionalArray(absl::string_view name, std::vector< Bounds > bounds, std::vector< Variable * > flat_variables, bool display_as_boolean)
Definition model.cc:989
static SolutionOutputSpecs VoidOutput()
Empty output.
Definition model.cc:1001
static SolutionOutputSpecs SingleVariable(absl::string_view name, Variable *variable, bool display_as_boolean)
Will output: name = <variable value>.
Definition model.cc:980
bool Merge(absl::string_view other_name, const Domain &other_domain, bool other_temporary)
Definition model.cc:782
std::string DebugString() const
Definition model.cc:792
Allow iterating over a vector<T> as a mutable vector<T*>.
Definition iterators.h:157