math_opt: update
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
#include <cstdint>
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "ortools/base/status_macros.h"
|
||||
#include "ortools/math_opt/core/model_summary.h"
|
||||
#include "ortools/math_opt/core/sparse_vector_view.h"
|
||||
#include "ortools/math_opt/model.pb.h"
|
||||
@@ -24,7 +25,6 @@
|
||||
#include "ortools/math_opt/validators/scalar_validator.h"
|
||||
#include "ortools/math_opt/validators/sparse_matrix_validator.h"
|
||||
#include "ortools/math_opt/validators/sparse_vector_validator.h"
|
||||
#include "ortools/base/status_macros.h"
|
||||
|
||||
namespace operations_research::math_opt {
|
||||
|
||||
|
||||
@@ -66,6 +66,7 @@ cc_library(
|
||||
srcs = ["model.cc"],
|
||||
hdrs = ["model.h"],
|
||||
deps = [
|
||||
":formatters",
|
||||
":key_types",
|
||||
":linear_constraint",
|
||||
":update_tracker",
|
||||
@@ -104,6 +105,7 @@ cc_library(
|
||||
srcs = ["variable_and_expressions.cc"],
|
||||
hdrs = ["variable_and_expressions.h"],
|
||||
deps = [
|
||||
":formatters",
|
||||
":id_map",
|
||||
":key_types",
|
||||
"//ortools/base",
|
||||
@@ -390,3 +392,8 @@ cc_library(
|
||||
"//ortools/math_opt/storage:model_storage",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "formatters",
|
||||
hdrs = ["formatters.h"],
|
||||
)
|
||||
|
||||
88
ortools/math_opt/cpp/formatters.h
Normal file
88
ortools/math_opt/cpp/formatters.h
Normal file
@@ -0,0 +1,88 @@
|
||||
// Copyright 2010-2022 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.
|
||||
|
||||
#ifndef OR_TOOLS_MATH_OPT_CPP_FORMATTERS_H_
|
||||
#define OR_TOOLS_MATH_OPT_CPP_FORMATTERS_H_
|
||||
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
|
||||
namespace operations_research::math_opt {
|
||||
|
||||
// Streaming formatter for a coefficient of a linear/quadratic term, along with
|
||||
// any leading "+"/"-"'s to connect it with preceding terms in a sum, and
|
||||
// potentially a "*" postfix. The `is_first` parameter specifies if the term is
|
||||
// the first appearing in the sum, in which case the handling of the +/-
|
||||
// connectors is different.
|
||||
struct LeadingCoefficientFormatter {
|
||||
LeadingCoefficientFormatter(const double coeff, const bool is_first)
|
||||
: coeff(coeff), is_first(is_first) {}
|
||||
const double coeff;
|
||||
const bool is_first;
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& out,
|
||||
const LeadingCoefficientFormatter formatter) {
|
||||
const double coeff = formatter.coeff;
|
||||
if (formatter.is_first) {
|
||||
if (coeff == 1.0) {
|
||||
// Do nothing.
|
||||
} else if (coeff == -1.0) {
|
||||
out << "-";
|
||||
} else {
|
||||
out << coeff << "*";
|
||||
}
|
||||
} else {
|
||||
if (coeff == 1.0) {
|
||||
out << " + ";
|
||||
} else if (coeff == -1.0) {
|
||||
out << " - ";
|
||||
} else if (std::isnan(coeff)) {
|
||||
out << " + nan*";
|
||||
} else if (coeff >= 0) {
|
||||
out << " + " << coeff << "*";
|
||||
} else {
|
||||
out << " - " << -coeff << "*";
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// Streaming formatter for a constant in a linear/quadratic expression.
|
||||
struct ConstantFormatter {
|
||||
ConstantFormatter(const double constant, const bool is_first)
|
||||
: constant(constant), is_first(is_first) {}
|
||||
const double constant;
|
||||
const bool is_first;
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& out,
|
||||
const ConstantFormatter formatter) {
|
||||
const double constant = formatter.constant;
|
||||
if (formatter.is_first) {
|
||||
out << constant;
|
||||
} else if (constant == 0) {
|
||||
// Do nothing.
|
||||
} else if (std::isnan(constant)) {
|
||||
out << " + nan";
|
||||
} else if (constant > 0) {
|
||||
out << " + " << constant;
|
||||
} else {
|
||||
out << " - " << -constant;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
} // namespace operations_research::math_opt
|
||||
|
||||
#endif // OR_TOOLS_MATH_OPT_CPP_FORMATTERS_H_
|
||||
@@ -14,23 +14,28 @@
|
||||
#include "ortools/math_opt/cpp/model.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/container/flat_hash_map.h"
|
||||
#include "absl/memory/memory.h"
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/status/statusor.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "ortools/base/logging.h"
|
||||
#include "ortools/base/status_macros.h"
|
||||
#include "ortools/base/strong_int.h"
|
||||
#include "ortools/math_opt/cpp/linear_constraint.h"
|
||||
#include "ortools/math_opt/storage/model_storage.h"
|
||||
|
||||
namespace operations_research {
|
||||
namespace math_opt {
|
||||
|
||||
constexpr double kInf = std::numeric_limits<double>::infinity();
|
||||
|
||||
absl::StatusOr<std::unique_ptr<Model>> Model::FromModelProto(
|
||||
const ModelProto& model_proto) {
|
||||
ASSIGN_OR_RETURN(std::unique_ptr<ModelStorage> storage,
|
||||
@@ -220,5 +225,47 @@ absl::Status Model::ApplyUpdateProto(const ModelUpdateProto& update_proto) {
|
||||
return storage()->ApplyUpdateProto(update_proto);
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& ostr, const Model& model) {
|
||||
ostr << "Model";
|
||||
if (!model.name().empty()) ostr << " " << model.name();
|
||||
ostr << ":\n";
|
||||
|
||||
ostr << " Objective:\n"
|
||||
<< (model.is_maximize() ? " maximize " : " minimize ")
|
||||
<< model.ObjectiveAsQuadraticExpression() << "\n";
|
||||
|
||||
ostr << " Linear constraints:\n";
|
||||
for (const LinearConstraint constraint : model.SortedLinearConstraints()) {
|
||||
ostr << " " << constraint << ": "
|
||||
<< model.AsBoundedLinearExpression(constraint) << "\n";
|
||||
}
|
||||
|
||||
ostr << " Variables:\n";
|
||||
for (const Variable v : model.SortedVariables()) {
|
||||
ostr << " " << v;
|
||||
if (v.is_integer()) {
|
||||
if (v.lower_bound() == 0 && v.upper_bound() == 1) {
|
||||
ostr << " (binary)\n";
|
||||
continue;
|
||||
}
|
||||
ostr << " (integer)";
|
||||
}
|
||||
ostr << " in ";
|
||||
if (v.lower_bound() == -kInf) {
|
||||
ostr << "(-∞";
|
||||
} else {
|
||||
ostr << "[" << v.lower_bound();
|
||||
}
|
||||
ostr << ", ";
|
||||
if (v.upper_bound() == kInf) {
|
||||
ostr << "+∞)";
|
||||
} else {
|
||||
ostr << v.upper_bound() << "]";
|
||||
}
|
||||
ostr << "\n";
|
||||
}
|
||||
return ostr;
|
||||
}
|
||||
|
||||
} // namespace math_opt
|
||||
} // namespace operations_research
|
||||
|
||||
@@ -455,6 +455,11 @@ class Model {
|
||||
// it.
|
||||
ModelStorage* storage() { return storage_.get(); }
|
||||
|
||||
// Prints the objective, the constraints and the variables of the model over
|
||||
// several lines in a human-readable way. Includes a new line at the end of
|
||||
// the model.
|
||||
friend std::ostream& operator<<(std::ostream& ostr, const Model& model);
|
||||
|
||||
private:
|
||||
// Asserts (with CHECK) that the input pointer is either nullptr or that it
|
||||
// points to the same model as storage_.
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "ortools/base/logging.h"
|
||||
#include "ortools/base/map_util.h"
|
||||
#include "ortools/base/strong_int.h"
|
||||
#include "ortools/math_opt/cpp/formatters.h" // IWYU pragma: export
|
||||
|
||||
namespace operations_research {
|
||||
namespace math_opt {
|
||||
@@ -92,73 +93,6 @@ double LinearExpression::EvaluateWithDefaultZero(
|
||||
return result;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// Streaming formatter for a coefficient of a linear/quadratic term, along with
|
||||
// any leading "+"/"-"'s to connect it with preceding terms in a sum, and
|
||||
// potentially a "*" postfix. The `is_first` parameter specifies if the term is
|
||||
// the first appearing in the sum, in which case the handling of the +/-
|
||||
// connectors is different.
|
||||
struct LeadingCoefficientFormatter {
|
||||
LeadingCoefficientFormatter(const double coeff, const bool is_first)
|
||||
: coeff(coeff), is_first(is_first) {}
|
||||
const double coeff;
|
||||
const bool is_first;
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& out,
|
||||
const LeadingCoefficientFormatter formatter) {
|
||||
const double coeff = formatter.coeff;
|
||||
if (formatter.is_first) {
|
||||
if (coeff == 1.0) {
|
||||
// Do nothing.
|
||||
} else if (coeff == -1.0) {
|
||||
out << "-";
|
||||
} else {
|
||||
out << coeff << "*";
|
||||
}
|
||||
} else {
|
||||
if (coeff == 1.0) {
|
||||
out << " + ";
|
||||
} else if (coeff == -1.0) {
|
||||
out << " - ";
|
||||
} else if (std::isnan(coeff)) {
|
||||
out << " + nan*";
|
||||
} else if (coeff >= 0) {
|
||||
out << " + " << coeff << "*";
|
||||
} else {
|
||||
out << " - " << -coeff << "*";
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// Streaming formatter for a constant in a linear/quadratic expression.
|
||||
struct ConstantFormatter {
|
||||
ConstantFormatter(const double constant, const bool is_first)
|
||||
: constant(constant), is_first(is_first) {}
|
||||
const double constant;
|
||||
const bool is_first;
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, const ConstantFormatter formatter) {
|
||||
const double constant = formatter.constant;
|
||||
if (formatter.is_first) {
|
||||
out << constant;
|
||||
} else if (constant == 0) {
|
||||
// Do nothing.
|
||||
} else if (std::isnan(constant)) {
|
||||
out << " + nan";
|
||||
} else if (constant > 0) {
|
||||
out << " + " << constant;
|
||||
} else {
|
||||
out << " - " << -constant;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
std::ostream& operator<<(std::ostream& ostr,
|
||||
const LinearExpression& expression) {
|
||||
// TODO(b/169415597): improve linear expression format:
|
||||
|
||||
@@ -18,13 +18,13 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "ortools/base/logging.h"
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/status/statusor.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "ortools/base/logging.h"
|
||||
#include "ortools/base/status_macros.h"
|
||||
#include "ortools/glpk/glpk_computational_form.h"
|
||||
#include "ortools/glpk/glpk_formatters.h"
|
||||
#include "ortools/base/status_macros.h"
|
||||
|
||||
namespace operations_research::math_opt {
|
||||
namespace {
|
||||
|
||||
@@ -17,11 +17,11 @@
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
|
||||
#include "ortools/base/logging.h"
|
||||
#include "ortools/base/cleanup.h"
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/status/statusor.h"
|
||||
#include "absl/strings/str_format.h"
|
||||
#include "ortools/base/cleanup.h"
|
||||
#include "ortools/base/logging.h"
|
||||
#include "ortools/base/source_location.h"
|
||||
#include "ortools/base/status_builder.h"
|
||||
#include "ortools/base/status_macros.h"
|
||||
|
||||
@@ -40,9 +40,8 @@
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/status/statusor.h"
|
||||
#include "ortools/base/source_location.h"
|
||||
#include "absl/types/span.h"
|
||||
|
||||
#include "ortools/base/source_location.h"
|
||||
#include "ortools/gurobi/environment.h"
|
||||
|
||||
namespace operations_research::math_opt {
|
||||
|
||||
@@ -197,28 +197,6 @@ absl::StatusOr<ModelUpdateProto> ReadModelUpdate(
|
||||
absl::StrCat("invalid format in ReadModelUpdate(): ", format));
|
||||
}
|
||||
|
||||
// Prints the model.
|
||||
void PrintModel(const Model& model) {
|
||||
if (model.is_maximize()) {
|
||||
std::cout << "max";
|
||||
} else {
|
||||
std::cout << "min";
|
||||
}
|
||||
std::cout << ' ' << model.ObjectiveAsQuadraticExpression() << std::endl;
|
||||
|
||||
std::cout << "variables:" << std::endl;
|
||||
for (const Variable v : model.SortedVariables()) {
|
||||
std::cout << ' ' << v.lower_bound() << " ≤ " << v << " ≤ "
|
||||
<< v.upper_bound() << std::endl;
|
||||
}
|
||||
|
||||
std::cout << "constraints:" << std::endl;
|
||||
for (const LinearConstraint c : model.SortedLinearConstraints()) {
|
||||
std::cout << ' ' << c << ": " << model.AsBoundedLinearExpression(c)
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// Prints the summary of the solve result.
|
||||
absl::Status PrintSummary(const SolveResult& result) {
|
||||
std::cout << "Solve finished:\n"
|
||||
@@ -306,7 +284,8 @@ absl::Status RunSolver() {
|
||||
|
||||
// Optionally prints the problem.
|
||||
if (absl::GetFlag(FLAGS_print_model)) {
|
||||
PrintModel(*model);
|
||||
std::cout << model;
|
||||
std::cout.flush();
|
||||
}
|
||||
|
||||
// Solve the problem.
|
||||
|
||||
Reference in New Issue
Block a user