OR-Tools  9.6
variable_and_expressions.cc
Go to the documentation of this file.
1 // Copyright 2010-2022 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"
23 #include "ortools/base/logging.h"
24 #include "ortools/base/map_util.h"
28 
29 namespace operations_research {
30 namespace math_opt {
31 
32 constexpr double kInf = std::numeric_limits<double>::infinity();
33 
34 #ifdef MATH_OPT_USE_EXPRESSION_COUNTERS
35 LinearExpression::LinearExpression() { ++num_calls_default_constructor_; }
36 
37 LinearExpression::LinearExpression(const LinearExpression& other)
38  : terms_(other.terms_), offset_(other.offset_) {
39  ++num_calls_copy_constructor_;
40 }
41 
42 LinearExpression::LinearExpression(LinearExpression&& other)
43  : terms_(std::move(other.terms_)),
44  offset_(std::exchange(other.offset_, 0.0)) {
45  ++num_calls_move_constructor_;
46 }
47 
48 LinearExpression& LinearExpression::operator=(const LinearExpression& other) {
49  terms_ = other.terms_;
50  offset_ = other.offset_;
51  return *this;
52 }
53 
54 ABSL_CONST_INIT thread_local int
55  LinearExpression::num_calls_default_constructor_ = 0;
56 ABSL_CONST_INIT thread_local int LinearExpression::num_calls_copy_constructor_ =
57  0;
58 ABSL_CONST_INIT thread_local int LinearExpression::num_calls_move_constructor_ =
59  0;
60 ABSL_CONST_INIT thread_local int
61  LinearExpression::num_calls_initializer_list_constructor_ = 0;
62 
63 void LinearExpression::ResetCounters() {
64  num_calls_default_constructor_ = 0;
65  num_calls_copy_constructor_ = 0;
66  num_calls_move_constructor_ = 0;
67  num_calls_initializer_list_constructor_ = 0;
68 }
69 #endif // MATH_OPT_USE_EXPRESSION_COUNTERS
70 
71 double LinearExpression::Evaluate(
72  const VariableMap<double>& variable_values) const {
73  if (variable_values.storage() != nullptr && storage() != nullptr) {
74  CHECK_EQ(variable_values.storage(), storage())
76  }
77  double result = offset_;
78  for (const auto& variable : terms_.SortedKeys()) {
79  result += terms_.raw_map().at(variable.typed_id()) *
80  variable_values.raw_map().at(variable.typed_id());
81  }
82  return result;
83 }
84 
85 double LinearExpression::EvaluateWithDefaultZero(
86  const VariableMap<double>& variable_values) const {
87  if (variable_values.storage() != nullptr && storage() != nullptr) {
88  CHECK_EQ(variable_values.storage(), storage())
90  }
91  double result = offset_;
92  for (const auto& variable : terms_.SortedKeys()) {
93  result +=
94  terms_.raw_map().at(variable.typed_id()) *
95  gtl::FindWithDefault(variable_values.raw_map(), variable.typed_id());
96  }
97  return result;
98 }
99 
100 std::ostream& operator<<(std::ostream& ostr,
101  const LinearExpression& expression) {
102  // TODO(b/169415597): improve linear expression format:
103  // - make sure to quote the variable name so that we support:
104  // * variable names contains +, -, ...
105  // * variable names resembling anonymous variable names.
106  const std::vector<Variable> sorted_variables = expression.terms_.SortedKeys();
107  bool first = true;
108  for (const auto v : sorted_variables) {
109  const double coeff = expression.terms_.at(v);
110  if (coeff != 0) {
111  ostr << LeadingCoefficientFormatter(coeff, first) << v;
112  first = false;
113  }
114  }
115  ostr << ConstantFormatter(expression.offset(), first);
116 
117  return ostr;
118 }
119 
120 std::ostream& operator<<(std::ostream& ostr,
121  const BoundedLinearExpression& bounded_expression) {
122  const double lb = bounded_expression.lower_bound;
123  const double ub = bounded_expression.upper_bound;
124  if (lb == ub) {
125  ostr << bounded_expression.expression << " = " << RoundTripDoubleFormat(lb);
126  } else if (lb == -kInf) {
127  ostr << bounded_expression.expression << " ≤ " << RoundTripDoubleFormat(ub);
128  } else if (ub == kInf) {
129  ostr << bounded_expression.expression << " ≥ " << RoundTripDoubleFormat(lb);
130  } else {
131  ostr << RoundTripDoubleFormat(lb) << " ≤ " << bounded_expression.expression
132  << " ≤ " << RoundTripDoubleFormat(ub);
133  }
134  return ostr;
135 }
136 
137 double QuadraticExpression::Evaluate(
138  const VariableMap<double>& variable_values) const {
139  if (variable_values.storage() != nullptr && storage() != nullptr) {
140  CHECK_EQ(variable_values.storage(), storage())
142  }
143  double result = offset();
144  for (const auto& variable : linear_terms_.SortedKeys()) {
145  result += linear_terms_.raw_map().at(variable.typed_id()) *
146  variable_values.raw_map().at(variable.typed_id());
147  }
148  for (const auto& variables : quadratic_terms_.SortedKeys()) {
149  result += quadratic_terms_.raw_map().at(variables.typed_id()) *
150  variable_values.raw_map().at(variables.typed_id().first) *
151  variable_values.raw_map().at(variables.typed_id().second);
152  }
153  return result;
154 }
155 
156 double QuadraticExpression::EvaluateWithDefaultZero(
157  const VariableMap<double>& variable_values) const {
158  if (variable_values.storage() != nullptr && storage() != nullptr) {
159  CHECK_EQ(variable_values.storage(), storage())
161  }
162  double result = offset();
163  for (const auto& variable : linear_terms_.SortedKeys()) {
164  result +=
165  linear_terms_.raw_map().at(variable.typed_id()) *
166  gtl::FindWithDefault(variable_values.raw_map(), variable.typed_id());
167  }
168  for (const auto& variables : quadratic_terms_.SortedKeys()) {
169  result += quadratic_terms_.raw_map().at(variables.typed_id()) *
170  gtl::FindWithDefault(variable_values.raw_map(),
171  variables.typed_id().first) *
172  gtl::FindWithDefault(variable_values.raw_map(),
173  variables.typed_id().second);
174  }
175  return result;
176 }
177 
178 std::ostream& operator<<(std::ostream& ostr, const QuadraticExpression& expr) {
179  // TODO(b/169415597): improve quadratic expression formatting. See b/170991498
180  // for desired improvements for LinearExpression streaming which are also
181  // applicable here.
182  bool first = true;
183  for (const auto v : expr.quadratic_terms().SortedKeys()) {
184  const double coeff = expr.quadratic_terms().at(v);
185  if (coeff != 0) {
186  ostr << LeadingCoefficientFormatter(coeff, first);
187  first = false;
188  }
189  const Variable first_variable(expr.quadratic_terms().storage(),
190  v.typed_id().first);
191  const Variable second_variable(expr.quadratic_terms().storage(),
192  v.typed_id().second);
193  if (first_variable == second_variable) {
194  ostr << first_variable << "²";
195  } else {
196  ostr << first_variable << "*" << second_variable;
197  }
198  }
199  for (const auto v : expr.linear_terms().SortedKeys()) {
200  const double coeff = expr.linear_terms().at(v);
201  if (coeff != 0) {
202  ostr << LeadingCoefficientFormatter(coeff, first) << v;
203  first = false;
204  }
205  }
206  ostr << ConstantFormatter(expr.offset(), first);
207  return ostr;
208 }
209 
210 std::ostream& operator<<(std::ostream& ostr,
211  const BoundedQuadraticExpression& bounded_expression) {
212  const double lb = bounded_expression.lower_bound;
213  const double ub = bounded_expression.upper_bound;
214  if (lb == ub) {
215  ostr << bounded_expression.expression << " = " << RoundTripDoubleFormat(lb);
216  } else if (lb == -kInf) {
217  ostr << bounded_expression.expression << " ≤ " << RoundTripDoubleFormat(ub);
218  } else if (ub == kInf) {
219  ostr << bounded_expression.expression << " ≥ " << RoundTripDoubleFormat(lb);
220  } else {
221  ostr << RoundTripDoubleFormat(lb) << " ≤ " << bounded_expression.expression
222  << " ≤ " << RoundTripDoubleFormat(ub);
223  }
224  return ostr;
225 }
226 
227 #ifdef MATH_OPT_USE_EXPRESSION_COUNTERS
228 QuadraticExpression::QuadraticExpression() { ++num_calls_default_constructor_; }
229 
230 QuadraticExpression::QuadraticExpression(const QuadraticExpression& other)
231  : quadratic_terms_(other.quadratic_terms_),
232  linear_terms_(other.linear_terms_),
233  offset_(other.offset_) {
234  ++num_calls_copy_constructor_;
235 }
236 
237 QuadraticExpression::QuadraticExpression(QuadraticExpression&& other)
238  : quadratic_terms_(std::move(other.quadratic_terms_)),
239  linear_terms_(std::move(other.linear_terms_)),
240  offset_(std::exchange(other.offset_, 0.0)) {
241  ++num_calls_move_constructor_;
242 }
243 
244 QuadraticExpression& QuadraticExpression::operator=(
245  const QuadraticExpression& other) {
246  quadratic_terms_ = other.quadratic_terms_;
247  linear_terms_ = other.linear_terms_;
248  offset_ = other.offset_;
249  return *this;
250 }
251 
252 ABSL_CONST_INIT thread_local int
253  QuadraticExpression::num_calls_default_constructor_ = 0;
254 ABSL_CONST_INIT thread_local int
255  QuadraticExpression::num_calls_copy_constructor_ = 0;
256 ABSL_CONST_INIT thread_local int
257  QuadraticExpression::num_calls_move_constructor_ = 0;
258 ABSL_CONST_INIT thread_local int
259  QuadraticExpression::num_calls_initializer_list_constructor_ = 0;
260 ABSL_CONST_INIT thread_local int
261  QuadraticExpression::num_calls_linear_expression_constructor_ = 0;
262 
263 void QuadraticExpression::ResetCounters() {
264  num_calls_default_constructor_ = 0;
265  num_calls_copy_constructor_ = 0;
266  num_calls_move_constructor_ = 0;
267  num_calls_initializer_list_constructor_ = 0;
268  num_calls_linear_expression_constructor_ = 0;
269 }
270 #endif // MATH_OPT_USE_EXPRESSION_COUNTERS
271 
272 } // namespace math_opt
273 } // namespace operations_research
const StorageType & raw_map() const
Definition: id_map.h:234
const ModelStorage * storage() const
Definition: id_map.h:235
const QuadraticTermMap< double > & quadratic_terms() const
const int64_t offset_
Definition: interval.cc:2109
const Collection::value_type::second_type & FindWithDefault(const Collection &collection, const typename Collection::value_type::first_type &key, const typename Collection::value_type::second_type &value)
Definition: map_util.h:29
constexpr absl::string_view kObjectsFromOtherModelStorage
Definition: key_types.h:57
Collection of objects used to extend the Constraint Solver library.
std::ostream & operator<<(std::ostream &out, const std::pair< First, Second > &p)
Definition: stl_logging.h:99