Files
ortools-clone/ortools/linear_solver/linear_expr.cc
Corentin Le Molgat c34026b101 Bump copyright to 2025
note: done using
```sh
git grep -l "2010-2024 Google" | xargs sed -i 's/2010-2024 Google/2010-2025 Google/'
```
2025-01-10 11:33:35 +01:00

194 lines
5.1 KiB
C++

// Copyright 2010-2025 Google LLC
// 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/linear_solver/linear_expr.h"
#include <algorithm>
#include <cstdlib>
#include <limits>
#include <ostream>
#include <string>
#include <vector>
#include "absl/strings/str_join.h"
#include "absl/strings/string_view.h"
#include "ortools/base/logging.h"
#include "ortools/linear_solver/linear_solver.h"
namespace operations_research {
LinearExpr::LinearExpr(double constant) : offset_(constant), terms_() {}
LinearExpr::LinearExpr() : LinearExpr(0.0) {}
LinearExpr::LinearExpr(const MPVariable* var) : LinearExpr(0.0) {
terms_[var] = 1.0;
}
LinearExpr& LinearExpr::operator+=(const LinearExpr& rhs) {
for (const auto& kv : rhs.terms_) {
terms_[kv.first] += kv.second;
}
offset_ += rhs.offset_;
return *this;
}
LinearExpr& LinearExpr::operator-=(const LinearExpr& rhs) {
for (const auto& kv : rhs.terms_) {
terms_[kv.first] -= kv.second;
}
offset_ -= rhs.offset_;
return *this;
}
LinearExpr& LinearExpr::operator*=(double rhs) {
if (rhs == 0) {
terms_.clear();
offset_ = 0;
} else if (rhs != 1) {
for (auto& kv : terms_) {
kv.second *= rhs;
}
offset_ *= rhs;
}
return *this;
}
LinearExpr& LinearExpr::operator/=(double rhs) {
DCHECK_NE(rhs, 0);
return (*this) *= 1 / rhs;
}
LinearExpr LinearExpr::operator-() const { return (*this) * -1; }
// static
LinearExpr LinearExpr::NotVar(LinearExpr var) {
var *= -1;
var += 1;
return var;
}
double LinearExpr::SolutionValue() const {
double solution = offset_;
for (const auto& pair : terms_) {
solution += pair.first->solution_value() * pair.second;
}
return solution;
}
namespace {
void AppendTerm(const double coef, absl::string_view var_name,
const bool is_first, std::string* s) {
if (is_first) {
if (coef == 1.0) {
absl::StrAppend(s, var_name);
} else if (coef == -1.0) {
absl::StrAppend(s, "-", var_name);
} else {
absl::StrAppend(s, coef, "*", var_name);
}
} else {
const std::string op = coef < 0 ? "-" : "+";
const double abs_coef = std::abs(coef);
if (abs_coef == 1.0) {
absl::StrAppend(s, " ", op, " ", var_name);
} else {
absl::StrAppend(s, " ", op, " ", abs_coef, "*", var_name);
}
}
}
void AppendOffset(const double offset, const bool is_first, std::string* s) {
if (is_first) {
absl::StrAppend(s, offset);
} else {
if (offset != 0.0) {
const std::string op = offset < 0 ? "-" : "+";
absl::StrAppend(s, " ", op, " ", std::abs(offset));
}
}
}
} // namespace
std::string LinearExpr::ToString() const {
std::vector<const MPVariable*> vars_in_order;
for (const auto& var_val_pair : terms_) {
vars_in_order.push_back(var_val_pair.first);
}
std::sort(vars_in_order.begin(), vars_in_order.end(),
[](const MPVariable* v, const MPVariable* u) {
return v->index() < u->index();
});
std::string result;
bool is_first = true;
for (const MPVariable* var : vars_in_order) {
// MPSolver gives names to all variables, even if you don't.
DCHECK(!var->name().empty());
AppendTerm(terms_.at(var), var->name(), is_first, &result);
is_first = false;
}
AppendOffset(offset_, is_first, &result);
// TODO(user): support optionally cropping long strings.
return result;
}
std::ostream& operator<<(std::ostream& stream, const LinearExpr& linear_expr) {
stream << linear_expr.ToString();
return stream;
}
LinearExpr operator+(LinearExpr lhs, const LinearExpr& rhs) {
lhs += rhs;
return lhs;
}
LinearExpr operator-(LinearExpr lhs, const LinearExpr& rhs) {
lhs -= rhs;
return lhs;
}
LinearExpr operator*(LinearExpr lhs, double rhs) {
lhs *= rhs;
return lhs;
}
LinearExpr operator/(LinearExpr lhs, double rhs) {
lhs /= rhs;
return lhs;
}
LinearExpr operator*(double lhs, LinearExpr rhs) {
rhs *= lhs;
return rhs;
}
LinearRange::LinearRange(double lower_bound, const LinearExpr& linear_expr,
double upper_bound)
: lower_bound_(lower_bound),
linear_expr_(linear_expr),
upper_bound_(upper_bound) {
lower_bound_ -= linear_expr_.offset();
upper_bound_ -= linear_expr_.offset();
linear_expr_ -= linear_expr_.offset();
}
LinearRange operator<=(const LinearExpr& lhs, const LinearExpr& rhs) {
return LinearRange(-std::numeric_limits<double>::infinity(), lhs - rhs, 0);
}
LinearRange operator==(const LinearExpr& lhs, const LinearExpr& rhs) {
return LinearRange(0, lhs - rhs, 0);
}
LinearRange operator>=(const LinearExpr& lhs, const LinearExpr& rhs) {
return LinearRange(0, lhs - rhs, std::numeric_limits<double>::infinity());
}
} // namespace operations_research