22 #include "absl/container/flat_hash_map.h"
23 #include "absl/status/status.h"
24 #include "absl/status/statusor.h"
30 #include "ortools/math_opt/model.pb.h"
31 #include "ortools/math_opt/sparse_containers.pb.h"
39 absl::Status IsSupported(
const MPModelProto&
model) {
41 if (validity_string.length() > 0) {
42 return absl::InvalidArgumentError(validity_string);
44 if (
model.general_constraint_size() > 0) {
45 return absl::InvalidArgumentError(
"General constraints are not supported");
47 if (
model.quadratic_objective().coefficient_size() > 0) {
48 return absl::InvalidArgumentError(
"Quadratic objectives not supported");
50 if (
model.solution_hint().var_index_size() > 0) {
51 return absl::InvalidArgumentError(
"Solution Hint not supported");
53 return absl::OkStatus();
56 absl::Status IsSupported(
const math_opt::ModelProto&
model) {
60 bool AnyVarNamed(
const MPModelProto&
model) {
61 for (
const MPVariableProto&
var :
model.variable()) {
62 if (
var.name().length() > 0) {
69 bool AnyConstraintNamed(
const MPModelProto&
model) {
70 for (
const MPConstraintProto& constraint :
model.constraint()) {
71 if (constraint.name().length() > 0) {
80 absl::StatusOr<::operations_research::math_opt::ModelProto>
85 output.set_name(
model.name());
87 math_opt::VariablesProto*
const vars = output.mutable_variables();
88 int objective_non_zeros = 0;
89 const int num_vars =
model.variable_size();
90 const bool vars_have_name = AnyVarNamed(
model);
91 vars->mutable_lower_bounds()->Reserve(num_vars);
92 vars->mutable_upper_bounds()->Reserve(num_vars);
93 vars->mutable_integers()->Reserve(num_vars);
95 vars->mutable_names()->Reserve(num_vars);
97 for (
int i = 0; i <
model.variable_size(); ++i) {
98 const MPVariableProto&
var =
model.variable(i);
99 if (
var.objective_coefficient() != 0.0) {
100 ++objective_non_zeros;
103 vars->add_lower_bounds(
var.lower_bound());
104 vars->add_upper_bounds(
var.upper_bound());
105 vars->add_integers(
var.is_integer());
106 if (vars_have_name) {
107 vars->add_names(
var.name());
111 math_opt::ObjectiveProto*
const objective = output.mutable_objective();
112 if (objective_non_zeros > 0) {
113 objective->mutable_linear_coefficients()->mutable_ids()->Reserve(
114 objective_non_zeros);
115 objective->mutable_linear_coefficients()->mutable_values()->Reserve(
116 objective_non_zeros);
117 for (
int j = 0; j < num_vars; ++j) {
118 const double value =
model.variable(j).objective_coefficient();
119 if (
value == 0.0)
continue;
120 objective->mutable_linear_coefficients()->add_ids(j);
121 objective->mutable_linear_coefficients()->add_values(
value);
124 objective->set_maximize(
model.maximize());
125 objective->set_offset(
model.objective_offset());
127 math_opt::LinearConstraintsProto*
const constraints =
128 output.mutable_linear_constraints();
129 const int num_constraints =
model.constraint_size();
130 const bool constraints_have_name = AnyConstraintNamed(
model);
131 int num_non_zeros = 0;
132 constraints->mutable_lower_bounds()->Reserve(num_constraints);
133 constraints->mutable_upper_bounds()->Reserve(num_constraints);
134 if (constraints_have_name) {
135 constraints->mutable_names()->Reserve(num_constraints);
137 for (
int i = 0; i < num_constraints; ++i) {
138 const MPConstraintProto& constraint =
model.constraint(i);
139 constraints->add_ids(i);
140 constraints->add_lower_bounds(constraint.lower_bound());
141 constraints->add_upper_bounds(constraint.upper_bound());
142 if (constraints_have_name) {
143 constraints->add_names(constraint.name());
145 num_non_zeros += constraint.var_index_size();
148 SparseDoubleMatrixProto*
const matrix =
149 output.mutable_linear_constraint_matrix();
150 matrix->mutable_column_ids()->Reserve(num_non_zeros);
151 matrix->mutable_row_ids()->Reserve(num_non_zeros);
152 matrix->mutable_coefficients()->Reserve(num_non_zeros);
154 std::vector<std::pair<int, double>> terms_in_order;
155 for (
int i = 0; i < num_constraints; ++i) {
156 const MPConstraintProto& constraint =
model.constraint(i);
157 const int constraint_non_zeros = constraint.var_index_size();
158 for (
int k = 0; k < constraint_non_zeros; ++k) {
159 const double coefficient = constraint.coefficient(k);
163 terms_in_order.emplace_back(constraint.var_index(k),
coefficient);
165 std::sort(terms_in_order.begin(), terms_in_order.end());
166 for (
const auto& term : terms_in_order) {
167 matrix->add_column_ids(i);
168 matrix->add_row_ids(term.first);
169 matrix->add_coefficients(term.second);
171 terms_in_order.clear();
177 const ::operations_research::math_opt::ModelProto&
model) {
180 const bool vars_have_name =
model.variables().names_size() > 0;
181 const bool constraints_have_name =
182 model.linear_constraints().names_size() > 0;
183 absl::flat_hash_map<int64_t, int> variable_id_to_mp_position;
184 absl::flat_hash_map<int64_t, MPConstraintProto*>
185 constraint_id_to_mp_constraint;
188 output.set_name(
model.name());
191 output.mutable_variable()->Reserve(num_vars);
192 for (
int j = 0; j < num_vars; ++j) {
193 MPVariableProto*
const variable = output.add_variable();
194 variable_id_to_mp_position.emplace(
model.variables().ids(j), j);
195 variable->set_lower_bound(
model.variables().lower_bounds(j));
196 variable->set_upper_bound(
model.variables().upper_bounds(j));
197 variable->set_is_integer(
model.variables().integers(j));
198 if (vars_have_name) {
199 variable->set_name(
model.variables().names(j));
204 output.mutable_constraint()->Reserve(num_constraints);
205 for (
int i = 0; i < num_constraints; ++i) {
206 MPConstraintProto*
const constraint = output.add_constraint();
207 constraint_id_to_mp_constraint.emplace(
model.linear_constraints().ids(i),
209 constraint->set_lower_bound(
model.linear_constraints().lower_bounds(i));
210 constraint->set_upper_bound(
model.linear_constraints().upper_bounds(i));
211 if (constraints_have_name) {
212 constraint->set_name(
model.linear_constraints().names(i));
216 output.set_maximize(
model.objective().maximize());
217 output.set_objective_offset(
model.objective().offset());
220 const int var_position = variable_id_to_mp_position[
var];
221 MPVariableProto*
const variable = output.mutable_variable(var_position);
222 variable->set_objective_coefficient(
coef);
226 const int constraint_non_zeros =
227 model.linear_constraint_matrix().coefficients_size();
228 for (
int k = 0; k < constraint_non_zeros; ++k) {
229 const int64_t constraint_id =
model.linear_constraint_matrix().row_ids(k);
230 MPConstraintProto*
const constraint =
231 constraint_id_to_mp_constraint[constraint_id];
232 const int64_t variable_id =
model.linear_constraint_matrix().column_ids(k);
233 const int variable_position = variable_id_to_mp_position[variable_id];
234 constraint->add_var_index(variable_position);
235 const double value =
model.linear_constraint_matrix().coefficients(k);
236 constraint->add_coefficient(
value);
int NumVariables(const VariablesProto &variables)
absl::StatusOr<::operations_research::MPModelProto > MathOptModelToMPModelProto(const ::operations_research::math_opt::ModelProto &model)
int NumConstraints(const LinearConstraintsProto &linear_constraints)
absl::StatusOr<::operations_research::math_opt::ModelProto > MPModelProtoToMathOptModel(const ::operations_research::MPModelProto &model)
SparseVectorView< T > MakeView(absl::Span< const int64_t > ids, const Collection &values)
absl::Status ValidateModel(const ModelProto &model, const bool check_names)
Collection of objects used to extend the Constraint Solver library.
std::string FindErrorInMPModelProto(const MPModelProto &model, double abs_value_threshold)
Returns an empty string iff the model is valid and not trivially infeasible.
#define RETURN_IF_ERROR(expr)