21#include "absl/strings/str_cat.h"
23#include "Eigen/SparseCore"
24#include "pybind11/eigen.h"
25#include "pybind11/pybind11.h"
26#include "pybind11/pytypes.h"
27#include "ortools/linear_solver/linear_solver.pb.h"
31using ::Eigen::SparseMatrix;
32using ::Eigen::VectorXd;
33using ::operations_research::ModelBuilderHelper;
34using ::operations_research::ModelSolverHelper;
35using ::operations_research::MPConstraintProto;
36using ::operations_research::MPModelExportOptions;
37using ::operations_research::MPModelProto;
38using ::operations_research::MPVariableProto;
49 const Eigen::Ref<const VectorXd>& objective_coefficients,
50 const Eigen::Ref<const VectorXd>& constraint_lower_bounds,
51 const Eigen::Ref<const VectorXd>& constraint_upper_bounds,
52 const SparseMatrix<double, Eigen::RowMajor>& constraint_matrix) {
54 const int num_constraints = constraint_lower_bounds.size();
57 throw std::invalid_argument(
59 " for variable_upper_bounds. Expected: ", num_variables));
61 if (objective_coefficients.size() != num_variables) {
62 throw std::invalid_argument(absl::StrCat(
63 "Invalid size ", objective_coefficients.size(),
64 " for linear_objective_coefficients. Expected: ", num_variables));
66 if (constraint_upper_bounds.size() != num_constraints) {
67 throw std::invalid_argument(absl::StrCat(
68 "Invalid size ", constraint_upper_bounds.size(),
69 " for constraint_upper_bounds. Expected: ", num_constraints));
71 if (constraint_matrix.cols() != num_variables) {
72 throw std::invalid_argument(
73 absl::StrCat(
"Invalid number of columns ", constraint_matrix.cols(),
74 " in constraint_matrix. Expected: ", num_variables));
76 if (constraint_matrix.rows() != num_constraints) {
77 throw std::invalid_argument(
78 absl::StrCat(
"Invalid number of rows ", constraint_matrix.rows(),
79 " in constraint_matrix. Expected: ", num_constraints));
83 for (
int i = 0; i < num_variables; ++i) {
84 MPVariableProto* variable =
model.add_variable();
87 variable->set_objective_coefficient(objective_coefficients[i]);
90 for (
int row = 0;
row < num_constraints; ++
row) {
91 MPConstraintProto* constraint =
model.add_constraint();
92 constraint->set_lower_bound(constraint_lower_bounds[
row]);
93 constraint->set_upper_bound(constraint_upper_bounds[
row]);
94 for (SparseMatrix<double, Eigen::RowMajor>::InnerIterator it(
95 constraint_matrix,
row);
97 constraint->add_coefficient(it.value());
98 constraint->add_var_index(it.col());
102 return model.SerializeAsString();
106 m.def(
"BuildModel",
BuildModel, arg(
"variable_lower_bounds"),
107 arg(
"variable_upper_bounds"), arg(
"objective_coefficients"),
108 arg(
"constraint_lower_bounds"), arg(
"constraint_upper_bounds"),
109 arg(
"constraint_matrix"));
111 pybind11::class_<MPModelExportOptions>(m,
"MPModelExportOptions")
112 .def(pybind11::init<>())
113 .def_readwrite(
"obfuscate", &MPModelExportOptions::obfuscate)
114 .def_readwrite(
"log_invalid_names",
115 &MPModelExportOptions::log_invalid_names)
116 .def_readwrite(
"show_unused_variables",
117 &MPModelExportOptions::show_unused_variables)
118 .def_readwrite(
"max_line_length", &MPModelExportOptions::max_line_length);
121 "ExportModelProtoToMpsString",
122 [](
const std::string& input_model,
const MPModelExportOptions& options) {
124 if (!
model.ParseFromString(input_model)) {
125 throw std::invalid_argument(
126 "Unable to parse input_model as MPModelProto.");
128 return ModelBuilderHelper::ExportModelProtoToMpsString(
model, options);
130 arg(
"input_model"), arg(
"options") = MPModelExportOptions());
132 "ExportModelProtoToLpString",
133 [](
const std::string& input_model,
const MPModelExportOptions& options) {
135 if (!
model.ParseFromString(input_model)) {
136 throw std::invalid_argument(
137 "Unable to parse input_model as MPModelProto.");
139 return ModelBuilderHelper::ExportModelProtoToLpString(
model, options);
141 arg(
"input_model"), arg(
"options") = MPModelExportOptions());
143 m.def(
"ImportFromMpsString", [](
const std::string& str) {
144 MPModelProto
model = ModelBuilderHelper::ImportFromMpsString(str);
145 return pybind11::bytes(
model.SerializeAsString());
147 m.def(
"ImportFromMpsFile", [](
const std::string& str) {
148 MPModelProto
model = ModelBuilderHelper::ImportFromMpsFile(str);
149 return pybind11::bytes(
model.SerializeAsString());
151 m.def(
"ImportFromLpString", [](
const std::string& str) {
152 MPModelProto
model = ModelBuilderHelper::ImportFromLpString(str);
153 return pybind11::bytes(
model.SerializeAsString());
155 m.def(
"ImportFromLpFile", [](
const std::string& str) {
156 MPModelProto
model = ModelBuilderHelper::ImportFromLpFile(str);
157 return pybind11::bytes(
model.SerializeAsString());
160 pybind11::class_<ModelSolverHelper>(m,
"ModelSolverHelper")
161 .def(pybind11::init<>())
164 [](ModelSolverHelper* solver_helper,
const std::string& request_str) {
165 operations_research::MPModelRequest request;
166 if (!request.ParseFromString(request_str)) {
167 throw std::invalid_argument(
168 "Unable to parse request as MPModelRequest.");
170 return pybind11::bytes(
171 solver_helper->Solve(request).SerializeAsString());
175 pybind11::call_guard<pybind11::gil_scoped_release>())
176 .def(
"InterruptSolve", &ModelSolverHelper::InterruptSolve,
177 "Returns true if the interrupt signal was correctly sent, that is, "
178 "if the underlying solver supports it.")
179 .def(
"SetLogCallback", &ModelSolverHelper::SetLogCallback);
PYBIND11_MODULE(pywrap_model_builder_helper, m)
pybind11::bytes BuildModel(const Eigen::Ref< const VectorXd > &variable_lower_bounds, const Eigen::Ref< const VectorXd > &variable_upper_bounds, const Eigen::Ref< const VectorXd > &objective_coefficients, const Eigen::Ref< const VectorXd > &constraint_lower_bounds, const Eigen::Ref< const VectorXd > &constraint_upper_bounds, const SparseMatrix< double, Eigen::RowMajor > &constraint_matrix)
VectorXd variable_lower_bounds
VectorXd variable_upper_bounds