Files
ortools-clone/ortools/math_opt/cpp/variable_and_expressions.cc

235 lines
8.4 KiB
C++
Raw Normal View History

2022-06-17 08:40:20 +02:00
// Copyright 2010-2022 Google LLC
2021-04-11 12:05:38 +02:00
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "ortools/math_opt/cpp/variable_and_expressions.h"
2022-01-14 14:00:30 +01:00
#include <cmath>
#include <limits>
2022-07-22 14:35:40 +02:00
#include <ostream>
2021-04-11 12:05:38 +02:00
#include <utility>
#include <vector>
2022-01-31 18:44:25 +01:00
#include "absl/base/attributes.h"
2021-04-11 12:05:38 +02:00
#include "ortools/base/logging.h"
#include "ortools/base/map_util.h"
2022-01-31 18:44:25 +01:00
#include "ortools/base/strong_int.h"
2022-10-07 18:24:08 +02:00
#include "ortools/math_opt/cpp/formatters.h"
#include "ortools/util/fp_roundtrip_conv.h"
2021-04-11 12:05:38 +02:00
namespace operations_research {
namespace math_opt {
2022-01-14 14:00:30 +01:00
constexpr double kInf = std::numeric_limits<double>::infinity();
2022-01-12 16:01:42 +01:00
#ifdef MATH_OPT_USE_EXPRESSION_COUNTERS
2021-04-11 12:05:38 +02:00
LinearExpression::LinearExpression() { ++num_calls_default_constructor_; }
LinearExpression::LinearExpression(const LinearExpression& other)
2023-04-03 18:22:22 +02:00
: storage_(other.storage_), terms_(other.terms_), offset_(other.offset_) {
2021-04-11 12:05:38 +02:00
++num_calls_copy_constructor_;
}
ABSL_CONST_INIT thread_local int
LinearExpression::num_calls_default_constructor_ = 0;
ABSL_CONST_INIT thread_local int LinearExpression::num_calls_copy_constructor_ =
0;
ABSL_CONST_INIT thread_local int LinearExpression::num_calls_move_constructor_ =
0;
ABSL_CONST_INIT thread_local int
LinearExpression::num_calls_initializer_list_constructor_ = 0;
void LinearExpression::ResetCounters() {
num_calls_default_constructor_ = 0;
num_calls_copy_constructor_ = 0;
num_calls_move_constructor_ = 0;
num_calls_initializer_list_constructor_ = 0;
}
2022-01-12 16:01:42 +01:00
#endif // MATH_OPT_USE_EXPRESSION_COUNTERS
2021-04-11 12:05:38 +02:00
double LinearExpression::Evaluate(
const VariableMap<double>& variable_values) const {
double result = offset_;
2023-04-03 18:22:22 +02:00
for (const auto& variable : SortedKeys(terms_)) {
const auto found = variable_values.find(variable);
CHECK(found != variable_values.end())
<< internal::kObjectsFromOtherModelStorage;
result += terms_.at(variable) * found->second;
2021-04-11 12:05:38 +02:00
}
return result;
}
double LinearExpression::EvaluateWithDefaultZero(
const VariableMap<double>& variable_values) const {
double result = offset_;
2023-04-03 18:22:22 +02:00
for (const auto& variable : SortedKeys(terms_)) {
2021-04-11 12:05:38 +02:00
result +=
2023-04-03 18:22:22 +02:00
terms_.at(variable) * gtl::FindWithDefault(variable_values, variable);
2021-04-11 12:05:38 +02:00
}
return result;
}
std::ostream& operator<<(std::ostream& ostr,
const LinearExpression& expression) {
// TODO(b/169415597): improve linear expression format:
// - make sure to quote the variable name so that we support:
// * variable names contains +, -, ...
// * variable names resembling anonymous variable names.
2023-04-03 18:22:22 +02:00
const std::vector<Variable> sorted_variables = SortedKeys(expression.terms_);
2021-04-11 12:05:38 +02:00
bool first = true;
for (const auto v : sorted_variables) {
2022-01-14 14:00:30 +01:00
const double coeff = expression.terms_.at(v);
if (coeff != 0) {
ostr << LeadingCoefficientFormatter(coeff, first) << v;
2021-04-11 12:05:38 +02:00
first = false;
}
}
2022-01-14 14:00:30 +01:00
ostr << ConstantFormatter(expression.offset(), first);
2021-04-11 12:05:38 +02:00
return ostr;
}
std::ostream& operator<<(std::ostream& ostr,
const BoundedLinearExpression& bounded_expression) {
2022-01-14 14:00:30 +01:00
const double lb = bounded_expression.lower_bound;
const double ub = bounded_expression.upper_bound;
if (lb == ub) {
2022-10-07 18:24:08 +02:00
ostr << bounded_expression.expression << " = " << RoundTripDoubleFormat(lb);
2022-01-14 14:00:30 +01:00
} else if (lb == -kInf) {
2022-10-07 18:24:08 +02:00
ostr << bounded_expression.expression << "" << RoundTripDoubleFormat(ub);
2022-01-14 14:00:30 +01:00
} else if (ub == kInf) {
2022-10-07 18:24:08 +02:00
ostr << bounded_expression.expression << "" << RoundTripDoubleFormat(lb);
2022-01-14 14:00:30 +01:00
} else {
2022-10-07 18:24:08 +02:00
ostr << RoundTripDoubleFormat(lb) << "" << bounded_expression.expression
<< "" << RoundTripDoubleFormat(ub);
2022-01-14 14:00:30 +01:00
}
2021-04-11 12:05:38 +02:00
return ostr;
}
2022-01-12 16:01:42 +01:00
double QuadraticExpression::Evaluate(
const VariableMap<double>& variable_values) const {
double result = offset();
2023-04-03 18:22:22 +02:00
for (const auto& variable : SortedKeys(linear_terms_)) {
const auto found = variable_values.find(variable);
CHECK(found != variable_values.end())
<< internal::kObjectsFromOtherModelStorage;
result += linear_terms_.at(variable) * found->second;
2022-01-12 16:01:42 +01:00
}
2023-04-03 18:22:22 +02:00
for (const auto& variables : SortedKeys(quadratic_terms_)) {
const auto found_first = variable_values.find(variables.first());
CHECK(found_first != variable_values.end())
<< internal::kObjectsFromOtherModelStorage;
const auto found_second = variable_values.find(variables.second());
CHECK(found_second != variable_values.end())
<< internal::kObjectsFromOtherModelStorage;
result += quadratic_terms_.at(variables) * found_first->second *
found_second->second;
2022-01-12 16:01:42 +01:00
}
return result;
}
double QuadraticExpression::EvaluateWithDefaultZero(
const VariableMap<double>& variable_values) const {
double result = offset();
2023-04-03 18:22:22 +02:00
for (const auto& variable : SortedKeys(linear_terms_)) {
result += linear_terms_.at(variable) *
gtl::FindWithDefault(variable_values, variable);
2022-01-12 16:01:42 +01:00
}
2023-04-03 18:22:22 +02:00
for (const auto& variables : SortedKeys(quadratic_terms_)) {
result += quadratic_terms_.at(variables) *
gtl::FindWithDefault(variable_values, variables.first()) *
gtl::FindWithDefault(variable_values, variables.second());
2022-01-12 16:01:42 +01:00
}
return result;
}
std::ostream& operator<<(std::ostream& ostr, const QuadraticExpression& expr) {
2022-01-14 14:00:30 +01:00
// TODO(b/169415597): improve quadratic expression formatting. See b/170991498
// for desired improvements for LinearExpression streaming which are also
// applicable here.
2022-01-12 16:01:42 +01:00
bool first = true;
2023-04-03 18:22:22 +02:00
for (const auto vs : SortedKeys(expr.quadratic_terms())) {
const double coeff = expr.quadratic_terms().at(vs);
2022-01-14 14:00:30 +01:00
if (coeff != 0) {
ostr << LeadingCoefficientFormatter(coeff, first);
2022-01-12 16:01:42 +01:00
first = false;
}
2023-04-03 18:22:22 +02:00
const Variable first_variable = vs.first();
const Variable second_variable = vs.second();
2022-01-12 16:01:42 +01:00
if (first_variable == second_variable) {
ostr << first_variable << "²";
} else {
ostr << first_variable << "*" << second_variable;
}
}
2023-04-03 18:22:22 +02:00
for (const auto v : SortedKeys(expr.linear_terms())) {
2022-01-14 14:00:30 +01:00
const double coeff = expr.linear_terms().at(v);
if (coeff != 0) {
ostr << LeadingCoefficientFormatter(coeff, first) << v;
2022-01-12 16:01:42 +01:00
first = false;
}
}
2022-01-14 14:00:30 +01:00
ostr << ConstantFormatter(expr.offset(), first);
2022-01-12 16:01:42 +01:00
return ostr;
}
2022-05-18 16:37:37 +02:00
std::ostream& operator<<(std::ostream& ostr,
const BoundedQuadraticExpression& bounded_expression) {
const double lb = bounded_expression.lower_bound;
const double ub = bounded_expression.upper_bound;
if (lb == ub) {
2022-10-07 18:24:08 +02:00
ostr << bounded_expression.expression << " = " << RoundTripDoubleFormat(lb);
2022-05-18 16:37:37 +02:00
} else if (lb == -kInf) {
2022-10-07 18:24:08 +02:00
ostr << bounded_expression.expression << "" << RoundTripDoubleFormat(ub);
2022-05-18 16:37:37 +02:00
} else if (ub == kInf) {
2022-10-07 18:24:08 +02:00
ostr << bounded_expression.expression << "" << RoundTripDoubleFormat(lb);
2022-05-18 16:37:37 +02:00
} else {
2022-10-07 18:24:08 +02:00
ostr << RoundTripDoubleFormat(lb) << "" << bounded_expression.expression
<< "" << RoundTripDoubleFormat(ub);
2022-05-18 16:37:37 +02:00
}
return ostr;
}
2022-01-12 16:01:42 +01:00
#ifdef MATH_OPT_USE_EXPRESSION_COUNTERS
QuadraticExpression::QuadraticExpression() { ++num_calls_default_constructor_; }
QuadraticExpression::QuadraticExpression(const QuadraticExpression& other)
2023-04-03 18:22:22 +02:00
: storage_(other.storage_),
quadratic_terms_(other.quadratic_terms_),
2022-01-12 16:01:42 +01:00
linear_terms_(other.linear_terms_),
offset_(other.offset_) {
++num_calls_copy_constructor_;
}
ABSL_CONST_INIT thread_local int
QuadraticExpression::num_calls_default_constructor_ = 0;
ABSL_CONST_INIT thread_local int
QuadraticExpression::num_calls_copy_constructor_ = 0;
ABSL_CONST_INIT thread_local int
QuadraticExpression::num_calls_move_constructor_ = 0;
ABSL_CONST_INIT thread_local int
QuadraticExpression::num_calls_initializer_list_constructor_ = 0;
ABSL_CONST_INIT thread_local int
QuadraticExpression::num_calls_linear_expression_constructor_ = 0;
void QuadraticExpression::ResetCounters() {
num_calls_default_constructor_ = 0;
num_calls_copy_constructor_ = 0;
num_calls_move_constructor_ = 0;
num_calls_initializer_list_constructor_ = 0;
num_calls_linear_expression_constructor_ = 0;
}
#endif // MATH_OPT_USE_EXPRESSION_COUNTERS
2021-04-11 12:05:38 +02:00
} // namespace math_opt
} // namespace operations_research