24#include "absl/container/flat_hash_set.h"
25#include "absl/log/check.h"
26#include "absl/strings/str_cat.h"
27#include "absl/strings/str_format.h"
28#include "absl/strings/str_join.h"
29#include "absl/strings/string_view.h"
30#include "absl/types/span.h"
62 result.
values.push_back(included_min);
63 result.
values.push_back(included_max);
70 result.
values.push_back(0);
71 result.
values.push_back(1);
134 if (!domain.
values.empty()) {
144 const int64_t imin =
values[0];
145 const int64_t imax =
values[1];
160 if (interval_min > interval_max) {
166 values.push_back(interval_min);
167 values.push_back(interval_max);
170 if (
values[0] >= interval_min &&
values[1] <= interval_max)
return false;
185 std::vector<int64_t> new_values;
186 new_values.reserve(
values.size());
187 bool changed =
false;
188 for (
const int64_t val :
values) {
189 if (val > interval_max) {
193 if (val >= interval_min &&
194 (new_values.empty() || val != new_values.back())) {
195 new_values.push_back(val);
210 values.empty() ? std::numeric_limits<int64_t>::min() :
values[0];
212 values.empty() ? std::numeric_limits<int64_t>::max() :
values[1];
214 for (
const int64_t v : integers) {
215 if (v >= dmin && v <= dmax)
values.push_back(v);
223 const int64_t last =
values.back();
236 absl::flat_hash_set<int64_t> other_values(integers.begin(), integers.end());
237 std::vector<int64_t> new_values;
238 new_values.reserve(std::min(
values.size(), integers.size()));
239 bool changed =
false;
240 for (
const int64_t val :
values) {
241 if (other_values.contains(val)) {
242 if (new_values.empty() || val != new_values.back()) {
243 new_values.push_back(val);
279 bool changed =
false;
359 (
values.empty() || (
values[0] == std::numeric_limits<int64_t>::min() &&
360 values[1] == std::numeric_limits<int64_t>::max()));
376bool IntervalOverlapValues(int64_t lb, int64_t ub,
377 absl::Span<const int64_t> values) {
378 for (int64_t
value : values) {
393 return IntervalOverlapValues(
values[0],
values[1], vec);
396 const std::vector<int64_t>& to_scan =
398 const absl::flat_hash_set<int64_t> container =
399 values.size() <= vec.size()
400 ? absl::flat_hash_set<int64_t>(vec.begin(), vec.end())
401 : absl::flat_hash_set<int64_t>(
values.begin(),
values.end());
402 for (int64_t
value : to_scan) {
403 if (container.contains(
value)) {
417 const int64_t dlb =
values[0];
418 const int64_t dub =
values[1];
419 return !(dub < lb || dlb > ub);
421 return IntervalOverlapValues(lb, ub,
values);
427 if (other.
values.empty()) {
449 const int64_t vmax =
values[1];
452 for (int64_t v =
values[0] + 1; v <= vmax; ++v) {
478 LOG(DFATAL) <<
"Error with float domain";
479 return "error_float";
486 return absl::StrFormat(
"[%d..%d]",
values[0],
values[1]);
488 }
else if (
values.size() == 1) {
489 return absl::StrCat(
values.back());
491 return absl::StrFormat(
"[%s]", absl::StrJoin(
values,
", "));
507 result.
values.push_back(imin);
508 result.
values.push_back(imax);
548 if (domain.
values.empty()) {
550 std::numeric_limits<int64_t>::max());
569 result.
floats.push_back(lb);
570 result.
floats.push_back(ub);
584 return absl::StrFormat(
"%d",
values[0]);
586 return absl::StrFormat(
"[%d..%d]",
values[0],
values[1]);
588 return absl::StrFormat(
"[%s]", absl::StrJoin(
values,
", "));
594 std::string result =
"[";
595 for (
int i = 0; i <
variables.size(); ++i) {
597 result.append(i !=
variables.size() - 1 ?
", " :
"]");
602 return "VoidArgument";
604 return absl::StrCat(
floats[0]);
606 return absl::StrCat(
"[",
floats[0],
"..",
floats[1],
"]");
608 return absl::StrFormat(
"[%s]", absl::StrJoin(
floats,
", "));
610 LOG(FATAL) <<
"Unhandled case in DebugString " <<
static_cast<int>(
type);
623 DCHECK(
HasOneValue()) <<
"Value() called on unbound Argument: "
634 LOG(FATAL) <<
"Should not be here";
650 if (!domain.HasOneValue()) {
660 if (!
var->domain.HasOneValue()) {
689 LOG(FATAL) <<
"Cannot call Contains() on " <<
DebugString();
699 CHECK_LT(pos,
values.size());
712 LOG(FATAL) <<
"Should not be here";
722 CHECK_LT(pos,
values.size());
727 return domains[pos].HasOneValue();
732 return variables[pos]->domain.HasOneValue();
735 LOG(FATAL) <<
"Should not be here";
766 LOG(FATAL) <<
"Should not be here";
774Variable::Variable(absl::string_view name_,
const Domain& domain_,
776 :
name(name_), domain(domain_), temporary(temporary_), active(true) {
777 if (!domain.is_interval) {
778 gtl::STLSortAndRemoveDuplicates(&domain.values);
783 bool other_temporary) {
798 active ?
"" :
" [removed during presolve]");
806 const std::string presolve_status_str =
809 :
"[removed during presolve]");
811 strong, presolve_status_str);
824 type =
"false_constraint";
857 std::vector<Annotation> args) {
892 LOG(INFO) <<
"Create INT_LIST";
928 ann.AppendAllVariables(vars);
953 return absl::StrFormat(
"[%s]", absl::StrJoin(
values,
", "));
959 std::string result =
"[";
960 for (
int i = 0; i <
variables.size(); ++i) {
962 result.append(i !=
variables.size() - 1 ?
", " :
"]");
970 LOG(FATAL) <<
"Unhandled case in DebugString " <<
static_cast<int>(
type);
990 absl::string_view
name, std::vector<Bounds>
bounds,
1010 return absl::StrFormat(
"output_var(%s)",
variable->
name);
1012 return absl::StrFormat(
"output_array([%s] [%s])",
1028 variables_.push_back(
var);
1036 variables_.push_back(
var);
1043 variables_.push_back(
var);
1050 new Constraint(
id, std::move(arguments), is_domain);
1051 constraints_.push_back(constraint);
1055 std::vector<Argument> arguments) {
1056 AddConstraint(
id, std::move(arguments),
false);
1060 output_.push_back(std::move(output));
1064 objective_ =
nullptr;
1065 search_annotations_ = std::move(search_annotations);
1069 std::vector<Annotation> search_annotations) {
1072 search_annotations_ = std::move(search_annotations);
1076 std::vector<Annotation> search_annotations) {
1079 search_annotations_ = std::move(search_annotations);
1083 std::string output = absl::StrFormat(
"Model %s\nVariables\n", name_);
1084 for (
int i = 0; i < variables_.size(); ++i) {
1085 absl::StrAppendFormat(&output,
" %s\n", variables_[i]->
DebugString());
1087 output.append(
"Constraints\n");
1088 for (
int i = 0; i < constraints_.size(); ++i) {
1089 if (constraints_[i] !=
nullptr) {
1090 absl::StrAppendFormat(&output,
" %s\n", constraints_[i]->
DebugString());
1093 if (objective_ !=
nullptr) {
1094 absl::StrAppendFormat(&output,
"%s %s\n %s\n",
1095 maximize_ ?
"Maximize" :
"Minimize", objective_->name,
1097 }
else if (!float_objective_variables_.empty()) {
1098 absl::StrAppendFormat(&output,
"%s [%s] * [%s] + %f\n %s\n",
1099 maximize_ ?
"Maximize" :
"Minimize",
1101 absl::StrJoin(float_objective_coefficients_,
", "),
1102 float_objective_offset_,
1106 absl::StrAppendFormat(&output,
"Satisfy\n %s\n",
1109 output.append(
"Output\n");
1110 for (
int i = 0; i < output_.size(); ++i) {
1111 absl::StrAppendFormat(&output,
" %s\n", output_[i].
DebugString());
1119 if (
var->domain.empty()) {
1124 if (
ct->type ==
"false_constraint") {
1135 SOLVER_LOG(logger_,
"Model ", model_.name());
1136 for (
const auto& it : constraints_per_type_) {
1137 SOLVER_LOG(logger_,
" - ", it.first,
": ", it.second.size());
1139 if (model_.objective() ==
nullptr) {
1140 SOLVER_LOG(logger_,
" - Satisfaction problem");
1143 (model_.maximize() ?
"Maximization" :
"Minimization"),
1150 constraints_per_type_.clear();
1151 constraints_per_variables_.clear();
1153 if (
ct !=
nullptr &&
ct->active) {
1154 constraints_per_type_[
ct->type].push_back(
ct);
1155 absl::flat_hash_set<const Variable*> marked;
1162 constraints_per_variables_[
var].push_back(
ct);
1176 out->push_back(ann);
void PrintStatistics() const
--— Model statistics --—
void AddConstraint(absl::string_view id, std::vector< Argument > arguments, bool is_domain)
Creates and add a constraint to the model.
Variable * AddFloatConstant(double value)
std::string DebugString() const
Services.
void AddOutput(SolutionOutputSpecs output)
void Maximize(Variable *obj, std::vector< Annotation > search_annotations)
void Satisfy(std::vector< Annotation > search_annotations)
Variable * AddVariable(absl::string_view name, const Domain &domain, bool defined)
--— Builder methods --—
bool IsInconsistent() const
void Minimize(Variable *obj, std::vector< Annotation > search_annotations)
Variable * AddConstant(int64_t value)
const std::string name
A name for logging purposes.
void STLSortAndRemoveDuplicates(T *v, const LessFunc &less_func)
void STLDeleteElements(T *container)
void FlattenAnnotations(const Annotation &ann, std::vector< Annotation > *out)
Flatten Search annotations.
In SWIG mode, we don't want anything besides these top-level includes.
std::string JoinDebugStringPtr(const std::vector< T > &v, absl::string_view separator)
Join v[i]->DebugString().
std::string JoinNameFieldPtr(const std::vector< T > &v, absl::string_view separator)
Join v[i]->name.
std::string JoinDebugString(const std::vector< T > &v, absl::string_view separator)
Join v[i].DebugString().
static Annotation String(absl::string_view str)
static Annotation FunctionCall(absl::string_view id)
void AppendAllVariables(std::vector< Variable * > *vars) const
static Annotation FunctionCallWithArguments(absl::string_view id, std::vector< Annotation > args)
static Annotation Empty()
--— Annotation --—
static Annotation AnnotationList(std::vector< Annotation > list)
static Annotation IntegerList(const std::vector< int64_t > &values)
static Annotation VarRefArray(std::vector< Variable * > variables)
static Annotation Identifier(absl::string_view id)
std::vector< Variable * > variables
std::vector< int64_t > values
bool IsFunctionCallWithIdentifier(absl::string_view identifier) const
static Annotation VarRef(Variable *var)
static Annotation IntegerValue(int64_t value)
static Annotation Interval(int64_t interval_min, int64_t interval_max)
std::vector< Annotation > annotations
std::string DebugString() const
std::vector< Variable * > variables
static Argument FloatList(std::vector< double > floats)
int Size() const
Returns the number of object in the argument.
static Argument FloatValue(double value)
bool IsVariable() const
Returns true if the argument is a variable.
std::vector< Domain > domains
bool HasOneValueAt(int pos) const
Returns true is the pos-th argument is fixed.
Variable * VarAt(int pos) const
std::string DebugString() const
bool IsArrayOfValues() const
static Argument VoidArgument()
static Argument IntegerValue(int64_t value)
--— Argument --—
int64_t ValueAt(int pos) const
Returns the value of the pos-th element.
static Argument Interval(int64_t imin, int64_t imax)
static Argument FromDomain(const Domain &domain)
int64_t Value() const
Returns the value of the argument. Does DCHECK(HasOneValue()).
static Argument IntegerList(std::vector< int64_t > values)
static Argument VarRef(Variable *var)
static Argument FloatInterval(double lb, double ub)
std::vector< double > floats
bool Contains(int64_t value) const
static Argument DomainList(std::vector< Domain > domains)
static Argument VarRefArray(std::vector< Variable * > vars)
std::vector< int64_t > values
std::string DebugString() const
--— Constraint --—
void MarkAsInactive()
Helpers to be used during presolve.
void RemoveArg(int arg_pos)
Helper method to remove one argument.
void SetAsFalse()
Set as a False constraint.
bool presolve_propagation_done
Indicates if presolve has finished propagating this constraint.
std::vector< Argument > arguments
static Domain AllFloats()
bool IntersectWithSingleton(int64_t value)
static Domain IntegerList(std::vector< int64_t > values)
The values will be sorted and duplicate values will be removed.
bool OverlapsDomain(const Domain &other) const
static Domain IntegerValue(int64_t value)
int64_t Max() const
Returns the max of the domain.
std::string DebugString() const
static Domain FloatValue(double value)
bool IntersectWithInterval(int64_t interval_min, int64_t interval_max)
bool IntersectWithDomain(const Domain &domain)
bool SetEmptyFloatDomain()
Sets the empty float domain. Returns true.
bool is_a_set
Indicates if the domain was created as a set domain.
static Domain EmptyDomain()
bool IntersectWithFloatDomain(const Domain &domain)
bool RemoveValue(int64_t value)
static Domain FloatInterval(double lb, double ub)
int64_t Min() const
Returns the min of the domain.
std::vector< int64_t > values
These should never be modified from outside the class.
bool is_float
Float domain.
static Domain SetOfBoolean()
static Domain Interval(int64_t included_min, int64_t included_max)
static Domain SetOfAllInt64()
static Domain SetOfInterval(int64_t included_min, int64_t included_max)
bool Contains(int64_t value) const
Various inclusion tests on a domain.
bool OverlapsIntInterval(int64_t lb, int64_t ub) const
std::vector< double > float_values
static Domain SetOfIntegerList(std::vector< int64_t > values)
static Domain SetOfIntegerValue(int64_t value)
int64_t Value() const
Returns the value of the domain. HasOneValue() must return true.
bool IntersectWithListOfIntegers(absl::Span< const int64_t > integers)
bool IsAllInt64() const
Returns true if the domain is [kint64min..kint64max].
bool OverlapsIntList(const std::vector< int64_t > &vec) const
std::string DebugString() const
--— SolutionOutputSpecs --—
std::vector< Variable * > flat_variables
static SolutionOutputSpecs MultiDimensionalArray(absl::string_view name, std::vector< Bounds > bounds, std::vector< Variable * > flat_variables, bool display_as_boolean)
std::string DebugString() const
static SolutionOutputSpecs VoidOutput()
Empty output.
static SolutionOutputSpecs SingleVariable(absl::string_view name, Variable *variable, bool display_as_boolean)
Will output: name = <variable value>.
std::vector< Bounds > bounds
bool Merge(absl::string_view other_name, const Domain &other_domain, bool other_temporary)
std::string DebugString() const
#define SOLVER_LOG(logger,...)