Files
2025-12-09 22:49:43 +01:00

1647 lines
65 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.
// IWYU pragma: private, include "ortools/math_opt/cpp/math_opt.h"
// IWYU pragma: friend "ortools/math_opt/cpp/.*"
#ifndef ORTOOLS_MATH_OPT_CPP_MODEL_H_
#define ORTOOLS_MATH_OPT_CPP_MODEL_H_
#include <cstdint>
#include <memory>
#include <optional>
#include <ostream>
#include <vector>
#include "absl/base/nullability.h"
#include "absl/log/check.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/string_view.h"
#include "absl/types/span.h"
#include "ortools/base/status_builder.h"
#include "ortools/base/strong_int.h"
#include "ortools/math_opt/constraints/indicator/indicator_constraint.h" // IWYU pragma: export
#include "ortools/math_opt/constraints/quadratic/quadratic_constraint.h" // IWYU pragma: export
#include "ortools/math_opt/constraints/second_order_cone/second_order_cone_constraint.h" // IWYU pragma: export
#include "ortools/math_opt/constraints/sos/sos1_constraint.h" // IWYU pragma: export
#include "ortools/math_opt/constraints/sos/sos2_constraint.h" // IWYU pragma: export
#include "ortools/math_opt/constraints/util/model_util.h"
#include "ortools/math_opt/cpp/key_types.h"
#include "ortools/math_opt/cpp/linear_constraint.h" // IWYU pragma: export
#include "ortools/math_opt/cpp/objective.h" // IWYU pragma: export
#include "ortools/math_opt/cpp/update_tracker.h" // IWYU pragma: export
#include "ortools/math_opt/cpp/variable_and_expressions.h" // IWYU pragma: export
#include "ortools/math_opt/model.pb.h" // IWYU pragma: export
#include "ortools/math_opt/model_update.pb.h" // IWYU pragma: export
#include "ortools/math_opt/storage/model_storage.h" // IWYU pragma: export
#include "ortools/math_opt/storage/model_storage_types.h" // IWYU pragma: export
namespace operations_research {
namespace math_opt {
// A C++ API for building optimization problems.
//
// Warning: Variable and LinearConstraint (along with all other constraint
// objects) are value types, see "Memory Model" below.
//
// A simple example:
//
// Model the problem:
// max 2.0 * x + y
// s.t. x + y <= 1.5
// x in {0.0, 1.0}
// y in [0.0, 2.5]
//
// math_opt::Model model("my_model");
// const math_opt::Variable x = model.AddBinaryVariable("x");
// const math_opt::Variable y = model.AddContinuousVariable(0.0, 2.5, "y");
// // We can directly use linear combinations of variables ...
// model.AddLinearConstraint(x + y <= 1.5, "c");
// // ... or build them incrementally.
// math_opt::LinearExpression objective_expression;
// objective_expression += 2 * x;
// objective_expression += y;
// model.Maximize(objective_expression);
// ASSIGN_OR_RETURN(const math_opt::SolveResult result,
// Solve(model, math_opt::SolverType::kGscip));
// switch (result.termination.reason) {
// case math_opt::TerminationReason::kOptimal:
// case math_opt::TerminationReason::kFeasible:
// std::cout << "objective value: " << result.objective_value() << std::endl
// << "value for variable x: " << result.variable_values().at(x)
// << std::endl;
// return absl::OkStatus();
// default:
// return util::InternalErrorBuilder()
// << "model failed to solve: " << result.termination;
// }
//
// Memory model:
//
// Variable, LinearConstraint, QuadraticConstraint, etc. are value types that
// represent references to the underlying Model object. They don't hold any of
// the actual model data, they can be copied, and they should be passed by
// value. They can be regenerated arbitrarily from Model. Model holds all the
// data.
//
// As a consequence of Variable and LinearConstraint holding back pointers,
// Model is not copyable or movable. Users needing to copy a Model can call
// Model::Clone() (this will create a new Model with no update trackers), and
// users needing to move a Model should wrap it in a std::unique_ptr.
//
// Performance:
//
// This class is a thin wrapper around ModelStorage (for incrementally building
// the model and reading it back, and producing the Model proto). Operations for
// building/reading/modifying the problem typically run in O(read/write size)
// and rely on hashing, see the ModelStorage documentation for details. At
// solve time (if you are solving locally) beware that there will be (at least)
// three copies of the model in memory, ModelStorage, the Model proto, and the
// underlying solver's copy(/ies). Note that the Model proto is reclaimed before
// the underlying solver begins solving.
class Model {
public:
// Returns a model from the input proto. Returns a failure status if the input
// proto is invalid.
//
// On top of loading a model from a MathOpt ModelProto, this function can also
// be used to load a model from other formats using the functions in
// math_opt/io/ like ReadMpsFile().
//
// See ExportModel() to get the proto of a Model. See ApplyUpdateProto() to
// apply an update to the model.
//
// Usage example reading an MPS file:
// ASSIGN_OR_RETURN(const ModelProto model_proto, ReadMpsFile(path));
// ASSIGN_OR_RETURN(const std::unique_ptr<Model> model,
// Model::FromModelProto(model_proto));
static absl::StatusOr<std::unique_ptr<Model>> FromModelProto(
const ModelProto& model_proto);
// Creates an empty minimization problem.
explicit Model(absl::string_view name = "");
// Creates a model from the existing model storage.
//
// This constructor is used when loading a model, for example from a
// ModelProto or an MPS file. Note that in those cases the FromModelProto()
// should be used.
explicit Model(absl_nonnull std::unique_ptr<ModelStorage> storage);
Model(const Model&) = delete;
Model& operator=(const Model&) = delete;
// Returns a clone of this model, optionally changing the model's name.
//
// The variables and constraints have the same integer ids. The clone will
// also not reused any id of variable/constraint that was deleted in the
// original.
//
// That said, the Variable and LinearConstraint reference objects are model
// specific. Hence the ones linked to the original model must NOT be used with
// the clone. The Variable and LinearConstraint reference objects for the
// clone can be obtained using:
// * the variable() and linear_constraint() methods on the ids from the old
// Variable and LinearConstraint objects.
// * in increasing id order using SortedVariables() and
// SortedLinearConstraints()
// * in an arbitrary order using Variables() and LinearConstraints().
//
// Note that the returned model does not have any update tracker.
absl_nonnull std::unique_ptr<Model> Clone(
std::optional<absl::string_view> new_name = std::nullopt) const;
inline absl::string_view name() const;
//////////////////////////////////////////////////////////////////////////////
// Variable methods
//////////////////////////////////////////////////////////////////////////////
// Adds a variable to the model and returns a reference to it.
inline Variable AddVariable(double lower_bound, double upper_bound,
bool is_integer, absl::string_view name = "");
// Adds a continuous unbounded variable to the model.
inline Variable AddVariable(absl::string_view name = "");
// Adds a variable to the model with domain {0, 1}.
inline Variable AddBinaryVariable(absl::string_view name = "");
// Adds a variable to the model with domain [lower_bound, upper_bound].
inline Variable AddContinuousVariable(double lower_bound, double upper_bound,
absl::string_view name = "");
// Adds a variable to the model that can take integer values between
// lower_bound and upper_bound (inclusive).
inline Variable AddIntegerVariable(double lower_bound, double upper_bound,
absl::string_view name = "");
// Removes a variable from the model.
//
// It is an error to use any reference to this variable after this operation.
// Runs in O(#constraints containing the variable).
inline void DeleteVariable(Variable variable);
// The number of variables in the model.
//
// Equal to the number of variables created minus the number of variables
// deleted.
inline int num_variables() const;
// The returned id of the next call to AddVariable.
//
// Equal to the number of variables created.
inline int64_t next_variable_id() const;
// Returns true if this id has been created and not yet deleted.
inline bool has_variable(int64_t id) const;
// Returns true if this id has been created and not yet deleted.
inline bool has_variable(VariableId id) const;
// Will CHECK if has_variable(id) is false.
inline Variable variable(int64_t id) const;
// Will CHECK if has_variable(id) is false.
inline Variable variable(VariableId id) const;
// Returns the variable name.
inline absl::string_view name(Variable variable) const;
// Sets a variable lower bound.
inline void set_lower_bound(Variable variable, double lower_bound);
// Returns a variable lower bound.
inline double lower_bound(Variable variable) const;
// Sets a variable upper bound.
inline void set_upper_bound(Variable variable, double upper_bound);
// Returns a variable upper bound.
inline double upper_bound(Variable variable) const;
// Sets the integrality of a variable.
inline void set_is_integer(Variable variable, bool is_integer);
// Makes the input variable integer.
inline void set_integer(Variable variable);
// Makes the input variable continuous.
inline void set_continuous(Variable variable);
// Returns the integrality of a variable.
inline bool is_integer(Variable variable) const;
// Returns all the existing (created and not deleted) variables in the model
// in an arbitrary order.
std::vector<Variable> Variables() const;
// Returns all the existing (created and not deleted) variables in the model,
// sorted by id.
std::vector<Variable> SortedVariables() const;
// Returns an error if `variable` is from another model or the id is not in
// this model (typically, if it was deleted).
inline absl::Status ValidateExistingVariableOfThisModel(
Variable variable) const;
std::vector<LinearConstraint> ColumnNonzeros(Variable variable) const;
//////////////////////////////////////////////////////////////////////////////
// LinearConstraint methods
//////////////////////////////////////////////////////////////////////////////
// Adds a linear constraint to the model with bounds [-inf, +inf].
inline LinearConstraint AddLinearConstraint(absl::string_view name = "");
// Adds a linear constraint with bounds [lower_bound, upper_bound].
inline LinearConstraint AddLinearConstraint(double lower_bound,
double upper_bound,
absl::string_view name = "");
// Adds a linear constraint from the given bounded linear expression.
//
// Usage:
// Model model = ...;
// const Variable x = ...;
// const Variable y = ...;
// model.AddLinearConstraint(3 <= 2 * x + y + 1 <= 5, "c");
// // The new constraint formula is:
// // 3 - 1 <= 2 * x + y <= 5 - 1
// // Which is:
// // 2 <= 2 * x + y <= 4
// // since the offset has been removed from bounds.
//
// model.AddLinearConstraint(2 * x + y == x + 5 * z + 3);
// model.AddLinearConstraint(x >= 5);
LinearConstraint AddLinearConstraint(
const BoundedLinearExpression& bounded_expr, absl::string_view name = "");
// Removes a linear constraint from the model.
//
// It is an error to use any reference to this linear constraint after this
// operation. Runs in O(#variables in the linear constraint).
inline void DeleteLinearConstraint(LinearConstraint constraint);
// The number of linear constraints in the model.
//
// Equal to the number of linear constraints created minus the number of
// linear constraints deleted.
inline int num_linear_constraints() const;
// The returned id of the next call to AddLinearConstraint.
//
// Equal to the number of linear constraints created.
inline int64_t next_linear_constraint_id() const;
// Returns true if this id has been created and not yet deleted.
inline bool has_linear_constraint(int64_t id) const;
// Returns true if this id has been created and not yet deleted.
inline bool has_linear_constraint(LinearConstraintId id) const;
// Will CHECK if has_linear_constraint(id) is false.
inline LinearConstraint linear_constraint(int64_t id) const;
// Will CHECK if has_linear_constraint(id) is false.
inline LinearConstraint linear_constraint(LinearConstraintId id) const;
// Returns the linear constraint name.
inline absl::string_view name(LinearConstraint constraint) const;
// Sets a linear constraint lower bound.
inline void set_lower_bound(LinearConstraint constraint, double lower_bound);
// Returns a linear constraint lower bound.
inline double lower_bound(LinearConstraint constraint) const;
// Sets a linear constraint upper bound.
inline void set_upper_bound(LinearConstraint constraint, double upper_bound);
// Returns a linear constraint upper bound.
inline double upper_bound(LinearConstraint constraint) const;
// Setting a value to 0.0 will delete the {constraint, variable} pair from the
// underlying sparse matrix representation (and has no effect if the pair is
// not present).
inline void set_coefficient(LinearConstraint constraint, Variable variable,
double value);
// Returns 0.0 if the variable is not used in the constraint.
inline double coefficient(LinearConstraint constraint,
Variable variable) const;
inline bool is_coefficient_nonzero(LinearConstraint constraint,
Variable variable) const;
std::vector<Variable> RowNonzeros(LinearConstraint constraint) const;
// Returns all the existing (created and not deleted) linear constraints in
// the model in an arbitrary order.
std::vector<LinearConstraint> LinearConstraints() const;
// Returns all the existing (created and not deleted) linear constraints in
// the model sorted by id.
std::vector<LinearConstraint> SortedLinearConstraints() const;
// Returns an error if `linear_constraint` is from another model or the id is
// not in this model (typically, if it was deleted).
inline absl::Status ValidateExistingLinearConstraintOfThisModel(
LinearConstraint linear_constraint) const;
//////////////////////////////////////////////////////////////////////////////
// QuadraticConstraint methods
//////////////////////////////////////////////////////////////////////////////
// Adds a quadratic constraint from the given bounded quadratic expression.
//
// Usage:
// Model model = ...;
// const Variable x = ...;
// const Variable y = ...;
// model.AddQuadraticConstraint(2 * x * x + y + 1 <= 5, "q");
// model.AddQuadraticConstraint(2 * x * x + y * y == x + 5 * z + 3);
// model.AddQuadraticConstraint(x * y >= 5);
QuadraticConstraint AddQuadraticConstraint(
const BoundedQuadraticExpression& bounded_expr,
absl::string_view name = "");
// Removes a quadratic constraint from the model.
//
// It is an error to use any reference to this quadratic constraint after this
// operation. Runs in O(#linear or quadratic terms appearing in constraint).
inline void DeleteQuadraticConstraint(QuadraticConstraint constraint);
// The number of quadratic constraints in the model.
//
// Equal to the number of quadratic constraints created minus the number of
// quadratic constraints deleted.
inline int64_t num_quadratic_constraints() const;
// The returned id of the next call to AddQuadraticConstraint.
inline int64_t next_quadratic_constraint_id() const;
// Returns true if this id has been created and not yet deleted.
inline bool has_quadratic_constraint(int64_t id) const;
// Returns true if this id has been created and not yet deleted.
inline bool has_quadratic_constraint(QuadraticConstraintId id) const;
// Will CHECK if has_quadratic_constraint(id) is false.
inline QuadraticConstraint quadratic_constraint(int64_t id) const;
// Will CHECK if has_quadratic_constraint(id) is false.
inline QuadraticConstraint quadratic_constraint(
QuadraticConstraintId id) const;
// Returns all the existing (created and not deleted) quadratic constraints in
// the model in an arbitrary order.
inline std::vector<QuadraticConstraint> QuadraticConstraints() const;
// Returns all the existing (created and not deleted) quadratic constraints in
// the model sorted by id.
inline std::vector<QuadraticConstraint> SortedQuadraticConstraints() const;
//////////////////////////////////////////////////////////////////////////////
// SecondOrderConeConstraint methods
//////////////////////////////////////////////////////////////////////////////
// Adds a second-order cone constraint to the model of the form
// ||arguments_to_norm||₂ ≤ upper_bound.
//
// Usage:
// Model model = ...;
// const Variable x = ...;
// const Variable y = ...;
// model.AddSecondOrderConeConstraint({x, y}, 1.0, "soc");
// model.AddSecondOrderConeConstraint({1.0, 3 * y - x}, 2 * x);
SecondOrderConeConstraint AddSecondOrderConeConstraint(
absl::Span<const LinearExpression> arguments_to_norm,
const LinearExpression& upper_bound, absl::string_view name = "");
// Removes a second-order cone constraint from the model.
//
// It is an error to use any reference to this second-order cone constraint
// after this operation. Runs in O(#linear terms appearing in constraint).
inline void DeleteSecondOrderConeConstraint(
SecondOrderConeConstraint constraint);
// The number of second-order cone constraints in the model.
//
// Equal to the number of second-order cone constraints created minus the
// number of second-order cone constraints deleted.
inline int64_t num_second_order_cone_constraints() const;
// The returned id of the next call to AddSecondOrderConeConstraint.
inline int64_t next_second_order_cone_constraint_id() const;
// Returns true if this id has been created and not yet deleted.
inline bool has_second_order_cone_constraint(int64_t id) const;
// Returns true if this id has been created and not yet deleted.
inline bool has_second_order_cone_constraint(
SecondOrderConeConstraintId id) const;
// Will CHECK if has_second_order_cone_constraint(id) is false.
inline SecondOrderConeConstraint second_order_cone_constraint(
int64_t id) const;
// Will CHECK if has_second_order_cone_constraint(id) is false.
inline SecondOrderConeConstraint second_order_cone_constraint(
SecondOrderConeConstraintId id) const;
// Returns all the existing (created and not deleted) second-order cone
// constraints in the model in an arbitrary order.
inline std::vector<SecondOrderConeConstraint> SecondOrderConeConstraints()
const;
// Returns all the existing (created and not deleted) second-order cone
// constraints in the model sorted by id.
inline std::vector<SecondOrderConeConstraint>
SortedSecondOrderConeConstraints() const;
//////////////////////////////////////////////////////////////////////////////
// Sos1Constraint methods
//////////////////////////////////////////////////////////////////////////////
// Adds an SOS1 constraint to the model: at most one of the `expressions` may
// take a nonzero value.
//
// The `weights` are an implementation detail in the solver used to order the
// `expressions`; see the Gurobi documentation for more detail:
// https://www.gurobi.com/documentation/9.5/refman/constraints.html#subsubsection:SOSConstraints
// For Xpress see
// https://www.fico.com/fico-xpress-optimization/docs/latest/solver/optimizer/HTML/XPRSaddsets.html
//
// These `weights` must either be empty or the same length as `expressions`.
// If it is empty, default weights of 1, 2, ... will be used.
//
// Usage:
// Model model = ...;
// const Variable x = ...;
// const Variable y = ...;
// model.AddSos1Constraint({x, y}, {}, "c");
// model.AddSos1Constraint({1 - 2 * x, y}, {3, 2});
Sos1Constraint AddSos1Constraint(
const std::vector<LinearExpression>& expressions,
std::vector<double> weights = {}, absl::string_view name = "");
// Removes an SOS1 constraint from the model.
//
// It is an error to use any reference to this SOS1 constraint after this
// operation. Runs in O(#terms in all expressions).
inline void DeleteSos1Constraint(Sos1Constraint constraint);
// The number of SOS1 constraints in the model.
//
// Equal to the number of SOS1 constraints created minus the number of SOS1
// constraints deleted.
inline int64_t num_sos1_constraints() const;
// The returned id of the next call to AddSos1Constraint.
inline int64_t next_sos1_constraint_id() const;
// Returns true if this id has been created and not yet deleted.
inline bool has_sos1_constraint(int64_t id) const;
// Returns true if this id has been created and not yet deleted.
inline bool has_sos1_constraint(Sos1ConstraintId id) const;
// Will CHECK if has_sos1_constraint(id) is false.
inline Sos1Constraint sos1_constraint(int64_t id) const;
// Will CHECK if has_sos1_constraint(id) is false.
inline Sos1Constraint sos1_constraint(Sos1ConstraintId id) const;
// Returns all the existing (created and not deleted) SOS1 constraints in the
// model in an arbitrary order.
inline std::vector<Sos1Constraint> Sos1Constraints() const;
// Returns all the existing (created and not deleted) SOS1 constraints in the
// model sorted by id.
inline std::vector<Sos1Constraint> SortedSos1Constraints() const;
//////////////////////////////////////////////////////////////////////////////
// Sos2Constraint methods
//////////////////////////////////////////////////////////////////////////////
// Adds an SOS2 constraint to the model: at most two of the `expressions` may
// take a nonzero value, and they must be adjacent in their ordering.
//
// The `weights` are an implementation detail in the solver used to order the
// `expressions`; see the Gurobi documentation for more detail:
// https://www.gurobi.com/documentation/9.5/refman/constraints.html#subsubsection:SOSConstraints
// For Xpress see
// https://www.fico.com/fico-xpress-optimization/docs/latest/solver/optimizer/HTML/XPRSaddsets.html
//
// These `weights` must either be empty or the same length as `expressions`.
// If it is empty, default weights of 1, 2, ... will be used.
//
// Usage:
// Model model = ...;
// const Variable x = ...;
// const Variable y = ...;
// model.AddSos2Constraint({x, y}, {}, "c");
// model.AddSos2Constraint({1 - 2 * x, y}, {3, 2});
Sos2Constraint AddSos2Constraint(
const std::vector<LinearExpression>& expressions,
std::vector<double> weights = {}, absl::string_view name = "");
// Removes an SOS2 constraint from the model.
//
// It is an error to use any reference to this SOS2 constraint after this
// operation. Runs in O(#terms in all expressions).
inline void DeleteSos2Constraint(Sos2Constraint constraint);
// The number of SOS2 constraints in the model.
//
// Equal to the number of SOS2 constraints created minus the number of SOS2
// constraints deleted.
inline int64_t num_sos2_constraints() const;
// The returned id of the next call to AddSos2Constraint.
inline int64_t next_sos2_constraint_id() const;
// Returns true if this id has been created and not yet deleted.
inline bool has_sos2_constraint(int64_t id) const;
// Returns true if this id has been created and not yet deleted.
inline bool has_sos2_constraint(Sos2ConstraintId id) const;
// Will CHECK if has_sos2_constraint(id) is false.
inline Sos2Constraint sos2_constraint(int64_t id) const;
// Will CHECK if has_sos2_constraint(id) is false.
inline Sos2Constraint sos2_constraint(Sos2ConstraintId id) const;
// Returns all the existing (created and not deleted) SOS2 constraints in the
// model in an arbitrary order.
inline std::vector<Sos2Constraint> Sos2Constraints() const;
// Returns all the existing (created and not deleted) SOS2 constraints in the
// model sorted by id.
inline std::vector<Sos2Constraint> SortedSos2Constraints() const;
//////////////////////////////////////////////////////////////////////////////
// IndicatorConstraint methods
//////////////////////////////////////////////////////////////////////////////
// Adds an indicator constraint to the model.
//
// Assume for the moment that `activate_on_zero == false` (the default value).
// * If `indicator_variable == 1`, then `implied_constraint` must hold.
// * If `indicator_variable == 0`, then `implied_constraint` need not hold.
// Alternatively, if `activate_on_zero = true`, flip the 1 and 0 above.
//
// The `indicator_variable` is expected to be a binary variable in the model.
// If this is not the case, the solver may elect to either implicitly add the
// binary constraint, or reject the model.
//
// Usage:
// Model model = ...;
// const Variable x = model.AddBinaryVariable("x");
// const Variable y = model.AddBinaryVariable("y");
// model.AddIndicatorConstraint(x, y <= 0);
// model.AddIndicatorConstraint(y, x >= 2, true, "c");
IndicatorConstraint AddIndicatorConstraint(
Variable indicator_variable,
const BoundedLinearExpression& implied_constraint,
bool activate_on_zero = false, absl::string_view name = {});
// Removes an indicator constraint from the model.
//
// It is an error to use any reference to this indicator constraint after this
// operation. Runs in O(#terms in implied constraint).
inline void DeleteIndicatorConstraint(IndicatorConstraint constraint);
// The number of indicator constraints in the model.
//
// Equal to the number of indicator constraints created minus the number of
// indicator constraints deleted.
inline int64_t num_indicator_constraints() const;
// The returned id of the next call to AddIndicatorConstraint.
inline int64_t next_indicator_constraint_id() const;
// Returns true if this id has been created and not yet deleted.
inline bool has_indicator_constraint(int64_t id) const;
// Returns true if this id has been created and not yet deleted.
inline bool has_indicator_constraint(IndicatorConstraintId id) const;
// Will CHECK if has_indicator_constraint(id) is false.
inline IndicatorConstraint indicator_constraint(int64_t id) const;
// Will CHECK if has_indicator_constraint(id) is false.
inline IndicatorConstraint indicator_constraint(
IndicatorConstraintId id) const;
// Returns all the existing (created and not deleted) indicator constraints in
// the model in an arbitrary order.
inline std::vector<IndicatorConstraint> IndicatorConstraints() const;
// Returns all the existing (created and not deleted) indicator constraints in
// the model sorted by id.
inline std::vector<IndicatorConstraint> SortedIndicatorConstraints() const;
//////////////////////////////////////////////////////////////////////////////
// Objective methods
//////////////////////////////////////////////////////////////////////////////
// Sets the objective to maximize the provided expression.
inline void Maximize(double objective);
// Sets the objective to maximize the provided expression.
inline void Maximize(Variable objective);
// Sets the objective to maximize the provided expression.
inline void Maximize(LinearTerm objective);
// Sets the objective to maximize the provided expression.
inline void Maximize(const LinearExpression& objective);
// Sets the objective to maximize the provided expression.
inline void Maximize(const QuadraticExpression& objective);
// Sets the objective to minimize the provided expression.
inline void Minimize(double objective);
// Sets the objective to minimize the provided expression.
inline void Minimize(Variable objective);
// Sets the objective to minimize the provided expression.
inline void Minimize(LinearTerm objective);
// Sets the objective to minimize the provided expression.
inline void Minimize(const LinearExpression& objective);
// Sets the objective to minimize the provided expression.
inline void Minimize(const QuadraticExpression& objective);
// Sets the objective to optimize the provided expression.
inline void SetObjective(double objective, bool is_maximize);
// Sets the objective to optimize the provided expression.
inline void SetObjective(Variable objective, bool is_maximize);
// Sets the objective to optimize the provided expression.
inline void SetObjective(LinearTerm objective, bool is_maximize);
// Sets the objective to optimize the provided expression.
void SetObjective(const LinearExpression& objective, bool is_maximize);
// Sets the objective to optimize the provided expression.
void SetObjective(const QuadraticExpression& objective, bool is_maximize);
// Adds the provided expression terms to the objective.
inline void AddToObjective(double objective);
// Adds the provided expression terms to the objective.
inline void AddToObjective(Variable objective);
// Adds the provided expression terms to the objective.
inline void AddToObjective(LinearTerm objective);
// Adds the provided expression terms to the objective.
void AddToObjective(const LinearExpression& objective);
// Adds the provided expression terms to the objective.
void AddToObjective(const QuadraticExpression& objective);
// NOTE: This will CHECK fail if the objective has quadratic terms.
LinearExpression ObjectiveAsLinearExpression() const;
QuadraticExpression ObjectiveAsQuadraticExpression() const;
// Returns an object referring to the primary objective in the model. Can be
// used with the multi-objective API in the same way that an auxiliary
// objective can be.
inline Objective primary_objective() const;
// Returns 0.0 if this variable has no linear objective coefficient.
inline double objective_coefficient(Variable variable) const;
// Returns 0.0 if this variable pair has no quadratic objective coefficient.
// The order of the variables does not matter.
inline double objective_coefficient(Variable first_variable,
Variable second_variable) const;
// Setting a value to 0.0 will delete the variable from the underlying sparse
// representation (and has no effect if the variable is not present).
inline void set_objective_coefficient(Variable variable, double value);
// Set quadratic objective terms for the product of two variables. Setting a
// value to 0.0 will delete the variable pair from the underlying sparse
// representation (and has no effect if the pair is not present). The order of
// the variables does not matter.
inline void set_objective_coefficient(Variable first_variable,
Variable second_variable, double value);
// Sets the objective offset, linear terms, and quadratic terms of the
// objective to zero. The name, direction, and priority are unchanged.
// Equivalent to SetObjective(0.0, is_maximize()).
//
// Runs in O(#linear and quadratic objective terms with nonzero coefficient).
inline void clear_objective();
inline bool is_objective_coefficient_nonzero(Variable variable) const;
inline bool is_objective_coefficient_nonzero(Variable first_variable,
Variable second_variable) const;
inline double objective_offset() const;
inline void set_objective_offset(double value);
inline bool is_maximize() const;
inline void set_maximize();
inline void set_minimize();
// 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
//
// This is an API for creating and deleting auxiliary objectives. To modify
// them, use the multi-objective API below.
//////////////////////////////////////////////////////////////////////////////
// Adds an empty (== 0) auxiliary minimization objective to the model.
inline Objective AddAuxiliaryObjective(int64_t priority,
absl::string_view name = {});
// Adds `expression` as an auxiliary objective to the model.
inline Objective AddAuxiliaryObjective(const LinearExpression& expression,
bool is_maximize, int64_t priority,
absl::string_view name = {});
// Adds `expression` as an auxiliary maximization objective to the model.
inline Objective AddMaximizationObjective(const LinearExpression& expression,
int64_t priority,
absl::string_view name = {});
// Adds `expression` as an auxiliary minimization objective to the model.
inline Objective AddMinimizationObjective(const LinearExpression& expression,
int64_t priority,
absl::string_view name = {});
// Removes an auxiliary objective from the model.
//
// It is an error to use any reference to this auxiliary objective after this
// operation. Runs in O(1) time.
//
// Will CHECK-fail if `objective` is from another model, has already been
// deleted, or is a primary objective.
inline void DeleteAuxiliaryObjective(Objective objective);
// The number of auxiliary objectives in the model.
//
// Equal to the number of auxiliary objectives created minus the number of
// auxiliary objectives deleted.
inline int64_t num_auxiliary_objectives() const;
// The returned id of the next call to AddAuxiliaryObjectve.
inline int64_t next_auxiliary_objective_id() const;
// Returns true if this id has been created and not yet deleted.
inline bool has_auxiliary_objective(int64_t id) const;
// Returns true if this id has been created and not yet deleted.
inline bool has_auxiliary_objective(AuxiliaryObjectiveId id) const;
// Will CHECK if has_auxiliary_objective(id) is false.
inline Objective auxiliary_objective(int64_t id) const;
// Will CHECK if has_auxiliary_objective(id) is false.
inline Objective auxiliary_objective(AuxiliaryObjectiveId id) const;
// Returns all the existing (created and not deleted) auxiliary objectives in
// the model in an arbitrary order.
std::vector<Objective> AuxiliaryObjectives() const;
// Returns all the existing (created and not deleted) auxiliary objectives in
// the model sorted by id.
std::vector<Objective> SortedAuxiliaryObjectives() const;
//////////////////////////////////////////////////////////////////////////////
// Multi-objective methods
//
// This is an API for setting objective properties (for either primary or
// auxiliary objectives). Only linear objectives are supported through this
// API. To query objective properties, use the methods on `Objective`.
//////////////////////////////////////////////////////////////////////////////
// Sets `objective` to be maximizing `expression`.
inline void Maximize(Objective objective, const LinearExpression& expression);
// Sets `objective` to be minimizing `expression`.
inline void Minimize(Objective objective, const LinearExpression& expression);
// Sets the objective to optimize the provided expression.
void SetObjective(Objective objective, const LinearExpression& expression,
bool is_maximize);
// Adds the provided expression terms to the objective.
void AddToObjective(Objective objective, const LinearExpression& expression);
// Sets the priority for an objective (lower is more important). `priority`
// must be nonnegative.
inline void set_objective_priority(Objective objective, int64_t priority);
// Setting a value to 0.0 will delete the variable from the underlying sparse
// representation (and has no effect if the variable is not present).
inline void set_objective_coefficient(Objective objective, Variable variable,
double value);
inline void set_objective_offset(Objective objective, double value);
inline void set_maximize(Objective objective);
inline void set_minimize(Objective objective);
// 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.
ModelProto ExportModel(bool remove_names = false) const;
// Returns a tracker that can be used to generate a ModelUpdateProto with the
// updates that happened since the last checkpoint. The tracker initial
// checkpoint corresponds to the current state of the model.
//
// The returned UpdateTracker keeps a reference to this model. See the
// implications in the documentation of the UpdateTracker class.
//
// Thread-safety: this method must not be used while modifying the model
// (variables, constraints, ...). The user is expected to use proper
// synchronization primitive to serialize changes to the model and the use of
// this method.
std::unique_ptr<UpdateTracker> NewUpdateTracker();
// Apply the provided update to this model. Returns a failure if the update is
// not valid.
//
// As with FromModelProto(), duplicated names are ignored.
//
// Note that it takes O(num_variables + num_constraints) extra memory and
// execution to apply the update (due to the need to build a ModelSummary). So
// even a small update will have some cost.
absl::Status ApplyUpdateProto(const ModelUpdateProto& update_proto);
// TODO(user): expose a way to efficiently iterate through the nonzeros of
// the linear constraint matrix.
// Returns a pointer to the underlying model storage.
//
// This API is for internal use only and regular users should have no need for
// it.
ModelStorageCPtr storage() const { return storage_.get(); }
// Returns a pointer to the underlying model storage.
//
// This API is for internal use only and regular users should have no need for
// it.
ModelStoragePtr 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_.
//
// Use CheckModel() when nullptr is not a valid value.
inline void CheckOptionalModel(NullableModelStorageCPtr other_storage) const;
// Asserts (with CHECK) that the input pointer is the same as storage_.
//
// Use CheckOptionalModel() if nullptr is a valid value too.
inline void CheckModel(ModelStorageCPtr other_storage) const;
// Don't use storage_ directly; prefer to use storage() so that const member
// functions don't have modifying access to the underlying storage.
//
// We use a shared_ptr here so that the UpdateTracker class can have a
// weak_ptr on the ModelStorage. This let it have a destructor that don't
// crash when called after the destruction of the associated Model.
const absl_nonnull std::shared_ptr<ModelStorage> storage_;
};
////////////////////////////////////////////////////////////////////////////////
// Inline function implementations
////////////////////////////////////////////////////////////////////////////////
// ------------------------------- Variables -----------------------------------
absl::string_view Model::name() const { return storage()->name(); }
Variable Model::AddVariable(const absl::string_view name) {
return Variable(storage(), storage()->AddVariable(name));
}
Variable Model::AddVariable(const double lower_bound, const double upper_bound,
const bool is_integer,
const absl::string_view name) {
return Variable(storage(), storage()->AddVariable(lower_bound, upper_bound,
is_integer, name));
}
Variable Model::AddBinaryVariable(const absl::string_view name) {
return AddVariable(0.0, 1.0, true, name);
}
Variable Model::AddContinuousVariable(const double lower_bound,
const double upper_bound,
const absl::string_view name) {
return AddVariable(lower_bound, upper_bound, false, name);
}
Variable Model::AddIntegerVariable(const double lower_bound,
const double upper_bound,
const absl::string_view name) {
return AddVariable(lower_bound, upper_bound, true, name);
}
void Model::DeleteVariable(const Variable variable) {
CheckModel(variable.storage());
storage()->DeleteVariable(variable.typed_id());
}
int Model::num_variables() const { return storage()->num_variables(); }
int64_t Model::next_variable_id() const {
return storage()->next_variable_id().value();
}
bool Model::has_variable(const int64_t id) const {
return id < 0 ? false : has_variable(VariableId(id));
}
bool Model::has_variable(const VariableId id) const {
return storage()->has_variable(id);
}
Variable Model::variable(const int64_t id) const {
return variable(VariableId(id));
}
Variable Model::variable(const VariableId id) const {
CHECK(has_variable(id)) << "No variable with id: " << id.value();
return Variable(storage(), id);
}
absl::string_view Model::name(const Variable variable) const {
CheckModel(variable.storage());
return storage()->variable_name(variable.typed_id());
}
void Model::set_lower_bound(const Variable variable, double lower_bound) {
CheckModel(variable.storage());
storage()->set_variable_lower_bound(variable.typed_id(), lower_bound);
}
double Model::lower_bound(const Variable variable) const {
CheckModel(variable.storage());
return storage()->variable_lower_bound(variable.typed_id());
}
void Model::set_upper_bound(const Variable variable, double upper_bound) {
CheckModel(variable.storage());
storage()->set_variable_upper_bound(variable.typed_id(), upper_bound);
}
double Model::upper_bound(const Variable variable) const {
CheckModel(variable.storage());
return storage()->variable_upper_bound(variable.typed_id());
}
void Model::set_is_integer(const Variable variable, bool is_integer) {
CheckModel(variable.storage());
storage()->set_variable_is_integer(variable.typed_id(), is_integer);
}
void Model::set_integer(const Variable variable) {
set_is_integer(variable, true);
}
void Model::set_continuous(const Variable variable) {
set_is_integer(variable, false);
}
bool Model::is_integer(const Variable variable) const {
CheckModel(variable.storage());
return storage()->is_variable_integer(variable.typed_id());
}
// -------------------------- Linear constraints -------------------------------
absl::Status Model::ValidateExistingVariableOfThisModel(
Variable variable) const {
// TODO(b/239810718): use << for Variable once it does not CHECK.
if (storage_.get() != variable.storage()) {
return util::InvalidArgumentErrorBuilder()
<< "variable with id " << variable.id()
<< " is from a different model";
}
if (!has_variable(variable.typed_id())) {
return util::InvalidArgumentErrorBuilder()
<< "variable with id " << variable.id()
<< " is not found in this model (it was probably deleted)";
}
return absl::OkStatus();
}
LinearConstraint Model::AddLinearConstraint(const absl::string_view name) {
return LinearConstraint(storage(), storage()->AddLinearConstraint(name));
}
LinearConstraint Model::AddLinearConstraint(const double lower_bound,
const double upper_bound,
const absl::string_view name) {
return LinearConstraint(storage(), storage()->AddLinearConstraint(
lower_bound, upper_bound, name));
}
void Model::DeleteLinearConstraint(const LinearConstraint constraint) {
CheckModel(constraint.storage());
storage()->DeleteLinearConstraint(constraint.typed_id());
}
int Model::num_linear_constraints() const {
return storage()->num_linear_constraints();
}
int64_t Model::next_linear_constraint_id() const {
return storage()->next_linear_constraint_id().value();
}
bool Model::has_linear_constraint(const int64_t id) const {
return id < 0 ? false : has_linear_constraint(LinearConstraintId(id));
}
bool Model::has_linear_constraint(const LinearConstraintId id) const {
return storage()->has_linear_constraint(id);
}
LinearConstraint Model::linear_constraint(const int64_t id) const {
CHECK_GE(id, 0) << "negative linear constraint id: " << id;
return linear_constraint(LinearConstraintId(id));
}
LinearConstraint Model::linear_constraint(const LinearConstraintId id) const {
CHECK(has_linear_constraint(id))
<< "No linear constraint with id: " << id.value();
return LinearConstraint(storage(), id);
}
absl::string_view Model::name(const LinearConstraint constraint) const {
CheckModel(constraint.storage());
return storage()->linear_constraint_name(constraint.typed_id());
}
void Model::set_lower_bound(const LinearConstraint constraint,
double lower_bound) {
CheckModel(constraint.storage());
storage()->set_linear_constraint_lower_bound(constraint.typed_id(),
lower_bound);
}
double Model::lower_bound(const LinearConstraint constraint) const {
CheckModel(constraint.storage());
return storage()->linear_constraint_lower_bound(constraint.typed_id());
}
void Model::set_upper_bound(const LinearConstraint constraint,
const double upper_bound) {
CheckModel(constraint.storage());
storage()->set_linear_constraint_upper_bound(constraint.typed_id(),
upper_bound);
}
double Model::upper_bound(const LinearConstraint constraint) const {
CheckModel(constraint.storage());
return storage()->linear_constraint_upper_bound(constraint.typed_id());
}
absl::Status Model::ValidateExistingLinearConstraintOfThisModel(
LinearConstraint linear_constraint) const {
// TODO(b/239810718): use << for LinearConstraint once it does not CHECK.
if (storage_.get() != linear_constraint.storage()) {
return util::InvalidArgumentErrorBuilder()
<< "linear constraint with id " << linear_constraint.id()
<< " is from a different model";
}
if (!has_linear_constraint(linear_constraint.typed_id())) {
return util::InvalidArgumentErrorBuilder()
<< "linear constraint with id " << linear_constraint.id()
<< " is not found in this model (it was probably deleted)";
}
return absl::OkStatus();
}
void Model::set_coefficient(const LinearConstraint constraint,
const Variable variable, const double value) {
CheckModel(constraint.storage());
CheckModel(variable.storage());
storage()->set_linear_constraint_coefficient(constraint.typed_id(),
variable.typed_id(), value);
}
double Model::coefficient(const LinearConstraint constraint,
const Variable variable) const {
CheckModel(constraint.storage());
CheckModel(variable.storage());
return storage()->linear_constraint_coefficient(constraint.typed_id(),
variable.typed_id());
}
bool Model::is_coefficient_nonzero(const LinearConstraint constraint,
const Variable variable) const {
CheckModel(constraint.storage());
CheckModel(variable.storage());
return storage()->is_linear_constraint_coefficient_nonzero(
constraint.typed_id(), variable.typed_id());
}
// ------------------------- Quadratic constraints -----------------------------
void Model::DeleteQuadraticConstraint(const QuadraticConstraint constraint) {
CheckModel(constraint.storage());
storage()->DeleteAtomicConstraint(constraint.typed_id());
}
int64_t Model::num_quadratic_constraints() const {
return storage()->num_constraints<QuadraticConstraintId>();
}
int64_t Model::next_quadratic_constraint_id() const {
return storage()->next_constraint_id<QuadraticConstraintId>().value();
}
bool Model::has_quadratic_constraint(const int64_t id) const {
return id < 0 ? false : has_quadratic_constraint(QuadraticConstraintId(id));
}
bool Model::has_quadratic_constraint(const QuadraticConstraintId id) const {
return storage()->has_constraint(id);
}
QuadraticConstraint Model::quadratic_constraint(const int64_t id) const {
CHECK_GE(id, 0) << "negative quadratic constraint id: " << id;
return quadratic_constraint(QuadraticConstraintId(id));
}
QuadraticConstraint Model::quadratic_constraint(
const QuadraticConstraintId id) const {
CHECK(has_quadratic_constraint(id))
<< "No quadratic constraint with id: " << id.value();
return QuadraticConstraint(storage(), id);
}
std::vector<QuadraticConstraint> Model::QuadraticConstraints() const {
return AtomicConstraints<QuadraticConstraint>(*storage());
}
std::vector<QuadraticConstraint> Model::SortedQuadraticConstraints() const {
return SortedAtomicConstraints<QuadraticConstraint>(*storage());
}
// --------------------- Second-order cone constraints -------------------------
void Model::DeleteSecondOrderConeConstraint(
const SecondOrderConeConstraint constraint) {
CheckModel(constraint.storage());
storage()->DeleteAtomicConstraint(constraint.typed_id());
}
int64_t Model::num_second_order_cone_constraints() const {
return storage()->num_constraints<SecondOrderConeConstraintId>();
}
int64_t Model::next_second_order_cone_constraint_id() const {
return storage()->next_constraint_id<SecondOrderConeConstraintId>().value();
}
bool Model::has_second_order_cone_constraint(const int64_t id) const {
return id < 0 ? false
: has_second_order_cone_constraint(
SecondOrderConeConstraintId(id));
}
bool Model::has_second_order_cone_constraint(
const SecondOrderConeConstraintId id) const {
return storage()->has_constraint(id);
}
SecondOrderConeConstraint Model::second_order_cone_constraint(
const int64_t id) const {
return second_order_cone_constraint(SecondOrderConeConstraintId(id));
}
SecondOrderConeConstraint Model::second_order_cone_constraint(
const SecondOrderConeConstraintId id) const {
CHECK(has_second_order_cone_constraint(id))
<< "No second-order cone constraint with id: " << id.value();
return SecondOrderConeConstraint(storage(), id);
}
std::vector<SecondOrderConeConstraint> Model::SecondOrderConeConstraints()
const {
return AtomicConstraints<SecondOrderConeConstraint>(*storage());
}
std::vector<SecondOrderConeConstraint> Model::SortedSecondOrderConeConstraints()
const {
return SortedAtomicConstraints<SecondOrderConeConstraint>(*storage());
}
// --------------------------- SOS1 constraints --------------------------------
void Model::DeleteSos1Constraint(const Sos1Constraint constraint) {
CheckModel(constraint.storage());
storage()->DeleteAtomicConstraint(constraint.typed_id());
}
int64_t Model::num_sos1_constraints() const {
return storage()->num_constraints<Sos1ConstraintId>();
}
int64_t Model::next_sos1_constraint_id() const {
return storage()->next_constraint_id<Sos1ConstraintId>().value();
}
bool Model::has_sos1_constraint(const int64_t id) const {
return id < 0 ? false : has_sos1_constraint(Sos1ConstraintId(id));
}
bool Model::has_sos1_constraint(const Sos1ConstraintId id) const {
return storage()->has_constraint(id);
}
Sos1Constraint Model::sos1_constraint(const int64_t id) const {
return sos1_constraint(Sos1ConstraintId(id));
}
Sos1Constraint Model::sos1_constraint(const Sos1ConstraintId id) const {
CHECK(has_sos1_constraint(id))
<< "No SOS1 constraint with id: " << id.value();
return Sos1Constraint(storage(), id);
}
std::vector<Sos1Constraint> Model::Sos1Constraints() const {
return AtomicConstraints<Sos1Constraint>(*storage());
}
std::vector<Sos1Constraint> Model::SortedSos1Constraints() const {
return SortedAtomicConstraints<Sos1Constraint>(*storage());
}
// --------------------------- SOS2 constraints --------------------------------
void Model::DeleteSos2Constraint(const Sos2Constraint constraint) {
CheckModel(constraint.storage());
storage()->DeleteAtomicConstraint(constraint.typed_id());
}
int64_t Model::num_sos2_constraints() const {
return storage()->num_constraints<Sos2ConstraintId>();
}
int64_t Model::next_sos2_constraint_id() const {
return storage()->next_constraint_id<Sos2ConstraintId>().value();
}
bool Model::has_sos2_constraint(const int64_t id) const {
return id < 0 ? false : has_sos2_constraint(Sos2ConstraintId(id));
}
bool Model::has_sos2_constraint(const Sos2ConstraintId id) const {
return storage()->has_constraint(id);
}
Sos2Constraint Model::sos2_constraint(const int64_t id) const {
return sos2_constraint(Sos2ConstraintId(id));
}
Sos2Constraint Model::sos2_constraint(const Sos2ConstraintId id) const {
CHECK(has_sos2_constraint(id))
<< "No SOS2 constraint with id: " << id.value();
return Sos2Constraint(storage(), id);
}
std::vector<Sos2Constraint> Model::Sos2Constraints() const {
return AtomicConstraints<Sos2Constraint>(*storage());
}
std::vector<Sos2Constraint> Model::SortedSos2Constraints() const {
return SortedAtomicConstraints<Sos2Constraint>(*storage());
}
// --------------------------- Indicator constraints ---------------------------
void Model::DeleteIndicatorConstraint(const IndicatorConstraint constraint) {
CheckModel(constraint.storage());
storage()->DeleteAtomicConstraint(constraint.typed_id());
}
int64_t Model::num_indicator_constraints() const {
return storage()->num_constraints<IndicatorConstraintId>();
}
int64_t Model::next_indicator_constraint_id() const {
return storage()->next_constraint_id<IndicatorConstraintId>().value();
}
bool Model::has_indicator_constraint(const int64_t id) const {
return id < 0 ? false : has_indicator_constraint(IndicatorConstraintId(id));
}
bool Model::has_indicator_constraint(const IndicatorConstraintId id) const {
return storage()->has_constraint(id);
}
IndicatorConstraint Model::indicator_constraint(const int64_t id) const {
return indicator_constraint(IndicatorConstraintId(id));
}
IndicatorConstraint Model::indicator_constraint(
const IndicatorConstraintId id) const {
CHECK(has_indicator_constraint(id))
<< "No indicator constraint with id: " << id.value();
return IndicatorConstraint(storage(), id);
}
std::vector<IndicatorConstraint> Model::IndicatorConstraints() const {
return AtomicConstraints<IndicatorConstraint>(*storage());
}
std::vector<IndicatorConstraint> Model::SortedIndicatorConstraints() const {
return SortedAtomicConstraints<IndicatorConstraint>(*storage());
}
// ------------------------------- Objective -----------------------------------
void Model::Maximize(const double objective) {
SetObjective(LinearExpression(objective), /*is_maximize=*/true);
}
void Model::Maximize(const Variable objective) {
SetObjective(LinearExpression(objective), /*is_maximize=*/true);
}
void Model::Maximize(const LinearTerm objective) {
SetObjective(LinearExpression(objective), /*is_maximize=*/true);
}
void Model::Maximize(const LinearExpression& objective) {
SetObjective(objective, /*is_maximize=*/true);
}
void Model::Maximize(const QuadraticExpression& objective) {
SetObjective(objective, /*is_maximize=*/true);
}
void Model::Minimize(const double objective) {
SetObjective(LinearExpression(objective), /*is_maximize=*/false);
}
void Model::Minimize(const Variable objective) {
SetObjective(LinearExpression(objective), /*is_maximize=*/false);
}
void Model::Minimize(const LinearTerm objective) {
SetObjective(LinearExpression(objective), /*is_maximize=*/false);
}
void Model::Minimize(const LinearExpression& objective) {
SetObjective(objective, /*is_maximize=*/false);
}
void Model::Minimize(const QuadraticExpression& objective) {
SetObjective(objective, /*is_maximize=*/false);
}
void Model::SetObjective(const double objective, const bool is_maximize) {
SetObjective(LinearExpression(objective), /*is_maximize=*/is_maximize);
}
void Model::SetObjective(const Variable objective, const bool is_maximize) {
SetObjective(LinearExpression(objective), /*is_maximize=*/is_maximize);
}
void Model::SetObjective(const LinearTerm objective, const bool is_maximize) {
SetObjective(LinearExpression(objective), /*is_maximize=*/is_maximize);
}
void Model::AddToObjective(const double objective) {
AddToObjective(LinearExpression(objective));
}
void Model::AddToObjective(const Variable objective) {
AddToObjective(LinearExpression(objective));
}
void Model::AddToObjective(const LinearTerm objective) {
AddToObjective(LinearExpression(objective));
}
Objective Model::primary_objective() const {
return Objective::Primary(storage());
}
double Model::objective_coefficient(const Variable variable) const {
CheckModel(variable.storage());
return storage()->linear_objective_coefficient(kPrimaryObjectiveId,
variable.typed_id());
}
double Model::objective_coefficient(const Variable first_variable,
const Variable second_variable) const {
CheckModel(first_variable.storage());
CheckModel(second_variable.storage());
return storage()->quadratic_objective_coefficient(kPrimaryObjectiveId,
first_variable.typed_id(),
second_variable.typed_id());
}
void Model::set_objective_coefficient(const Variable variable,
const double value) {
CheckModel(variable.storage());
storage()->set_linear_objective_coefficient(kPrimaryObjectiveId,
variable.typed_id(), value);
}
void Model::set_objective_coefficient(const Variable first_variable,
const Variable second_variable,
const double value) {
CheckModel(first_variable.storage());
CheckModel(second_variable.storage());
storage()->set_quadratic_objective_coefficient(
kPrimaryObjectiveId, first_variable.typed_id(),
second_variable.typed_id(), value);
}
void Model::clear_objective() {
storage()->clear_objective(kPrimaryObjectiveId);
}
bool Model::is_objective_coefficient_nonzero(const Variable variable) const {
CheckModel(variable.storage());
return storage()->is_linear_objective_coefficient_nonzero(
kPrimaryObjectiveId, variable.typed_id());
}
bool Model::is_objective_coefficient_nonzero(
const Variable first_variable, const Variable second_variable) const {
CheckModel(first_variable.storage());
CheckModel(second_variable.storage());
return storage()->is_quadratic_objective_coefficient_nonzero(
kPrimaryObjectiveId, first_variable.typed_id(),
second_variable.typed_id());
}
double Model::objective_offset() const {
return storage()->objective_offset(kPrimaryObjectiveId);
}
void Model::set_objective_offset(const double value) {
storage()->set_objective_offset(kPrimaryObjectiveId, value);
}
bool Model::is_maximize() const {
return storage()->is_maximize(kPrimaryObjectiveId);
}
void Model::set_maximize() { storage()->set_maximize(kPrimaryObjectiveId); }
void Model::set_minimize() { storage()->set_minimize(kPrimaryObjectiveId); }
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,
const absl::string_view name) {
return Objective::Auxiliary(storage(),
storage()->AddAuxiliaryObjective(priority, name));
}
Objective Model::AddAuxiliaryObjective(const LinearExpression& expression,
const bool is_maximize,
const int64_t priority,
const absl::string_view name) {
const Objective obj = AddAuxiliaryObjective(priority, name);
SetObjective(obj, expression, is_maximize);
return obj;
}
Objective Model::AddMaximizationObjective(const LinearExpression& expression,
const int64_t priority,
const absl::string_view name) {
return AddAuxiliaryObjective(expression, /*is_maximize=*/true, priority,
name);
}
Objective Model::AddMinimizationObjective(const LinearExpression& expression,
const int64_t priority,
const absl::string_view name) {
return AddAuxiliaryObjective(expression, /*is_maximize=*/false, priority,
name);
}
void Model::DeleteAuxiliaryObjective(const Objective objective) {
CheckModel(objective.storage());
CHECK(!objective.is_primary()) << "cannot delete primary objective";
const AuxiliaryObjectiveId id = *objective.typed_id();
CHECK(storage()->has_auxiliary_objective(id))
<< "cannot delete unrecognized auxiliary objective id: " << id;
storage()->DeleteAuxiliaryObjective(id);
}
int64_t Model::num_auxiliary_objectives() const {
return storage()->num_auxiliary_objectives();
}
int64_t Model::next_auxiliary_objective_id() const {
return storage()->next_auxiliary_objective_id().value();
}
bool Model::has_auxiliary_objective(const int64_t id) const {
return id < 0 ? false : has_auxiliary_objective(AuxiliaryObjectiveId(id));
}
bool Model::has_auxiliary_objective(const AuxiliaryObjectiveId id) const {
return storage()->has_auxiliary_objective(id);
}
Objective Model::auxiliary_objective(const int64_t id) const {
CHECK_GE(id, 0) << "negative auxiliary objective id: " << id;
return auxiliary_objective(AuxiliaryObjectiveId(id));
}
Objective Model::auxiliary_objective(const AuxiliaryObjectiveId id) const {
CHECK(has_auxiliary_objective(id))
<< "unrecognized auxiliary objective id: " << id;
return Objective::Auxiliary(storage(), id);
}
// ---------------------------- Multi-objective --------------------------------
void Model::Maximize(const Objective objective,
const LinearExpression& expression) {
SetObjective(objective, expression, /*is_maximize=*/true);
}
void Model::Minimize(const Objective objective,
const LinearExpression& expression) {
SetObjective(objective, expression, /*is_maximize=*/false);
}
void Model::set_objective_priority(const Objective objective,
const int64_t priority) {
CheckModel(objective.storage());
storage()->set_objective_priority(objective.typed_id(), priority);
}
void Model::set_objective_coefficient(const Objective objective,
const Variable variable,
const double value) {
CheckModel(objective.storage());
CheckModel(variable.storage());
storage()->set_linear_objective_coefficient(objective.typed_id(),
variable.typed_id(), value);
}
void Model::set_objective_offset(const Objective objective,
const double value) {
CheckModel(objective.storage());
storage()->set_objective_offset(objective.typed_id(), value);
}
void Model::set_maximize(const Objective objective) {
set_is_maximize(objective, /*is_maximize=*/true);
}
void Model::set_minimize(const Objective objective) {
set_is_maximize(objective, /*is_maximize=*/false);
}
void Model::set_is_maximize(const Objective objective, const bool is_maximize) {
CheckModel(objective.storage());
storage()->set_is_maximize(objective.typed_id(), is_maximize);
}
void Model::CheckOptionalModel(
const NullableModelStorageCPtr other_storage) const {
if (other_storage != nullptr) {
CHECK_EQ(other_storage, storage())
<< internal::kObjectsFromOtherModelStorage;
}
}
void Model::CheckModel(const ModelStorageCPtr other_storage) const {
CHECK_EQ(other_storage, storage()) << internal::kObjectsFromOtherModelStorage;
}
} // namespace math_opt
} // namespace operations_research
#endif // ORTOOLS_MATH_OPT_CPP_MODEL_H_