math_opt: Export from google3
This commit is contained in:
@@ -226,6 +226,8 @@ std::function<int(GRBenv** envP)> GRBemptyenv = nullptr;
|
||||
std::function<int(GRBenv** envP, const char* logfilename)> GRBloadenv = nullptr;
|
||||
std::function<int(GRBenv* env)> GRBstartenv = nullptr;
|
||||
std::function<GRBenv*(GRBmodel* model)> GRBgetenv = nullptr;
|
||||
std::function<GRBenv*(GRBmodel* model, int num)> GRBgetmultiobjenv = nullptr;
|
||||
std::function<GRBenv*(GRBmodel* model)> GRBdiscardmultiobjenvs = nullptr;
|
||||
std::function<void(GRBenv* env)> GRBfreeenv = nullptr;
|
||||
std::function<const char*(GRBenv* env)> GRBgeterrormsg = nullptr;
|
||||
std::function<void(int* majorP, int* minorP, int* technicalP)> GRBversion =
|
||||
@@ -337,6 +339,10 @@ void LoadGurobiFunctions(DynamicLibrary* gurobi_dynamic_library) {
|
||||
gurobi_dynamic_library->GetFunction(&GRBgetstrparaminfo,
|
||||
"GRBgetstrparaminfo");
|
||||
gurobi_dynamic_library->GetFunction(&GRBgetenv, "GRBgetenv");
|
||||
gurobi_dynamic_library->GetFunction(&GRBgetmultiobjenv,
|
||||
"GRBgetmultiobjenv");
|
||||
gurobi_dynamic_library->GetFunction(&GRBdiscardmultiobjenvs,
|
||||
"GRBdiscardmultiobjenvs");
|
||||
gurobi_dynamic_library->GetFunction(&GRBfreeenv, "GRBfreeenv");
|
||||
gurobi_dynamic_library->GetFunction(&GRBgeterrormsg, "GRBgeterrormsg");
|
||||
gurobi_dynamic_library->GetFunction(&GRBversion, "GRBversion");
|
||||
|
||||
@@ -723,6 +723,8 @@ extern std::function<int(GRBenv *envP, const char *paramname, int *valueP, int *
|
||||
extern std::function<int(GRBenv *envP, const char *paramname, double *valueP, double *minP, double *maxP, double *defP)> GRBgetdblparaminfo;
|
||||
extern std::function<int(GRBenv *envP, const char *paramname, char *valueP, char *defP)> GRBgetstrparaminfo;
|
||||
extern std::function<GRBenv *(GRBmodel *model)> GRBgetenv;
|
||||
extern std::function<GRBenv*(GRBmodel* model, int num)> GRBgetmultiobjenv;
|
||||
extern std::function<GRBenv*(GRBmodel* model)> GRBdiscardmultiobjenvs;
|
||||
extern std::function<void(GRBenv *env)> GRBfreeenv;
|
||||
extern std::function<const char *(GRBenv *env)> GRBgeterrormsg;
|
||||
extern std::function<void(int *majorP, int *minorP, int *technicalP)> GRBversion;
|
||||
|
||||
@@ -11,9 +11,9 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
load("@com_google_protobuf//bazel:proto_library.bzl", "proto_library")
|
||||
load("@rules_cc//cc:defs.bzl", "cc_proto_library")
|
||||
load("@rules_python//python:proto.bzl", "py_proto_library")
|
||||
load("@com_google_protobuf//bazel:proto_library.bzl", "proto_library")
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
@@ -64,6 +64,7 @@ proto_library(
|
||||
deps = [
|
||||
":solution_proto",
|
||||
":sparse_containers_proto",
|
||||
"@com_google_protobuf//:duration_proto",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ class QuadraticConstraint {
|
||||
// The quadratic expression will have a zero offset, even if the constraint
|
||||
// was created with a non-zero one. For example:
|
||||
//
|
||||
// const LinearConstraint c =
|
||||
// const QuadraticConstraint c =
|
||||
// model.AddQuadraticConstraint(3.2 <= x*x + 1.0 <= 4.2);
|
||||
//
|
||||
// // Here `e` will contain 3.2 - 1.0 <= x*x <= 4.2 - 1.0.
|
||||
|
||||
@@ -24,6 +24,7 @@ cc_library(
|
||||
"//ortools/math_opt/cpp:variable_and_expressions",
|
||||
"//ortools/math_opt/storage:linear_expression_data",
|
||||
"//ortools/math_opt/storage:model_storage",
|
||||
"//ortools/math_opt/storage:model_storage_types",
|
||||
"@com_google_absl//absl/strings",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -24,9 +24,11 @@
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "ortools/base/strong_int.h"
|
||||
#include "ortools/math_opt/constraints/second_order_cone/storage.h" // IWYU pragma: keep (`AtomicConstraintTraits<SecondOrderConeConstraintId>`)
|
||||
#include "ortools/math_opt/constraints/util/model_util.h"
|
||||
#include "ortools/math_opt/cpp/variable_and_expressions.h"
|
||||
#include "ortools/math_opt/storage/model_storage.h"
|
||||
#include "ortools/math_opt/storage/model_storage_types.h"
|
||||
|
||||
namespace operations_research::math_opt {
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "ortools/base/logging.h"
|
||||
#include "ortools/base/status_builder.h"
|
||||
#include "ortools/base/status_macros.h"
|
||||
#include "ortools/math_opt/callback.pb.h"
|
||||
#include "ortools/math_opt/core/sparse_vector_view.h"
|
||||
#include "ortools/math_opt/model.pb.h"
|
||||
@@ -542,6 +543,41 @@ bool UpdateIsSupported(const ModelUpdateProto& update,
|
||||
return true;
|
||||
}
|
||||
|
||||
absl::Status ModelSolveParametersAreSupported(
|
||||
const ModelSolveParametersProto& model_parameters,
|
||||
const SupportedProblemStructures& support_menu,
|
||||
const absl::string_view solver_name) {
|
||||
const auto validate_support = [solver_name](
|
||||
const absl::string_view structure,
|
||||
const SupportType support) -> absl::Status {
|
||||
switch (support) {
|
||||
case SupportType::kSupported:
|
||||
return absl::OkStatus();
|
||||
case SupportType::kNotSupported:
|
||||
return util::InvalidArgumentErrorBuilder()
|
||||
<< structure << " is not supported as " << solver_name
|
||||
<< " does not support multiple objectives";
|
||||
case SupportType::kNotImplemented:
|
||||
return util::UnimplementedErrorBuilder()
|
||||
<< structure
|
||||
<< " is not supported as MathOpt does not currently support "
|
||||
<< solver_name << " models with multiple objectives";
|
||||
}
|
||||
return absl::OkStatus();
|
||||
};
|
||||
if (model_parameters.has_primary_objective_parameters()) {
|
||||
RETURN_IF_ERROR(validate_support(
|
||||
"ModelSolveParametersProto.primary_objective_parameters",
|
||||
support_menu.multi_objectives));
|
||||
}
|
||||
if (!model_parameters.auxiliary_objective_parameters().empty()) {
|
||||
RETURN_IF_ERROR(validate_support(
|
||||
"ModelSolveParametersProto.auxiliary_objective_parameters",
|
||||
support_menu.multi_objectives));
|
||||
}
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
void UpgradeSolveResultProtoForStatsMigration(
|
||||
SolveResultProto& solve_result_proto) {
|
||||
*solve_result_proto.mutable_termination()->mutable_problem_status() =
|
||||
|
||||
@@ -343,6 +343,14 @@ absl::Status ModelIsSupported(const ModelProto& model,
|
||||
bool UpdateIsSupported(const ModelUpdateProto& update,
|
||||
const SupportedProblemStructures& support_menu);
|
||||
|
||||
// Returns an InvalidArgumentError (respectively, UnimplementedError) if a
|
||||
// problem structure is present in `model_parameters` and not supported (resp.,
|
||||
// not yet implemented) according to `support_menu`.
|
||||
absl::Status ModelSolveParametersAreSupported(
|
||||
const ModelSolveParametersProto& model_parameters,
|
||||
const SupportedProblemStructures& support_menu,
|
||||
absl::string_view solver_name);
|
||||
|
||||
void UpgradeSolveResultProtoForStatsMigration(
|
||||
SolveResultProto& solve_result_proto);
|
||||
|
||||
|
||||
@@ -84,6 +84,7 @@ cc_library(
|
||||
"//ortools/math_opt/constraints/indicator:indicator_constraint",
|
||||
"//ortools/math_opt/constraints/quadratic:quadratic_constraint",
|
||||
"//ortools/math_opt/constraints/second_order_cone:second_order_cone_constraint",
|
||||
"//ortools/math_opt/constraints/second_order_cone:storage",
|
||||
"//ortools/math_opt/constraints/sos:sos1_constraint",
|
||||
"//ortools/math_opt/constraints/sos:sos2_constraint",
|
||||
"//ortools/math_opt/constraints/util:model_util",
|
||||
@@ -277,6 +278,7 @@ cc_library(
|
||||
":solution",
|
||||
":sparse_containers",
|
||||
":variable_and_expressions",
|
||||
"//ortools/base:protoutil",
|
||||
"//ortools/base:status_macros",
|
||||
"//ortools/math_opt:model_parameters_cc_proto",
|
||||
"//ortools/math_opt:solution_cc_proto",
|
||||
@@ -285,8 +287,10 @@ cc_library(
|
||||
"//ortools/util:status_macros",
|
||||
"@com_google_absl//absl/algorithm:container",
|
||||
"@com_google_absl//absl/container:flat_hash_set",
|
||||
"@com_google_absl//absl/log:check",
|
||||
"@com_google_absl//absl/status",
|
||||
"@com_google_absl//absl/status:statusor",
|
||||
"@com_google_absl//absl/time",
|
||||
"@com_google_protobuf//:protobuf",
|
||||
],
|
||||
)
|
||||
@@ -316,6 +320,7 @@ cc_library(
|
||||
"@com_google_absl//absl/base:core_headers",
|
||||
"@com_google_absl//absl/strings",
|
||||
"@com_google_absl//absl/synchronization",
|
||||
"@com_google_absl//absl/types:span",
|
||||
"@com_google_protobuf//:protobuf",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -77,7 +77,8 @@ absl::Status BoundsMapProtoToCpp(
|
||||
const google::protobuf::Map<int64_t, ModelSubsetProto::Bounds>& source,
|
||||
absl::flat_hash_map<K, ModelSubset::Bounds>& target,
|
||||
const ModelStorage* const model,
|
||||
bool (ModelStorage::*const contains_strong_id)(typename K::IdType id) const,
|
||||
bool (ModelStorage::* const contains_strong_id)(typename K::IdType id)
|
||||
const,
|
||||
const absl::string_view object_name) {
|
||||
for (const auto& [raw_id, bounds_proto] : source) {
|
||||
const typename K::IdType strong_id(raw_id);
|
||||
@@ -95,7 +96,8 @@ template <typename K>
|
||||
absl::Status RepeatedIdsProtoToCpp(
|
||||
const google::protobuf::RepeatedField<int64_t>& source,
|
||||
absl::flat_hash_set<K>& target, const ModelStorage* const model,
|
||||
bool (ModelStorage::*const contains_strong_id)(typename K::IdType id) const,
|
||||
bool (ModelStorage::* const contains_strong_id)(typename K::IdType id)
|
||||
const,
|
||||
const absl::string_view object_name) {
|
||||
for (const int64_t raw_id : source) {
|
||||
const typename K::IdType strong_id(raw_id);
|
||||
|
||||
@@ -228,11 +228,11 @@ std::optional<E> EnumFromString(absl::string_view str);
|
||||
//
|
||||
// It calls EnumToOptString(), printing the returned value if not nullopt. When
|
||||
// nullopt it prints the enum numeric value instead.
|
||||
template <typename E,
|
||||
// We must use enable_if here to prevent this overload to be selected
|
||||
// for other types than ones that implement Enum<E>.
|
||||
typename = std::enable_if_t<Enum<E>::kIsImplemented>>
|
||||
std::ostream& operator<<(std::ostream& out, const E value) {
|
||||
// We must use enable_if here to prevent this overload to be selected
|
||||
// for other types than ones that implement Enum<E>.
|
||||
template <typename E>
|
||||
std::enable_if_t<Enum<E>::kIsImplemented, std::ostream&> operator<<(
|
||||
std::ostream& out, const E value) {
|
||||
const std::optional<absl::string_view> opt_str = EnumToOptString(value);
|
||||
if (opt_str.has_value()) {
|
||||
out << *opt_str;
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "absl/base/thread_annotations.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/synchronization/mutex.h"
|
||||
#include "absl/types/span.h"
|
||||
#include "google/protobuf/repeated_field.h"
|
||||
#include "google/protobuf/repeated_ptr_field.h"
|
||||
#include "ortools/base/logging.h"
|
||||
@@ -50,7 +51,7 @@ class PrinterMessageCallbackImpl {
|
||||
const std::string prefix_;
|
||||
};
|
||||
|
||||
void PushBack(const std::vector<std::string>& messages,
|
||||
void PushBack(absl::Span<const std::string> messages,
|
||||
std::vector<std::string>* const sink) {
|
||||
sink->insert(sink->end(), messages.begin(), messages.end());
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "ortools/math_opt/constraints/indicator/indicator_constraint.h"
|
||||
#include "ortools/math_opt/constraints/quadratic/quadratic_constraint.h"
|
||||
#include "ortools/math_opt/constraints/second_order_cone/second_order_cone_constraint.h"
|
||||
#include "ortools/math_opt/constraints/second_order_cone/storage.h"
|
||||
#include "ortools/math_opt/constraints/sos/sos1_constraint.h"
|
||||
#include "ortools/math_opt/constraints/sos/sos2_constraint.h"
|
||||
#include "ortools/math_opt/constraints/util/model_util.h"
|
||||
@@ -261,7 +262,7 @@ void Model::SetObjective(const Objective objective,
|
||||
}
|
||||
}
|
||||
|
||||
void Model::AddToObjective(Objective objective,
|
||||
void Model::AddToObjective(const Objective objective,
|
||||
const LinearExpression& expression) {
|
||||
CheckModel(objective.storage());
|
||||
CheckOptionalModel(expression.storage());
|
||||
@@ -272,6 +273,28 @@ void Model::AddToObjective(Objective objective,
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Variable> Model::NonzeroVariablesInLinearObjective(
|
||||
const Objective objective) const {
|
||||
CheckModel(objective.storage());
|
||||
std::vector<Variable> result;
|
||||
result.reserve(storage()->num_linear_objective_terms(objective.typed_id()));
|
||||
for (const auto [var_id, unused] :
|
||||
storage()->linear_objective(objective.typed_id())) {
|
||||
result.push_back(Variable(storage(), var_id));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<Variable> Model::NonzeroVariablesInQuadraticObjective() const {
|
||||
std::vector<Variable> result;
|
||||
for (const auto& [var_id1, var_id2, unused] :
|
||||
storage()->quadratic_objective_terms(kPrimaryObjectiveId)) {
|
||||
result.push_back(Variable(storage(), var_id1));
|
||||
result.push_back(Variable(storage(), var_id2));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
ModelProto Model::ExportModel(const bool remove_names) const {
|
||||
return storage()->ExportModel(remove_names);
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/log/check.h"
|
||||
@@ -162,7 +161,7 @@ class Model {
|
||||
std::unique_ptr<Model> Clone(
|
||||
std::optional<absl::string_view> new_name = std::nullopt) const;
|
||||
|
||||
inline const std::string& name() const;
|
||||
inline absl::string_view name() const;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Variable methods
|
||||
@@ -217,7 +216,7 @@ class Model {
|
||||
inline Variable variable(VariableId id) const;
|
||||
|
||||
// Returns the variable name.
|
||||
inline const std::string& name(Variable variable) const;
|
||||
inline absl::string_view name(Variable variable) const;
|
||||
|
||||
// Sets a variable lower bound.
|
||||
inline void set_lower_bound(Variable variable, double lower_bound);
|
||||
@@ -318,7 +317,7 @@ class Model {
|
||||
inline LinearConstraint linear_constraint(LinearConstraintId id) const;
|
||||
|
||||
// Returns the linear constraint name.
|
||||
inline const std::string& name(LinearConstraint constraint) const;
|
||||
inline absl::string_view name(LinearConstraint constraint) const;
|
||||
|
||||
// Sets a linear constraint lower bound.
|
||||
inline void set_lower_bound(LinearConstraint constraint, double lower_bound);
|
||||
@@ -750,6 +749,13 @@ class Model {
|
||||
// Prefer set_maximize() and set_minimize() above for more readable code.
|
||||
inline void set_is_maximize(bool is_maximize);
|
||||
|
||||
// Returns all variables that have a nonzero coefficient in the linear part of
|
||||
// the primary objective. Result is not sorted.
|
||||
inline std::vector<Variable> NonzeroVariablesInLinearObjective() const;
|
||||
// Returns all variables that have a nonzero coefficient in the quadratic part
|
||||
// of the primary objective. Result is not sorted.
|
||||
std::vector<Variable> NonzeroVariablesInQuadraticObjective() const;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Auxiliary objective methods
|
||||
//
|
||||
@@ -847,6 +853,11 @@ class Model {
|
||||
// Prefer set_maximize() and set_minimize() above for more readable code.
|
||||
inline void set_is_maximize(Objective objective, bool is_maximize);
|
||||
|
||||
// Returns all variables that have a nonzero coefficient in the linear part of
|
||||
// the `objective`. Result is not sorted.
|
||||
std::vector<Variable> NonzeroVariablesInLinearObjective(
|
||||
Objective objective) const;
|
||||
|
||||
// Returns a proto representation of the optimization model.
|
||||
//
|
||||
// See FromModelProto() to build a Model from a proto.
|
||||
@@ -922,7 +933,7 @@ class Model {
|
||||
|
||||
// ------------------------------- Variables -----------------------------------
|
||||
|
||||
const std::string& Model::name() const { return storage()->name(); }
|
||||
absl::string_view Model::name() const { return storage()->name(); }
|
||||
|
||||
Variable Model::AddVariable(const absl::string_view name) {
|
||||
return Variable(storage(), storage()->AddVariable(name));
|
||||
@@ -978,7 +989,7 @@ Variable Model::variable(const VariableId id) const {
|
||||
return Variable(storage(), id);
|
||||
}
|
||||
|
||||
const std::string& Model::name(const Variable variable) const {
|
||||
absl::string_view Model::name(const Variable variable) const {
|
||||
CheckModel(variable.storage());
|
||||
return storage()->variable_name(variable.typed_id());
|
||||
}
|
||||
@@ -1080,7 +1091,7 @@ LinearConstraint Model::linear_constraint(const LinearConstraintId id) const {
|
||||
return LinearConstraint(storage(), id);
|
||||
}
|
||||
|
||||
const std::string& Model::name(const LinearConstraint constraint) const {
|
||||
absl::string_view Model::name(const LinearConstraint constraint) const {
|
||||
CheckModel(constraint.storage());
|
||||
return storage()->linear_constraint_name(constraint.typed_id());
|
||||
}
|
||||
@@ -1491,6 +1502,10 @@ void Model::set_is_maximize(const bool is_maximize) {
|
||||
storage()->set_is_maximize(kPrimaryObjectiveId, is_maximize);
|
||||
}
|
||||
|
||||
std::vector<Variable> Model::NonzeroVariablesInLinearObjective() const {
|
||||
return NonzeroVariablesInLinearObjective(primary_objective());
|
||||
}
|
||||
|
||||
// -------------------------- Auxiliary objectives -----------------------------
|
||||
|
||||
Objective Model::AddAuxiliaryObjective(const int64_t priority,
|
||||
|
||||
@@ -20,9 +20,12 @@
|
||||
#include <utility>
|
||||
|
||||
#include "absl/algorithm/container.h"
|
||||
#include "absl/log/check.h"
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/status/statusor.h"
|
||||
#include "absl/time/time.h"
|
||||
#include "google/protobuf/repeated_field.h"
|
||||
#include "ortools/base/protoutil.h"
|
||||
#include "ortools/base/status_macros.h"
|
||||
#include "ortools/math_opt/cpp/linear_constraint.h"
|
||||
#include "ortools/math_opt/cpp/model.h"
|
||||
@@ -137,8 +140,8 @@ ModelSolveParameters::SolutionHint::FromProto(
|
||||
};
|
||||
}
|
||||
|
||||
ObjectiveParametersProto ModelSolveParameters::ObjectiveParameters::Proto()
|
||||
const {
|
||||
absl::StatusOr<ObjectiveParametersProto>
|
||||
ModelSolveParameters::ObjectiveParameters::Proto() const {
|
||||
ObjectiveParametersProto params;
|
||||
if (objective_degradation_absolute_tolerance) {
|
||||
params.set_objective_degradation_absolute_tolerance(
|
||||
@@ -148,10 +151,14 @@ ObjectiveParametersProto ModelSolveParameters::ObjectiveParameters::Proto()
|
||||
params.set_objective_degradation_relative_tolerance(
|
||||
*objective_degradation_relative_tolerance);
|
||||
}
|
||||
if (time_limit < absl::InfiniteDuration()) {
|
||||
RETURN_IF_ERROR(util_time::EncodeGoogleApiProto(
|
||||
time_limit, params.mutable_time_limit()));
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
ModelSolveParameters::ObjectiveParameters
|
||||
absl::StatusOr<ModelSolveParameters::ObjectiveParameters>
|
||||
ModelSolveParameters::ObjectiveParameters::FromProto(
|
||||
const ObjectiveParametersProto& proto) {
|
||||
ObjectiveParameters result;
|
||||
@@ -163,11 +170,18 @@ ModelSolveParameters::ObjectiveParameters::FromProto(
|
||||
result.objective_degradation_relative_tolerance =
|
||||
proto.objective_degradation_relative_tolerance();
|
||||
}
|
||||
if (proto.has_time_limit()) {
|
||||
OR_ASSIGN_OR_RETURN3(result.time_limit,
|
||||
util_time::DecodeGoogleApiProto(proto.time_limit()),
|
||||
_ << "invalid time_limit");
|
||||
} else {
|
||||
result.time_limit = absl::InfiniteDuration();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// TODO: b/315974557 - Return an error if a RepeatedField is too long.
|
||||
ModelSolveParametersProto ModelSolveParameters::Proto() const {
|
||||
absl::StatusOr<ModelSolveParametersProto> ModelSolveParameters::Proto() const {
|
||||
ModelSolveParametersProto ret;
|
||||
*ret.mutable_variable_values_filter() = variable_values_filter.Proto();
|
||||
*ret.mutable_dual_values_filter() = dual_values_filter.Proto();
|
||||
@@ -195,11 +209,15 @@ ModelSolveParametersProto ModelSolveParameters::Proto() const {
|
||||
}
|
||||
}
|
||||
for (const auto& [objective, params] : objective_parameters) {
|
||||
if (objective.id()) {
|
||||
(*ret.mutable_auxiliary_objective_parameters())[*objective.id()] =
|
||||
params.Proto();
|
||||
if (objective.id().has_value()) {
|
||||
OR_ASSIGN_OR_RETURN3(
|
||||
((*ret.mutable_auxiliary_objective_parameters())[*objective.id()]),
|
||||
params.Proto(),
|
||||
_ << "invalid parameters for objective " << *objective.id());
|
||||
} else {
|
||||
*ret.mutable_primary_objective_parameters() = params.Proto();
|
||||
OR_ASSIGN_OR_RETURN3(*ret.mutable_primary_objective_parameters(),
|
||||
params.Proto(),
|
||||
_ << "invalid parameters for primary objective");
|
||||
}
|
||||
}
|
||||
if (!lazy_linear_constraints.empty()) {
|
||||
@@ -253,9 +271,13 @@ absl::StatusOr<ModelSolveParameters> ModelSolveParameters::FromProto(
|
||||
VariableValuesFromProto(model.storage(), proto.branching_priorities()),
|
||||
_ << "invalid branching_priorities");
|
||||
if (proto.has_primary_objective_parameters()) {
|
||||
OR_ASSIGN_OR_RETURN3(
|
||||
auto primary_objective_params,
|
||||
ObjectiveParameters::FromProto(proto.primary_objective_parameters()),
|
||||
_ << "invalid primary_objective_parameters");
|
||||
result.objective_parameters.try_emplace(
|
||||
Objective::Primary(model.storage()),
|
||||
ObjectiveParameters::FromProto(proto.primary_objective_parameters()));
|
||||
std::move(primary_objective_params));
|
||||
}
|
||||
for (const auto& [id, aux_obj_params_proto] :
|
||||
proto.auxiliary_objective_parameters()) {
|
||||
@@ -264,9 +286,13 @@ absl::StatusOr<ModelSolveParameters> ModelSolveParameters::FromProto(
|
||||
<< "invalid auxiliary_objective_parameters with id: " << id
|
||||
<< ", objective not in the model";
|
||||
}
|
||||
OR_ASSIGN_OR_RETURN3(
|
||||
auto aux_obj_params,
|
||||
ObjectiveParameters::FromProto(aux_obj_params_proto),
|
||||
_ << "invalid auxiliary_objective_parameters with id: " << id);
|
||||
result.objective_parameters.try_emplace(
|
||||
Objective::Auxiliary(model.storage(), AuxiliaryObjectiveId{id}),
|
||||
ObjectiveParameters::FromProto(aux_obj_params_proto));
|
||||
std::move(aux_obj_params));
|
||||
}
|
||||
for (int64_t lin_con : proto.lazy_linear_constraint_ids()) {
|
||||
if (!model.has_linear_constraint(lin_con)) {
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "absl/container/flat_hash_set.h"
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/status/statusor.h"
|
||||
#include "absl/time/time.h"
|
||||
#include "ortools/math_opt/cpp/linear_constraint.h"
|
||||
#include "ortools/math_opt/cpp/map_filter.h" // IWYU pragma: export
|
||||
#include "ortools/math_opt/cpp/model.h"
|
||||
@@ -184,10 +185,21 @@ struct ModelSolveParameters {
|
||||
// If set, must be nonnegative.
|
||||
std::optional<double> objective_degradation_relative_tolerance;
|
||||
|
||||
// Returns the proto equivalent of this object.
|
||||
ObjectiveParametersProto Proto() const;
|
||||
// Maximum time a solver should spend on optimizing this particular
|
||||
// objective (or infinite if not set).
|
||||
//
|
||||
// Note that this does not supersede the global time limit in
|
||||
// SolveParametersProto.time_limit; both will be enforced when set.
|
||||
//
|
||||
// This value is not a hard limit, solve time may slightly exceed this
|
||||
// value.
|
||||
absl::Duration time_limit = absl::InfiniteDuration();
|
||||
|
||||
static ObjectiveParameters FromProto(const ObjectiveParametersProto& proto);
|
||||
// Returns the proto equivalent of this object.
|
||||
absl::StatusOr<ObjectiveParametersProto> Proto() const;
|
||||
|
||||
static absl::StatusOr<ObjectiveParameters> FromProto(
|
||||
const ObjectiveParametersProto& proto);
|
||||
};
|
||||
// Parameters for individual objectives in a multi-objective model.
|
||||
ObjectiveMap<ObjectiveParameters> objective_parameters;
|
||||
@@ -209,7 +221,7 @@ struct ModelSolveParameters {
|
||||
//
|
||||
// The caller should use CheckModelStorage() as this function does not check
|
||||
// internal consistency of the referenced variables and constraints.
|
||||
ModelSolveParametersProto Proto() const;
|
||||
absl::StatusOr<ModelSolveParametersProto> Proto() const;
|
||||
|
||||
// Returns the ModelSolveParameters corresponding to this proto and the given
|
||||
// model.
|
||||
|
||||
@@ -78,9 +78,11 @@ absl::StatusOr<SolveResult> CallSolve(
|
||||
};
|
||||
}
|
||||
|
||||
ASSIGN_OR_RETURN(ModelSolveParametersProto model_parameters,
|
||||
arguments.model_parameters.Proto());
|
||||
const absl::StatusOr<SolveResultProto> solve_result_proto = solver.Solve(
|
||||
{.parameters = arguments.parameters.Proto(),
|
||||
.model_parameters = arguments.model_parameters.Proto(),
|
||||
.model_parameters = std::move(model_parameters),
|
||||
.message_callback = arguments.message_callback,
|
||||
.callback_registration = arguments.callback_registration.Proto(),
|
||||
.user_cb = std::move(cb),
|
||||
|
||||
@@ -30,13 +30,17 @@ namespace operations_research::math_opt {
|
||||
// parameters are hints and may be ignored by the remote server (in particular
|
||||
// in case of solve in a local subprocess, for example).
|
||||
//
|
||||
// When using RemoteSolve() and RemoteComputeInfeasibleSubsystem(), these hints
|
||||
// are mostly optional as some defaults will be computed based on the other
|
||||
// parameters.
|
||||
// When using:
|
||||
// - RemoteSolve(),
|
||||
// - RemoteComputeInfeasibleSubsystem(),
|
||||
// - XxxRemoteStreamingSolve(),
|
||||
// - XxxRemoteStreamingComputeInfeasibleSubsystem(),
|
||||
// these hints are recommended but optional. When they are not provided,
|
||||
// resource usage will be estimated based on other parameters.
|
||||
//
|
||||
// When using RemoteStreamingSolve() these hints are used to dimension the
|
||||
// resources available during the execution of every action; thus it is
|
||||
// recommended to set them.
|
||||
// When using NewXxxRemoteStreamingIncrementalSolver() these hints are used to
|
||||
// dimension the resources available during the execution of every action; thus
|
||||
// it is recommended to set them.
|
||||
//
|
||||
struct SolverResources {
|
||||
// The number of solver threads that are expected to actually execute in
|
||||
|
||||
@@ -17,6 +17,7 @@ syntax = "proto3";
|
||||
|
||||
package operations_research.math_opt;
|
||||
|
||||
import "google/protobuf/duration.proto";
|
||||
import "ortools/math_opt/solution.proto";
|
||||
import "ortools/math_opt/sparse_containers.proto";
|
||||
|
||||
@@ -89,6 +90,15 @@ message ObjectiveParametersProto {
|
||||
//
|
||||
// If set, must be nonnegative.
|
||||
optional double objective_degradation_relative_tolerance = 8;
|
||||
|
||||
// Maximum time a solver should spend on optimizing this particular objective
|
||||
// (or infinite if not set).
|
||||
//
|
||||
// Note that this does not supersede the global time limit in
|
||||
// SolveParametersProto.time_limit; both will be enforced when set.
|
||||
//
|
||||
// This value is not a hard limit, solve time may slightly exceed this value.
|
||||
google.protobuf.Duration time_limit = 9;
|
||||
}
|
||||
|
||||
// TODO(b/183628247): follow naming convention in fields below.
|
||||
|
||||
@@ -317,6 +317,7 @@ cc_library(
|
||||
"@com_google_absl//absl/status",
|
||||
"@com_google_absl//absl/status:statusor",
|
||||
"@com_google_absl//absl/strings:string_view",
|
||||
"@com_google_absl//absl/time",
|
||||
],
|
||||
# Make sure the tests are included when using --dynamic_mode=off.
|
||||
alwayslink = 1,
|
||||
|
||||
@@ -110,7 +110,8 @@ ortools_cxx_library(
|
||||
TESTING
|
||||
)
|
||||
|
||||
# In CMake or-tools is linked with all enable solvers so this test won't work.
|
||||
# In CMake, or-tools is linked with all solvers enable at configure time so this
|
||||
# test won't work...
|
||||
#ortools_cxx_test(
|
||||
# NAME
|
||||
# ${_PREFIX}_unregistered_solver_test
|
||||
|
||||
@@ -15,10 +15,12 @@
|
||||
|
||||
#include <memory>
|
||||
#include <ostream>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/status/statusor.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/time/time.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "ortools/base/gmock.h"
|
||||
#include "ortools/base/status_macros.h"
|
||||
|
||||
@@ -30,6 +30,7 @@ cc_library(
|
||||
"//ortools/gurobi:environment",
|
||||
"//ortools/gurobi/isv_public:gurobi_isv",
|
||||
"//ortools/math_opt/solvers:gurobi_cc_proto",
|
||||
"@com_google_absl//absl/log",
|
||||
"@com_google_absl//absl/log:check",
|
||||
"@com_google_absl//absl/log:die_if_null",
|
||||
"@com_google_absl//absl/memory",
|
||||
|
||||
@@ -777,6 +777,23 @@ absl::Status Gurobi::ResetParameters() {
|
||||
return ToStatus(GRBresetparams(model_env_));
|
||||
}
|
||||
|
||||
absl::Status Gurobi::SetMultiObjectiveDoubleParam(const char* const name,
|
||||
const int obj_index,
|
||||
const double value) {
|
||||
ASSIGN_OR_RETURN(GRBenv* const obj_env, GetMultiObjectiveEnv(obj_index));
|
||||
return util::StatusBuilder(ToStatus(GRBsetdblparam(obj_env, name, value)))
|
||||
<< " for objective index: " << obj_index;
|
||||
}
|
||||
|
||||
absl::StatusOr<double> Gurobi::GetMultiObjectiveDoubleParam(
|
||||
const char* const name, const int obj_index) {
|
||||
ASSIGN_OR_RETURN(GRBenv* const obj_env, GetMultiObjectiveEnv(obj_index));
|
||||
double result;
|
||||
RETURN_IF_ERROR(ToStatus(GRBgetdblparam(obj_env, name, &result)))
|
||||
<< " for objective index: " << obj_index;
|
||||
return result;
|
||||
}
|
||||
|
||||
void Gurobi::Terminate() { GRBterminate(gurobi_model_); }
|
||||
|
||||
Gurobi::CallbackContext::CallbackContext(Gurobi* const gurobi,
|
||||
@@ -842,4 +859,15 @@ absl::StatusOr<double> Gurobi::CallbackContext::CbSolution(
|
||||
return result;
|
||||
}
|
||||
|
||||
absl::StatusOr<GRBenv*> Gurobi::GetMultiObjectiveEnv(
|
||||
const int obj_index) const {
|
||||
GRBenv* const obj_env = GRBgetmultiobjenv(gurobi_model_, obj_index);
|
||||
if (obj_env == nullptr) {
|
||||
return util::InvalidArgumentErrorBuilder()
|
||||
<< "Failed to get objective environment for objective index: "
|
||||
<< obj_index;
|
||||
}
|
||||
return obj_env;
|
||||
}
|
||||
|
||||
} // namespace operations_research::math_opt
|
||||
|
||||
@@ -556,6 +556,20 @@ class Gurobi {
|
||||
// Calls GRBresetparams().
|
||||
absl::Status ResetParameters();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Multi-objective Parameters
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Calls GRBsetdblparam() on the environment associated with the
|
||||
// `obj_index`-th objective.
|
||||
absl::Status SetMultiObjectiveDoubleParam(const char* name, int obj_index,
|
||||
double value);
|
||||
|
||||
// Calls GRBgetdblparam() on the environment associated with the
|
||||
// `obj_index`-th objective.
|
||||
absl::StatusOr<double> GetMultiObjectiveDoubleParam(const char* name,
|
||||
int obj_index);
|
||||
|
||||
// Typically not needed.
|
||||
GRBmodel* model() const { return gurobi_model_; }
|
||||
|
||||
@@ -570,6 +584,7 @@ class Gurobi {
|
||||
// optional_owned_primary_env can be null, primary_env cannot.
|
||||
static absl::StatusOr<std::unique_ptr<Gurobi>> New(
|
||||
GRBenvUniquePtr optional_owned_primary_env, GRBenv* primary_env);
|
||||
absl::StatusOr<GRBenv*> GetMultiObjectiveEnv(int obj_index) const;
|
||||
|
||||
const GRBenvUniquePtr owned_primary_env_;
|
||||
// Invariant: Not null.
|
||||
|
||||
@@ -203,6 +203,7 @@ cc_library(
|
||||
"@com_google_absl//absl/container:flat_hash_map",
|
||||
"@com_google_absl//absl/container:flat_hash_set",
|
||||
"@com_google_absl//absl/log:check",
|
||||
"@com_google_absl//absl/memory",
|
||||
"@com_google_absl//absl/status",
|
||||
"@com_google_absl//absl/status:statusor",
|
||||
"@com_google_absl//absl/strings",
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace operations_research::math_opt {
|
||||
// const std::pair<XXX, std::unique_ptr<UpdateData>>&
|
||||
// The returned iterator will be over non-const references to Field as read off
|
||||
// the UpdateData values.
|
||||
template <typename UpdateData, typename V, V UpdateData::*Field,
|
||||
template <typename UpdateData, typename V, V UpdateData::* Field,
|
||||
typename BaseIter>
|
||||
class UpdateDataFieldIterator {
|
||||
public:
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <new>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
@@ -23,6 +24,7 @@
|
||||
#include "absl/container/flat_hash_map.h"
|
||||
#include "absl/container/flat_hash_set.h"
|
||||
#include "absl/log/check.h"
|
||||
#include "absl/memory/memory.h"
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/status/statusor.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
|
||||
@@ -164,7 +164,7 @@ class ModelStorage {
|
||||
// considered invalid when solving.
|
||||
//
|
||||
// See ApplyUpdateProto() for dealing with subsequent updates.
|
||||
static absl::StatusOr<std::unique_ptr<ModelStorage>> FromModelProto(
|
||||
static absl::StatusOr<std::unique_ptr<ModelStorage> > FromModelProto(
|
||||
const ModelProto& model_proto);
|
||||
|
||||
// Creates an empty minimization problem.
|
||||
@@ -326,7 +326,7 @@ class ModelStorage {
|
||||
|
||||
// The {linear constraint, variable, coefficient} tuples with nonzero linear
|
||||
// constraint matrix coefficients.
|
||||
inline std::vector<std::tuple<LinearConstraintId, VariableId, double>>
|
||||
inline std::vector<std::tuple<LinearConstraintId, VariableId, double> >
|
||||
linear_constraint_matrix() const;
|
||||
|
||||
// Returns the variables with nonzero coefficients in a linear constraint.
|
||||
@@ -399,7 +399,7 @@ class ModelStorage {
|
||||
// are ordered such that .first <= .second. All values are nonempty.
|
||||
//
|
||||
// TODO(b/233630053) do no allocate the result, expose an iterator API.
|
||||
inline std::vector<std::tuple<VariableId, VariableId, double>>
|
||||
inline std::vector<std::tuple<VariableId, VariableId, double> >
|
||||
quadratic_objective_terms(ObjectiveId id) const;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -194,12 +194,15 @@ cc_library(
|
||||
":ids_validator",
|
||||
":solution_validator",
|
||||
":sparse_vector_validator",
|
||||
"//ortools/base:protoutil",
|
||||
"//ortools/base:status_macros",
|
||||
"//ortools/math_opt:model_parameters_cc_proto",
|
||||
"//ortools/math_opt:sparse_containers_cc_proto",
|
||||
"//ortools/math_opt/core:model_summary",
|
||||
"//ortools/math_opt/core:sparse_vector_view",
|
||||
"//ortools/util:status_macros",
|
||||
"@com_google_absl//absl/status",
|
||||
"@com_google_absl//absl/time",
|
||||
"@com_google_protobuf//:protobuf",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -16,7 +16,9 @@
|
||||
#include <cstdint>
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/time/time.h"
|
||||
#include "google/protobuf/repeated_field.h"
|
||||
#include "ortools/base/protoutil.h"
|
||||
#include "ortools/base/status_builder.h"
|
||||
#include "ortools/base/status_macros.h"
|
||||
#include "ortools/math_opt/core/model_summary.h"
|
||||
@@ -26,6 +28,7 @@
|
||||
#include "ortools/math_opt/validators/ids_validator.h"
|
||||
#include "ortools/math_opt/validators/solution_validator.h"
|
||||
#include "ortools/math_opt/validators/sparse_vector_validator.h"
|
||||
#include "ortools/util/status_macros.h"
|
||||
|
||||
namespace operations_research {
|
||||
namespace math_opt {
|
||||
@@ -80,6 +83,17 @@ absl::Status ValidateObjectiveParameters(
|
||||
"tolerance = "
|
||||
<< parameters.objective_degradation_relative_tolerance() << " < 0";
|
||||
}
|
||||
{
|
||||
OR_ASSIGN_OR_RETURN3(
|
||||
const absl::Duration time_limit,
|
||||
util_time::DecodeGoogleApiProto(parameters.time_limit()),
|
||||
_ << "invalid ObjectiveParametersProto.time_limit");
|
||||
if (time_limit < absl::ZeroDuration()) {
|
||||
return util::InvalidArgumentErrorBuilder()
|
||||
<< "ObjectiveParametersProto.time_limit = " << time_limit
|
||||
<< " < 0";
|
||||
}
|
||||
}
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user