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