OR-Tools  9.2
cp_model_utils.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_SAT_CP_MODEL_UTILS_H_
15 #define OR_TOOLS_SAT_CP_MODEL_UTILS_H_
16 
17 #include <algorithm>
18 #include <cstdint>
19 #include <functional>
20 #include <limits>
21 #include <string>
22 #include <vector>
23 
24 #include "absl/container/flat_hash_set.h"
26 #include "ortools/base/logging.h"
29 
30 namespace operations_research {
31 namespace sat {
32 
33 // Small utility functions to deal with negative variable/literal references.
34 inline int NegatedRef(int ref) { return -ref - 1; }
35 inline int PositiveRef(int ref) { return std::max(ref, NegatedRef(ref)); }
36 inline bool RefIsPositive(int ref) { return ref >= 0; }
37 
38 // Small utility functions to deal with half-reified constraints.
40  return !ct.enforcement_literal().empty();
41 }
43  return ct.enforcement_literal(0);
44 }
45 
46 // Fills the target as negated ref.
47 void SetToNegatedLinearExpression(const LinearExpressionProto& input_expr,
48  LinearExpressionProto* output_negated_expr);
49 
50 // Collects all the references used by a constraint. This function is used in a
51 // few places to have a "generic" code dealing with constraints. Note that the
52 // enforcement_literal is NOT counted here and that the vectors can have
53 // duplicates.
55  std::vector<int> variables;
56  std::vector<int> literals;
57 };
59 
60 // Applies the given function to all variables/literals/intervals indices of the
61 // constraint. This function is used in a few places to have a "generic" code
62 // dealing with constraints.
63 void ApplyToAllVariableIndices(const std::function<void(int*)>& function,
65 void ApplyToAllLiteralIndices(const std::function<void(int*)>& function,
67 void ApplyToAllIntervalIndices(const std::function<void(int*)>& function,
69 
70 // Returns the name of the ConstraintProto::ConstraintCase oneof enum.
71 // Note(user): There is no such function in the proto API as of 16/01/2017.
72 std::string ConstraintCaseName(ConstraintProto::ConstraintCase constraint_case);
73 
74 // Returns the sorted list of variables used by a constraint.
75 // Note that this include variable used as a literal.
76 std::vector<int> UsedVariables(const ConstraintProto& ct);
77 
78 // Returns the sorted list of interval used by a constraint.
79 std::vector<int> UsedIntervals(const ConstraintProto& ct);
80 
81 // Returns true if a proto.domain() contain the given value.
82 // The domain is expected to be encoded as a sorted disjoint interval list.
83 template <typename ProtoWithDomain>
84 bool DomainInProtoContains(const ProtoWithDomain& proto, int64_t value) {
85  for (int i = 0; i < proto.domain_size(); i += 2) {
86  if (value >= proto.domain(i) && value <= proto.domain(i + 1)) return true;
87  }
88  return false;
89 }
90 
91 // Serializes a Domain into the domain field of a proto.
92 template <typename ProtoWithDomain>
93 void FillDomainInProto(const Domain& domain, ProtoWithDomain* proto) {
94  proto->clear_domain();
95  proto->mutable_domain()->Reserve(domain.NumIntervals());
96  for (const ClosedInterval& interval : domain) {
97  proto->add_domain(interval.start);
98  proto->add_domain(interval.end);
99  }
100 }
101 
102 // Reads a Domain from the domain field of a proto.
103 template <typename ProtoWithDomain>
104 Domain ReadDomainFromProto(const ProtoWithDomain& proto) {
105 #if defined(__PORTABLE_PLATFORM__)
107  {proto.domain().begin(), proto.domain().end()});
108 #else
109  return Domain::FromFlatSpanOfIntervals(proto.domain());
110 #endif
111 }
112 
113 // Returns the list of values in a given domain.
114 // This will fail if the domain contains more than one millions values.
115 //
116 // TODO(user): work directly on the Domain class instead.
117 template <typename ProtoWithDomain>
118 std::vector<int64_t> AllValuesInDomain(const ProtoWithDomain& proto) {
119  std::vector<int64_t> result;
120  for (int i = 0; i < proto.domain_size(); i += 2) {
121  for (int64_t v = proto.domain(i); v <= proto.domain(i + 1); ++v) {
122  CHECK_LE(result.size(), 1e6);
123  result.push_back(v);
124  }
125  }
126  return result;
127 }
128 
129 // Scales back a objective value to a double value from the original model.
131  int64_t value) {
132  double result = static_cast<double>(value);
134  result = -std::numeric_limits<double>::infinity();
136  result = std::numeric_limits<double>::infinity();
137  result += proto.offset();
138  if (proto.scaling_factor() == 0) return result;
139  return proto.scaling_factor() * result;
140 }
141 
142 // Similar to ScaleObjectiveValue() but uses the integer version.
144  int64_t value) {
145  if (proto.integer_scaling_factor() == 0) {
146  return value + proto.integer_offset();
147  }
148  return value * proto.integer_scaling_factor() + proto.integer_offset();
149 }
150 
151 // Removes the objective scaling and offset from the given value.
153  double value) {
154  double result = value;
155  if (proto.scaling_factor() != 0) {
156  result /= proto.scaling_factor();
157  }
158  return result - proto.offset();
159 }
160 
161 // Computes the "inner" objective of a response that contains a solution.
162 // This is the objective without offset and scaling. Call ScaleObjectiveValue()
163 // to get the user facing objective.
164 int64_t ComputeInnerObjective(const CpObjectiveProto& objective,
165  const CpSolverResponse& response);
166 
167 // Returns true if a linear expression can be reduced to a single ref.
168 bool ExpressionContainsSingleRef(const LinearExpressionProto& expr);
169 
170 // Checks if the expression is affine or constant.
171 bool ExpressionIsAffine(const LinearExpressionProto& expr);
172 
173 // Returns the reference the expression can be reduced to. It will DCHECK that
174 // ExpressionContainsSingleRef(expr) is true.
175 int GetSingleRefFromExpression(const LinearExpressionProto& expr);
176 
177 // Adds a linear expression proto to a linear constraint in place.
178 //
179 // Important: The domain must already be set, otherwise the offset will be lost.
180 // We also do not do any duplicate detection, so the constraint might need
181 // presolving afterwards.
182 void AddLinearExpressionToLinearConstraint(const LinearExpressionProto& expr,
183  int64_t coefficient,
184  LinearConstraintProto* linear);
185 
186 // Returns true iff a == b * b_scaling.
187 bool LinearExpressionProtosAreEqual(const LinearExpressionProto& a,
188  const LinearExpressionProto& b,
189  int64_t b_scaling = 1);
190 
191 } // namespace sat
192 } // namespace operations_research
193 
194 #endif // OR_TOOLS_SAT_CP_MODEL_UTILS_H_
std::vector< int > UsedVariables(const ConstraintProto &ct)
int64_t min
Definition: alldiff_cst.cc:139
void ApplyToAllIntervalIndices(const std::function< void(int *)> &f, ConstraintProto *ct)
std::vector< int64_t > AllValuesInDomain(const ProtoWithDomain &proto)
int64_t ScaleInnerObjectiveValue(const CpObjectiveProto &proto, int64_t value)
void ApplyToAllVariableIndices(const std::function< void(int *)> &f, ConstraintProto *ct)
Represents a closed interval [start, end].
bool LinearExpressionProtosAreEqual(const LinearExpressionProto &a, const LinearExpressionProto &b, int64_t b_scaling)
int64_t coefficient
int64_t b
int64_t max
Definition: alldiff_cst.cc:140
CpModelProto proto
double ScaleObjectiveValue(const CpObjectiveProto &proto, int64_t value)
#define CHECK_LE(val1, val2)
Definition: base/logging.h:704
SharedResponseManager * response
void AddLinearExpressionToLinearConstraint(const LinearExpressionProto &expr, int64_t coefficient, LinearConstraintProto *linear)
std::vector< int > UsedIntervals(const ConstraintProto &ct)
double UnscaleObjectiveValue(const CpObjectiveProto &proto, double value)
int EnforcementLiteral(const ConstraintProto &ct)
std::string ConstraintCaseName(ConstraintProto::ConstraintCase constraint_case)
static Domain FromFlatSpanOfIntervals(absl::Span< const int64_t > flat_intervals)
Same as FromIntervals() for a flattened representation (start, end, start, end, .....
We call domain any subset of Int64 = [kint64min, kint64max].
void FillDomainInProto(const Domain &domain, ProtoWithDomain *proto)
static Domain FromFlatIntervals(const std::vector< int64_t > &flat_intervals)
This method is available in Python, Java and .NET.
bool ExpressionContainsSingleRef(const LinearExpressionProto &expr)
bool HasEnforcementLiteral(const ConstraintProto &ct)
Collection of objects used to extend the Constraint Solver library.
int64_t ComputeInnerObjective(const CpObjectiveProto &objective, const CpSolverResponse &response)
bool ExpressionIsAffine(const LinearExpressionProto &expr)
bool RefIsPositive(int ref)
int GetSingleRefFromExpression(const LinearExpressionProto &expr)
Domain ReadDomainFromProto(const ProtoWithDomain &proto)
bool DomainInProtoContains(const ProtoWithDomain &proto, int64_t value)
void ApplyToAllLiteralIndices(const std::function< void(int *)> &f, ConstraintProto *ct)
int64_t value
IntervalVar * interval
Definition: resource.cc:100
int NumIntervals() const
Basic read-only std::vector<> wrapping to view a Domain as a sorted list of non-adjacent intervals.
const Constraint * ct
IndexReferences GetReferencesUsedByConstraint(const ConstraintProto &ct)
void SetToNegatedLinearExpression(const LinearExpressionProto &input_expr, LinearExpressionProto *output_negated_expr)
int64_t a