OR-Tools  9.0
model.cc
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 #include "ortools/flatzinc/model.h"
15 
16 #include <cstdint>
17 #include <limits>
18 #include <set>
19 #include <vector>
20 
21 #include "absl/container/flat_hash_set.h"
22 #include "absl/strings/str_cat.h"
23 #include "absl/strings/str_format.h"
24 #include "absl/strings/str_join.h"
25 #include "ortools/base/map_util.h"
26 #include "ortools/base/stl_util.h"
27 #include "ortools/util/logging.h"
28 
29 namespace operations_research {
30 namespace fz {
31 // ----- Domain -----
32 
33 Domain Domain::IntegerList(std::vector<int64_t> values) {
34  Domain result;
35  result.is_interval = false;
36  result.values = std::move(values);
38  result.display_as_boolean = false;
39  result.is_a_set = false;
40  return result;
41 }
42 
44  Domain result;
45  result.is_interval = true;
46  result.display_as_boolean = false;
47  result.is_a_set = false;
48  return result;
49 }
50 
52  Domain result;
53  result.is_interval = false;
54  result.values.push_back(value);
55  result.display_as_boolean = false;
56  result.is_a_set = false;
57  return result;
58 }
59 
60 Domain Domain::Interval(int64_t included_min, int64_t included_max) {
61  Domain result;
62  result.is_interval = true;
63  result.display_as_boolean = false;
64  result.values.push_back(included_min);
65  result.values.push_back(included_max);
66  result.is_a_set = false;
67  return result;
68 }
69 
71  Domain result;
72  result.is_interval = false;
73  result.display_as_boolean = true;
74  result.values.push_back(0);
75  result.values.push_back(1);
76  result.is_a_set = false;
77  return result;
78 }
79 
80 Domain Domain::SetOfIntegerList(std::vector<int64_t> values) {
81  Domain result = IntegerList(std::move(values));
82  result.is_a_set = true;
83  return result;
84 }
85 
87  Domain result = AllInt64();
88  result.is_a_set = true;
89  return result;
90 }
91 
93  Domain result = IntegerValue(value);
94  result.is_a_set = true;
95  return result;
96 }
97 
98 Domain Domain::SetOfInterval(int64_t included_min, int64_t included_max) {
99  Domain result = Interval(included_min, included_max);
100  result.is_a_set = true;
101  return result;
102 }
103 
105  Domain result = Boolean();
106  result.is_a_set = true;
107  return result;
108 }
109 
111  Domain result;
112  result.is_interval = false;
113  result.display_as_boolean = false;
114  result.is_a_set = false;
115  return result;
116 }
117 
118 bool Domain::IntersectWithDomain(const Domain& domain) {
119  if (domain.is_interval) {
120  if (!domain.values.empty()) {
121  return IntersectWithInterval(domain.values[0], domain.values[1]);
122  }
123  return false;
124  }
125  if (is_interval) {
126  is_interval = false; // Other is not an interval.
127  if (values.empty()) {
128  values = domain.values;
129  } else {
130  const int64_t imin = values[0];
131  const int64_t imax = values[1];
132  values = domain.values;
133  IntersectWithInterval(imin, imax);
134  }
135  return true;
136  }
137  // now deal with the intersection of two lists of values
138  return IntersectWithListOfIntegers(domain.values);
139 }
140 
143 }
144 
145 bool Domain::IntersectWithInterval(int64_t interval_min, int64_t interval_max) {
146  if (interval_min > interval_max) { // Empty interval -> empty domain.
147  is_interval = false;
148  values.clear();
149  return true;
150  } else if (is_interval) {
151  if (values.empty()) {
152  values.push_back(interval_min);
153  values.push_back(interval_max);
154  return true;
155  } else {
156  if (values[0] >= interval_min && values[1] <= interval_max) return false;
157  values[0] = std::max(values[0], interval_min);
158  values[1] = std::min(values[1], interval_max);
159  if (values[0] > values[1]) {
160  values.clear();
161  is_interval = false;
162  } else if (values[0] == values[1]) {
163  is_interval = false;
164  values.pop_back();
165  }
166  return true;
167  }
168  } else {
169  if (!values.empty()) {
170  std::sort(values.begin(), values.end());
171  std::vector<int64_t> new_values;
172  new_values.reserve(values.size());
173  bool changed = false;
174  for (const int64_t val : values) {
175  if (val > interval_max) {
176  changed = true;
177  break;
178  }
179  if (val >= interval_min &&
180  (new_values.empty() || val != new_values.back())) {
181  new_values.push_back(val);
182  } else {
183  changed = true;
184  }
185  }
186  values.swap(new_values);
187  return changed;
188  }
189  }
190  return false;
191 }
192 
193 bool Domain::IntersectWithListOfIntegers(const std::vector<int64_t>& integers) {
194  if (is_interval) {
195  const int64_t dmin =
197  const int64_t dmax =
199  values.clear();
200  for (const int64_t v : integers) {
201  if (v >= dmin && v <= dmax) values.push_back(v);
202  }
204  if (!values.empty() &&
205  values.back() - values.front() == values.size() - 1 &&
206  values.size() >= 2) {
207  if (values.size() > 2) {
208  // Contiguous case.
209  const int64_t last = values.back();
210  values.resize(2);
211  values[1] = last;
212  }
213  return values[0] != dmin || values[1] != dmax;
214  } else {
215  // This also covers and invalid (empty) domain.
216  is_interval = false;
217  return true;
218  }
219  } else {
220  // TODO(user): Investigate faster code for small arrays.
221  std::sort(values.begin(), values.end());
222  absl::flat_hash_set<int64_t> other_values(integers.begin(), integers.end());
223  std::vector<int64_t> new_values;
224  new_values.reserve(std::min(values.size(), integers.size()));
225  bool changed = false;
226  for (const int64_t val : values) {
227  if (gtl::ContainsKey(other_values, val)) {
228  if (new_values.empty() || val != new_values.back()) {
229  new_values.push_back(val);
230  }
231  } else {
232  changed = true;
233  }
234  }
235  values.swap(new_values);
236  return changed;
237  }
238 }
239 
240 bool Domain::HasOneValue() const {
241  return (values.size() == 1 || (values.size() == 2 && values[0] == values[1]));
242 }
243 
244 bool Domain::empty() const {
245  return is_interval ? (values.size() == 2 && values[0] > values[1])
246  : values.empty();
247 }
248 
249 int64_t Domain::Min() const {
250  CHECK(!empty());
252  : values.front();
253 }
254 
255 int64_t Domain::Max() const {
256  CHECK(!empty());
258  : values.back();
259 }
260 
261 int64_t Domain::Value() const {
262  CHECK(HasOneValue());
263  return values.front();
264 }
265 
266 bool Domain::IsAllInt64() const {
267  return is_interval &&
268  (values.empty() || (values[0] == std::numeric_limits<int64_t>::min() &&
270 }
271 
272 bool Domain::Contains(int64_t value) const {
273  if (is_interval) {
274  if (values.empty()) {
275  return true;
276  } else {
277  return value >= values[0] && value <= values[1];
278  }
279  } else {
280  return std::find(values.begin(), values.end(), value) != values.end();
281  }
282 }
283 
284 namespace {
285 bool IntervalOverlapValues(int64_t lb, int64_t ub,
286  const std::vector<int64_t>& values) {
287  for (int64_t value : values) {
288  if (lb <= value && value <= ub) {
289  return true;
290  }
291  }
292  return false;
293 }
294 } // namespace
295 
296 bool Domain::OverlapsIntList(const std::vector<int64_t>& vec) const {
297  if (IsAllInt64()) {
298  return true;
299  }
300  if (is_interval) {
301  CHECK(!values.empty());
302  return IntervalOverlapValues(values[0], values[1], vec);
303  } else {
304  // TODO(user): Better algorithm, sort and compare increasingly.
305  const std::vector<int64_t>& to_scan =
306  values.size() <= vec.size() ? values : vec;
307  const absl::flat_hash_set<int64_t> container =
308  values.size() <= vec.size()
309  ? absl::flat_hash_set<int64_t>(vec.begin(), vec.end())
310  : absl::flat_hash_set<int64_t>(values.begin(), values.end());
311  for (int64_t value : to_scan) {
312  if (gtl::ContainsKey(container, value)) {
313  return true;
314  }
315  }
316  return false;
317  }
318 }
319 
320 bool Domain::OverlapsIntInterval(int64_t lb, int64_t ub) const {
321  if (IsAllInt64()) {
322  return true;
323  }
324  if (is_interval) {
325  CHECK(!values.empty());
326  const int64_t dlb = values[0];
327  const int64_t dub = values[1];
328  return !(dub < lb || dlb > ub);
329  } else {
330  return IntervalOverlapValues(lb, ub, values);
331  }
332 }
333 
334 bool Domain::OverlapsDomain(const Domain& other) const {
335  if (other.is_interval) {
336  if (other.values.empty()) {
337  return true;
338  } else {
339  return OverlapsIntInterval(other.values[0], other.values[1]);
340  }
341  } else {
342  return OverlapsIntList(other.values);
343  }
344 }
345 
346 bool Domain::RemoveValue(int64_t value) {
347  if (is_interval) {
348  if (values.empty()) {
349  return false;
350  } else if (value == values[0] && value != values[1]) {
351  values[0]++;
352  return true;
353  } else if (value == values[1] && value != values[0]) {
354  values[1]--;
355  return true;
356  } else if (values[1] - values[0] < 1024 && value > values[0] &&
357  value < values[1]) { // small
358  const int64_t vmax = values[1];
359  values.pop_back();
360  values.reserve(vmax - values[0]);
361  for (int64_t v = values[0] + 1; v <= vmax; ++v) {
362  if (v != value) {
363  values.push_back(v);
364  }
365  }
366  is_interval = false;
367  return true;
368  }
369  } else {
370  values.erase(std::remove(values.begin(), values.end(), value),
371  values.end());
372  return true;
373  }
374  return false;
375 }
376 
377 std::string Domain::DebugString() const {
378  if (is_interval) {
379  if (values.empty()) {
380  return "int";
381  } else {
382  return absl::StrFormat("[%d..%d]", values[0], values[1]);
383  }
384  } else if (values.size() == 1) {
385  return absl::StrCat(values.back());
386  } else {
387  return absl::StrFormat("[%s]", absl::StrJoin(values, ", "));
388  }
389 }
390 
391 // ----- Argument -----
392 
394  Argument result;
395  result.type = INT_VALUE;
396  result.values.push_back(value);
397  return result;
398 }
399 
400 Argument Argument::Interval(int64_t imin, int64_t imax) {
401  Argument result;
402  result.type = INT_INTERVAL;
403  result.values.push_back(imin);
404  result.values.push_back(imax);
405  return result;
406 }
407 
408 Argument Argument::IntegerList(std::vector<int64_t> values) {
409  Argument result;
410  result.type = INT_LIST;
411  result.values = std::move(values);
412  return result;
413 }
414 
415 Argument Argument::DomainList(std::vector<Domain> domains) {
416  Argument result;
417  result.type = DOMAIN_LIST;
418  result.domains = std::move(domains);
419  return result;
420 }
421 
423  Argument result;
424  result.type = INT_VAR_REF;
425  result.variables.push_back(var);
426  return result;
427 }
428 
429 Argument Argument::IntVarRefArray(std::vector<IntegerVariable*> vars) {
430  Argument result;
431  result.type = INT_VAR_REF_ARRAY;
432  result.variables = std::move(vars);
433  return result;
434 }
435 
437  Argument result;
438  result.type = VOID_ARGUMENT;
439  return result;
440 }
441 
443  if (domain.is_interval) {
444  if (domain.values.empty()) {
447  } else {
448  return Argument::Interval(domain.values[0], domain.values[1]);
449  }
450  } else {
451  return Argument::IntegerList(domain.values);
452  }
453 }
454 
455 std::string Argument::DebugString() const {
456  switch (type) {
457  case INT_VALUE:
458  return absl::StrFormat("% d", values[0]);
459  case INT_INTERVAL:
460  return absl::StrFormat("[%d..%d]", values[0], values[1]);
461  case INT_LIST:
462  return absl::StrFormat("[%s]", absl::StrJoin(values, ", "));
463  case DOMAIN_LIST:
464  return absl::StrFormat("[%s]", JoinDebugString(domains, ", "));
465  case INT_VAR_REF:
466  return variables[0]->name;
467  case INT_VAR_REF_ARRAY: {
468  std::string result = "[";
469  for (int i = 0; i < variables.size(); ++i) {
470  result.append(variables[i]->name);
471  result.append(i != variables.size() - 1 ? ", " : "]");
472  }
473  return result;
474  }
475  case VOID_ARGUMENT:
476  return "VoidArgument";
477  }
478  LOG(FATAL) << "Unhandled case in DebugString " << static_cast<int>(type);
479  return "";
480 }
481 
482 bool Argument::IsVariable() const { return type == INT_VAR_REF; }
483 
484 bool Argument::HasOneValue() const {
485  return (type == INT_VALUE || (type == INT_LIST && values.size() == 1) ||
486  (type == INT_INTERVAL && values[0] == values[1]) ||
487  (type == INT_VAR_REF && variables[0]->domain.HasOneValue()));
488 }
489 
490 int64_t Argument::Value() const {
491  DCHECK(HasOneValue()) << "Value() called on unbound Argument: "
492  << DebugString();
493  switch (type) {
494  case INT_VALUE:
495  case INT_INTERVAL:
496  case INT_LIST:
497  return values[0];
498  case INT_VAR_REF: {
499  return variables[0]->domain.values[0];
500  }
501  default: {
502  LOG(FATAL) << "Should not be here";
503  return 0;
504  }
505  }
506 }
507 
509  switch (type) {
510  case INT_VALUE:
511  return false;
512  case INT_INTERVAL:
513  return false;
514  case INT_LIST:
515  return true;
516  case DOMAIN_LIST: {
517  for (const Domain& domain : domains) {
518  if (!domain.HasOneValue()) {
519  return false;
520  }
521  }
522  return true;
523  }
524  case INT_VAR_REF:
525  return false;
526  case INT_VAR_REF_ARRAY: {
527  for (IntegerVariable* var : variables) {
528  if (!var->domain.HasOneValue()) {
529  return false;
530  }
531  }
532  return true;
533  }
534  case VOID_ARGUMENT:
535  return false;
536  }
537 }
538 
539 bool Argument::Contains(int64_t value) const {
540  switch (type) {
541  case Argument::INT_LIST: {
542  return std::find(values.begin(), values.end(), value) != values.end();
543  }
544  case Argument::INT_INTERVAL: {
545  return value >= values.front() && value <= values.back();
546  }
547  case Argument::INT_VALUE: {
548  return value == values.front();
549  }
550  default: {
551  LOG(FATAL) << "Cannot call Contains() on " << DebugString();
552  return false;
553  }
554  }
555 }
556 
557 int64_t Argument::ValueAt(int pos) const {
558  switch (type) {
559  case INT_LIST:
560  CHECK_GE(pos, 0);
561  CHECK_LT(pos, values.size());
562  return values[pos];
563  case DOMAIN_LIST: {
564  CHECK_GE(pos, 0);
565  CHECK_LT(pos, domains.size());
566  CHECK(domains[pos].HasOneValue());
567  return domains[pos].Value();
568  }
569  case INT_VAR_REF_ARRAY: {
570  CHECK_GE(pos, 0);
571  CHECK_LT(pos, variables.size());
572  CHECK(variables[pos]->domain.HasOneValue());
573  return variables[pos]->domain.Value();
574  }
575  default: {
576  LOG(FATAL) << "Should not be here";
577  return 0;
578  }
579  }
580 }
581 
583  return type == INT_VAR_REF ? variables[0] : nullptr;
584 }
585 
587  return type == INT_VAR_REF_ARRAY ? variables[pos] : nullptr;
588 }
589 
590 // ----- IntegerVariable -----
591 
592 IntegerVariable::IntegerVariable(const std::string& name_,
593  const Domain& domain_, bool temporary_)
594  : name(name_), domain(domain_), temporary(temporary_), active(true) {
595  if (!domain.is_interval) {
596  gtl::STLSortAndRemoveDuplicates(&domain.values);
597  }
598 }
599 
600 bool IntegerVariable::Merge(const std::string& other_name,
601  const Domain& other_domain, bool other_temporary) {
602  if (temporary && !other_temporary) {
603  temporary = false;
604  name = other_name;
605  }
606  domain.IntersectWithDomain(other_domain);
607  return true;
608 }
609 
610 std::string IntegerVariable::DebugString() const {
611  if (!domain.is_interval && domain.values.size() == 1) {
612  return absl::StrFormat("% d", domain.values.back());
613  } else {
614  return absl::StrFormat("%s(%s%s)%s", name, domain.DebugString(),
615  temporary ? ", temporary" : "",
616  active ? "" : " [removed during presolve]");
617  }
618 }
619 
620 // ----- Constraint -----
621 
622 std::string Constraint::DebugString() const {
623  const std::string strong = strong_propagation ? "strong propagation" : "";
624  const std::string presolve_status_str =
625  active ? ""
626  : (presolve_propagation_done ? "[propagated during presolve]"
627  : "[removed during presolve]");
628  return absl::StrFormat("%s(%s)%s %s", type, JoinDebugString(arguments, ", "),
629  strong, presolve_status_str);
630 }
631 
632 void Constraint::RemoveArg(int arg_pos) {
633  arguments.erase(arguments.begin() + arg_pos);
634 }
635 
637  active = false;
638  // TODO(user): Reclaim arguments and memory.
639 }
640 
642  type = "false_constraint";
643  arguments.clear();
644 }
645 
646 // ----- Annotation -----
647 
649  Annotation result;
650  result.type = ANNOTATION_LIST;
651  result.interval_min = 0;
652  result.interval_max = 0;
653  return result;
654 }
655 
656 Annotation Annotation::AnnotationList(std::vector<Annotation> list) {
657  Annotation result;
658  result.type = ANNOTATION_LIST;
659  result.interval_min = 0;
660  result.interval_max = 0;
661  result.annotations = std::move(list);
662  return result;
663 }
664 
665 Annotation Annotation::Identifier(const std::string& id) {
666  Annotation result;
667  result.type = IDENTIFIER;
668  result.interval_min = 0;
669  result.interval_max = 0;
670  result.id = id;
671  return result;
672 }
673 
675  std::vector<Annotation> args) {
676  Annotation result;
677  result.type = FUNCTION_CALL;
678  result.interval_min = 0;
679  result.interval_max = 0;
680  result.id = id;
681  result.annotations = std::move(args);
682  return result;
683 }
684 
685 Annotation Annotation::FunctionCall(const std::string& id) {
686  Annotation result;
687  result.type = FUNCTION_CALL;
688  result.interval_min = 0;
689  result.interval_max = 0;
690  result.id = id;
691  return result;
692 }
693 
694 Annotation Annotation::Interval(int64_t interval_min, int64_t interval_max) {
695  Annotation result;
696  result.type = INTERVAL;
697  result.interval_min = interval_min;
698  result.interval_max = interval_max;
699  return result;
700 }
701 
703  Annotation result;
704  result.type = INT_VALUE;
705  result.interval_min = value;
706  return result;
707 }
708 
710  Annotation result;
711  result.type = INT_VAR_REF;
712  result.interval_min = 0;
713  result.interval_max = 0;
714  result.variables.push_back(var);
715  return result;
716 }
717 
718 Annotation Annotation::VariableList(std::vector<IntegerVariable*> variables) {
719  Annotation result;
720  result.type = INT_VAR_REF_ARRAY;
721  result.interval_min = 0;
722  result.interval_max = 0;
723  result.variables = std::move(variables);
724  return result;
725 }
726 
727 Annotation Annotation::String(const std::string& str) {
728  Annotation result;
729  result.type = STRING_VALUE;
730  result.interval_min = 0;
731  result.interval_max = 0;
732  result.string_value = str;
733  return result;
734 }
735 
737  std::vector<IntegerVariable*>* const vars) const {
738  for (const Annotation& ann : annotations) {
739  ann.AppendAllIntegerVariables(vars);
740  }
741  if (!variables.empty()) {
742  vars->insert(vars->end(), variables.begin(), variables.end());
743  }
744 }
745 
746 std::string Annotation::DebugString() const {
747  switch (type) {
748  case ANNOTATION_LIST: {
749  return absl::StrFormat("[%s]", JoinDebugString(annotations, ", "));
750  }
751  case IDENTIFIER: {
752  return id;
753  }
754  case FUNCTION_CALL: {
755  return absl::StrFormat("%s(%s)", id, JoinDebugString(annotations, ", "));
756  }
757  case INTERVAL: {
758  return absl::StrFormat("%d..%d", interval_min, interval_max);
759  }
760  case INT_VALUE: {
761  return absl::StrCat(interval_min);
762  }
763  case INT_VAR_REF: {
764  return variables.front()->name;
765  }
766  case INT_VAR_REF_ARRAY: {
767  std::string result = "[";
768  for (int i = 0; i < variables.size(); ++i) {
769  result.append(variables[i]->DebugString());
770  result.append(i != variables.size() - 1 ? ", " : "]");
771  }
772  return result;
773  }
774  case STRING_VALUE: {
775  return absl::StrFormat("\"%s\"", string_value);
776  }
777  }
778  LOG(FATAL) << "Unhandled case in DebugString " << static_cast<int>(type);
779  return "";
780 }
781 
782 // ----- SolutionOutputSpecs -----
783 
785  return absl::StrFormat("%d..%d", min_value, max_value);
786 }
787 
789  const std::string& name, IntegerVariable* variable,
790  bool display_as_boolean) {
791  SolutionOutputSpecs result;
792  result.name = name;
793  result.variable = variable;
795  return result;
796 }
797 
799  const std::string& name, std::vector<Bounds> bounds,
800  std::vector<IntegerVariable*> flat_variables, bool display_as_boolean) {
801  SolutionOutputSpecs result;
802  result.variable = nullptr;
803  result.name = name;
804  result.bounds = std::move(bounds);
805  result.flat_variables = std::move(flat_variables);
807  return result;
808 }
809 
811  SolutionOutputSpecs result;
812  result.variable = nullptr;
813  result.display_as_boolean = false;
814  return result;
815 }
816 
817 std::string SolutionOutputSpecs::DebugString() const {
818  if (variable != nullptr) {
819  return absl::StrFormat("output_var(%s)", variable->name);
820  } else {
821  return absl::StrFormat("output_array([%s] [%s])",
822  JoinDebugString(bounds, ", "),
824  }
825 }
826 
827 // ----- Model -----
828 
830  gtl::STLDeleteElements(&variables_);
831  gtl::STLDeleteElements(&constraints_);
832 }
833 
835  const Domain& domain, bool defined) {
836  IntegerVariable* const var = new IntegerVariable(name, domain, defined);
837  variables_.push_back(var);
838  return var;
839 }
840 
841 // TODO(user): Create only once constant per value.
843  IntegerVariable* const var = new IntegerVariable(
844  absl::StrCat(value), Domain::IntegerValue(value), true);
845  variables_.push_back(var);
846  return var;
847 }
848 
849 void Model::AddConstraint(const std::string& id,
850  std::vector<Argument> arguments, bool is_domain) {
851  Constraint* const constraint =
852  new Constraint(id, std::move(arguments), is_domain);
853  constraints_.push_back(constraint);
854 }
855 
856 void Model::AddConstraint(const std::string& id,
857  std::vector<Argument> arguments) {
858  AddConstraint(id, std::move(arguments), false);
859 }
860 
862  output_.push_back(std::move(output));
863 }
864 
865 void Model::Satisfy(std::vector<Annotation> search_annotations) {
866  objective_ = nullptr;
867  search_annotations_ = std::move(search_annotations);
868 }
869 
871  std::vector<Annotation> search_annotations) {
872  objective_ = obj;
873  maximize_ = false;
874  search_annotations_ = std::move(search_annotations);
875 }
876 
878  std::vector<Annotation> search_annotations) {
879  objective_ = obj;
880  maximize_ = true;
881  search_annotations_ = std::move(search_annotations);
882 }
883 
884 std::string Model::DebugString() const {
885  std::string output = absl::StrFormat("Model %s\nVariables\n", name_);
886  for (int i = 0; i < variables_.size(); ++i) {
887  absl::StrAppendFormat(&output, " %s\n", variables_[i]->DebugString());
888  }
889  output.append("Constraints\n");
890  for (int i = 0; i < constraints_.size(); ++i) {
891  if (constraints_[i] != nullptr) {
892  absl::StrAppendFormat(&output, " %s\n", constraints_[i]->DebugString());
893  }
894  }
895  if (objective_ != nullptr) {
896  absl::StrAppendFormat(&output, "%s %s\n %s\n",
897  maximize_ ? "Maximize" : "Minimize", objective_->name,
898  JoinDebugString(search_annotations_, ", "));
899  } else {
900  absl::StrAppendFormat(&output, "Satisfy\n %s\n",
901  JoinDebugString(search_annotations_, ", "));
902  }
903  output.append("Output\n");
904  for (int i = 0; i < output_.size(); ++i) {
905  absl::StrAppendFormat(&output, " %s\n", output_[i].DebugString());
906  }
907 
908  return output;
909 }
910 
911 bool Model::IsInconsistent() const {
912  for (IntegerVariable* var : variables_) {
913  if (var->domain.empty()) {
914  return true;
915  }
916  }
917  for (Constraint* ct : constraints_) {
918  if (ct->type == "false_constraint") {
919  return true;
920  }
921  }
922 
923  return false;
924 }
925 
926 // ----- Model statistics -----
927 
929  SOLVER_LOG(logger_, "Model ", model_.name());
930  for (const auto& it : constraints_per_type_) {
931  SOLVER_LOG(logger_, " - ", it.first, ": ", it.second.size());
932  }
933  if (model_.objective() == nullptr) {
934  SOLVER_LOG(logger_, " - Satisfaction problem");
935  } else {
936  SOLVER_LOG(logger_, " - ",
937  (model_.maximize() ? "Maximization" : "Minimization"),
938  " problem");
939  }
940  SOLVER_LOG(logger_);
941 }
942 
944  constraints_per_type_.clear();
945  constraints_per_variables_.clear();
946  for (Constraint* const ct : model_.constraints()) {
947  if (ct != nullptr && ct->active) {
948  constraints_per_type_[ct->type].push_back(ct);
949  absl::flat_hash_set<const IntegerVariable*> marked;
950  for (const Argument& arg : ct->arguments) {
951  for (IntegerVariable* const var : arg.variables) {
952  marked.insert(var);
953  }
954  }
955  for (const IntegerVariable* const var : marked) {
956  constraints_per_variables_[var].push_back(ct);
957  }
958  }
959  }
960 }
961 
962 // Flatten Search annotations.
963 void FlattenAnnotations(const Annotation& ann, std::vector<Annotation>* out) {
964  if (ann.type == Annotation::ANNOTATION_LIST ||
965  ann.IsFunctionCallWithIdentifier("seq_search")) {
966  for (const Annotation& inner : ann.annotations) {
967  FlattenAnnotations(inner, out);
968  }
969  } else {
970  out->push_back(ann);
971  }
972 }
973 
974 } // namespace fz
975 } // namespace operations_research
int64_t max
Definition: alldiff_cst.cc:140
int64_t min
Definition: alldiff_cst.cc:139
#define CHECK(condition)
Definition: base/logging.h:498
#define CHECK_LT(val1, val2)
Definition: base/logging.h:708
#define CHECK_GE(val1, val2)
Definition: base/logging.h:709
#define LOG(severity)
Definition: base/logging.h:423
#define DCHECK(condition)
Definition: base/logging.h:892
IntegerVariable * AddVariable(const std::string &name, const Domain &domain, bool defined)
Definition: model.cc:834
IntegerVariable * AddConstant(int64_t value)
Definition: model.cc:842
void Satisfy(std::vector< Annotation > search_annotations)
Definition: model.cc:865
void Maximize(IntegerVariable *obj, std::vector< Annotation > search_annotations)
Definition: model.cc:877
std::string DebugString() const
Definition: model.cc:884
void AddOutput(SolutionOutputSpecs output)
Definition: model.cc:861
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
bool IsInconsistent() const
Definition: model.cc:911
const std::string name
const Constraint * ct
int64_t value
IntVar * var
Definition: expr_array.cc:1874
const int FATAL
Definition: log_severity.h:32
void STLSortAndRemoveDuplicates(T *v, const LessFunc &less_func)
Definition: stl_util.h:58
void STLDeleteElements(T *container)
Definition: stl_util.h:372
bool ContainsKey(const Collection &collection, const Key &key)
Definition: map_util.h:200
void FlattenAnnotations(const Annotation &ann, std::vector< Annotation > *out)
Definition: model.cc:963
Collection of objects used to extend the Constraint Solver library.
std::string JoinNameFieldPtr(const std::vector< T > &v, const std::string &separator)
Definition: string_array.h:58
std::string JoinDebugString(const std::vector< T > &v, const std::string &separator)
Definition: string_array.h:38
const bool maximize_
Definition: search.cc:2508
IntVar *const objective_
Definition: search.cc:2966
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
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
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
#define SOLVER_LOG(logger,...)
Definition: util/logging.h:63