Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
variable_and_expressions.cc
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
15
16#include <cmath>
17#include <limits>
18#include <ostream>
19#include <utility>
20#include <vector>
21
22#include "absl/base/attributes.h"
28
29namespace operations_research {
30namespace math_opt {
31
32constexpr double kInf = std::numeric_limits<double>::infinity();
33
34#ifdef MATH_OPT_USE_EXPRESSION_COUNTERS
35LinearExpression::LinearExpression() { ++num_calls_default_constructor_; }
36
37LinearExpression::LinearExpression(const LinearExpression& other)
38 : storage_(other.storage_), terms_(other.terms_), offset_(other.offset_) {
39 ++num_calls_copy_constructor_;
40}
41
42ABSL_CONST_INIT thread_local int
43 LinearExpression::num_calls_default_constructor_ = 0;
44ABSL_CONST_INIT thread_local int LinearExpression::num_calls_copy_constructor_ =
45 0;
46ABSL_CONST_INIT thread_local int LinearExpression::num_calls_move_constructor_ =
47 0;
48ABSL_CONST_INIT thread_local int
49 LinearExpression::num_calls_initializer_list_constructor_ = 0;
50
51void LinearExpression::ResetCounters() {
52 num_calls_default_constructor_ = 0;
53 num_calls_copy_constructor_ = 0;
54 num_calls_move_constructor_ = 0;
55 num_calls_initializer_list_constructor_ = 0;
56}
57#endif // MATH_OPT_USE_EXPRESSION_COUNTERS
58
59double LinearExpression::Evaluate(
60 const VariableMap<double>& variable_values) const {
61 double result = offset_;
62 for (const auto& variable : SortedKeys(terms_)) {
63 const auto found = variable_values.find(variable);
64 CHECK(found != variable_values.end())
65 << internal::kObjectsFromOtherModelStorage;
66 result += terms_.at(variable) * found->second;
67 }
68 return result;
69}
70
71double LinearExpression::EvaluateWithDefaultZero(
72 const VariableMap<double>& variable_values) const {
73 double result = offset_;
74 for (const auto& variable : SortedKeys(terms_)) {
75 result +=
76 terms_.at(variable) * gtl::FindWithDefault(variable_values, variable);
77 }
78 return result;
79}
80
81std::ostream& operator<<(std::ostream& ostr,
82 const LinearExpression& expression) {
83 // TODO(b/169415597): improve linear expression format:
84 // - make sure to quote the variable name so that we support:
85 // * variable names contains +, -, ...
86 // * variable names resembling anonymous variable names.
87 const std::vector<Variable> sorted_variables = SortedKeys(expression.terms_);
88 bool first = true;
89 for (const auto v : sorted_variables) {
90 const double coeff = expression.terms_.at(v);
91 if (coeff != 0) {
92 ostr << LeadingCoefficientFormatter(coeff, first) << v;
93 first = false;
94 }
95 }
96 ostr << ConstantFormatter(expression.offset(), first);
97
98 return ostr;
99}
100
101std::ostream& operator<<(std::ostream& ostr,
102 const BoundedLinearExpression& bounded_expression) {
103 const double lb = bounded_expression.lower_bound;
104 const double ub = bounded_expression.upper_bound;
105 if (lb == ub) {
106 ostr << bounded_expression.expression << " = " << RoundTripDoubleFormat(lb);
107 } else if (lb == -kInf) {
108 ostr << bounded_expression.expression << " ≤ " << RoundTripDoubleFormat(ub);
109 } else if (ub == kInf) {
110 ostr << bounded_expression.expression << " ≥ " << RoundTripDoubleFormat(lb);
111 } else {
112 ostr << RoundTripDoubleFormat(lb) << " ≤ " << bounded_expression.expression
113 << " ≤ " << RoundTripDoubleFormat(ub);
114 }
115 return ostr;
116}
117
118double QuadraticExpression::Evaluate(
119 const VariableMap<double>& variable_values) const {
120 double result = offset();
121 for (const auto& variable : SortedKeys(linear_terms_)) {
122 const auto found = variable_values.find(variable);
123 CHECK(found != variable_values.end())
124 << internal::kObjectsFromOtherModelStorage;
125 result += linear_terms_.at(variable) * found->second;
126 }
127 for (const auto& variables : SortedKeys(quadratic_terms_)) {
128 const auto found_first = variable_values.find(variables.first());
129 CHECK(found_first != variable_values.end())
130 << internal::kObjectsFromOtherModelStorage;
131 const auto found_second = variable_values.find(variables.second());
132 CHECK(found_second != variable_values.end())
133 << internal::kObjectsFromOtherModelStorage;
134 result += quadratic_terms_.at(variables) * found_first->second *
135 found_second->second;
136 }
137 return result;
138}
139
140double QuadraticExpression::EvaluateWithDefaultZero(
141 const VariableMap<double>& variable_values) const {
142 double result = offset();
143 for (const auto& variable : SortedKeys(linear_terms_)) {
144 result += linear_terms_.at(variable) *
145 gtl::FindWithDefault(variable_values, variable);
146 }
147 for (const auto& variables : SortedKeys(quadratic_terms_)) {
148 result += quadratic_terms_.at(variables) *
149 gtl::FindWithDefault(variable_values, variables.first()) *
150 gtl::FindWithDefault(variable_values, variables.second());
151 }
152 return result;
153}
154
155std::ostream& operator<<(std::ostream& ostr, const QuadraticExpression& expr) {
156 // TODO(b/169415597): improve quadratic expression formatting. See b/170991498
157 // for desired improvements for LinearExpression streaming which are also
158 // applicable here.
159 bool first = true;
160 for (const auto vs : SortedKeys(expr.quadratic_terms())) {
161 const double coeff = expr.quadratic_terms().at(vs);
162 if (coeff != 0) {
163 ostr << LeadingCoefficientFormatter(coeff, first);
164 first = false;
165 }
166 const Variable first_variable = vs.first();
167 const Variable second_variable = vs.second();
168 if (first_variable == second_variable) {
169 ostr << first_variable << "²";
170 } else {
171 ostr << first_variable << "*" << second_variable;
172 }
173 }
174 for (const auto v : SortedKeys(expr.linear_terms())) {
175 const double coeff = expr.linear_terms().at(v);
176 if (coeff != 0) {
177 ostr << LeadingCoefficientFormatter(coeff, first) << v;
178 first = false;
179 }
180 }
181 ostr << ConstantFormatter(expr.offset(), first);
182 return ostr;
183}
184
185std::ostream& operator<<(std::ostream& ostr,
186 const BoundedQuadraticExpression& bounded_expression) {
187 const double lb = bounded_expression.lower_bound;
188 const double ub = bounded_expression.upper_bound;
189 if (lb == ub) {
190 ostr << bounded_expression.expression << " = " << RoundTripDoubleFormat(lb);
191 } else if (lb == -kInf) {
192 ostr << bounded_expression.expression << " ≤ " << RoundTripDoubleFormat(ub);
193 } else if (ub == kInf) {
194 ostr << bounded_expression.expression << " ≥ " << RoundTripDoubleFormat(lb);
195 } else {
196 ostr << RoundTripDoubleFormat(lb) << " ≤ " << bounded_expression.expression
197 << " ≤ " << RoundTripDoubleFormat(ub);
198 }
199 return ostr;
200}
201
202#ifdef MATH_OPT_USE_EXPRESSION_COUNTERS
203QuadraticExpression::QuadraticExpression() { ++num_calls_default_constructor_; }
204
205QuadraticExpression::QuadraticExpression(const QuadraticExpression& other)
206 : storage_(other.storage_),
207 quadratic_terms_(other.quadratic_terms_),
208 linear_terms_(other.linear_terms_),
209 offset_(other.offset_) {
210 ++num_calls_copy_constructor_;
211}
212
213ABSL_CONST_INIT thread_local int
214 QuadraticExpression::num_calls_default_constructor_ = 0;
215ABSL_CONST_INIT thread_local int
216 QuadraticExpression::num_calls_copy_constructor_ = 0;
217ABSL_CONST_INIT thread_local int
218 QuadraticExpression::num_calls_move_constructor_ = 0;
219ABSL_CONST_INIT thread_local int
220 QuadraticExpression::num_calls_initializer_list_constructor_ = 0;
221ABSL_CONST_INIT thread_local int
222 QuadraticExpression::num_calls_linear_expression_constructor_ = 0;
223
224void QuadraticExpression::ResetCounters() {
225 num_calls_default_constructor_ = 0;
226 num_calls_copy_constructor_ = 0;
227 num_calls_move_constructor_ = 0;
228 num_calls_initializer_list_constructor_ = 0;
229 num_calls_linear_expression_constructor_ = 0;
230}
231#endif // MATH_OPT_USE_EXPRESSION_COUNTERS
232
233} // namespace math_opt
234} // namespace operations_research
const QuadraticTermMap< double > & quadratic_terms() const
const MapUtilMappedT< Collection > & FindWithDefault(const Collection &collection, const KeyType &key, const MapUtilMappedT< Collection > &value)
Definition map_util.h:36
absl::flat_hash_map< Variable, V > VariableMap
std::vector< typename Map::key_type > SortedKeys(const Map &map)
Definition key_types.h:87
In SWIG mode, we don't want anything besides these top-level includes.
std::ostream & operator<<(std::ostream &out, const std::pair< First, Second > &p)
Definition stl_logging.h:99
A LinearExpression with upper and lower bounds.
A QuadraticExpression with upper and lower bounds.
Streaming formatter for a constant in a linear/quadratic expression.
Definition formatters.h:65