21#include "absl/container/flat_hash_map.h"
22#include "absl/status/status.h"
23#include "absl/status/statusor.h"
24#include "absl/strings/str_cat.h"
26#include "Eigen/SparseCore"
27#include "ortools/pdlp/quadratic_program.h"
30#include "ortools/math_opt/model.pb.h"
31#include "ortools/math_opt/sparse_containers.pb.h"
37absl::StatusOr<SparseDoubleVectorProto> ExtractSolution(
38 const Eigen::VectorXd& values,
const std::vector<int64_t>& pdlp_index_to_id,
39 const SparseVectorFilterProto& filter,
const double scale) {
40 if (values.size() != pdlp_index_to_id.size()) {
41 return absl::InternalError(
42 absl::StrCat(
"Expected solution vector with ", pdlp_index_to_id.size(),
43 " elements, found: ", values.size()));
45 SparseVectorFilterPredicate predicate(filter);
46 SparseDoubleVectorProto result;
47 for (
int i = 0; i < pdlp_index_to_id.size(); ++i) {
48 const double value = scale * values[i];
49 const int64_t
id = pdlp_index_to_id[i];
50 if (predicate.AcceptsAndUpdate(
id,
value)) {
52 result.add_values(
value);
63 pdlp::QuadraticProgram&
pdlp_lp = result.pdlp_lp_;
64 const VariablesProto& variables =
model_proto.variables();
65 const LinearConstraintsProto& linear_constraints =
67 pdlp_lp.ResizeAndInitialize(variables.ids_size(),
68 linear_constraints.ids_size());
72 if (variables.names_size() > 0) {
73 pdlp_lp.variable_names = {variables.names().begin(),
74 variables.names().end()};
76 if (linear_constraints.names_size() > 0) {
77 pdlp_lp.constraint_names = {linear_constraints.names().begin(),
78 linear_constraints.names().end()};
80 for (
int i = 0; i < variables.ids_size(); ++i) {
81 result.var_id_to_pdlp_index_[variables.ids(i)] = i;
82 result.pdlp_index_to_var_id_.push_back(variables.ids(i));
83 pdlp_lp.variable_lower_bounds[i] = variables.lower_bounds(i);
84 pdlp_lp.variable_upper_bounds[i] = variables.upper_bounds(i);
85 if (variables.integers(i)) {
86 return absl::InvalidArgumentError(
87 "PDLP cannot solve problems with integer variables");
90 for (
int i = 0; i < linear_constraints.ids_size(); ++i) {
91 result.lin_con_id_to_pdlp_index_[linear_constraints.ids(i)] = i;
92 result.pdlp_index_to_lin_con_id_.push_back(linear_constraints.ids(i));
93 pdlp_lp.constraint_lower_bounds[i] = linear_constraints.lower_bounds(i);
94 pdlp_lp.constraint_upper_bounds[i] = linear_constraints.upper_bounds(i);
96 const bool is_maximize =
model_proto.objective().maximize();
97 const double obj_scale = is_maximize ? -1.0 : 1.0;
99 for (
const auto [var_id,
coef] :
101 pdlp_lp.objective_vector[result.var_id_to_pdlp_index_.at(var_id)] =
104 const SparseDoubleMatrixProto& quadratic_objective =
106 std::vector<Eigen::Triplet<double, int64_t>> obj_triplets;
107 const int obj_nnz = quadratic_objective.row_ids().size();
108 for (
int i = 0; i < obj_nnz; ++i) {
109 const int64_t row_index =
110 result.var_id_to_pdlp_index_.at(quadratic_objective.row_ids(i));
111 const int64_t column_index =
112 result.var_id_to_pdlp_index_.at(quadratic_objective.column_ids(i));
113 const double value = obj_scale * quadratic_objective.coefficients(i);
121 obj_triplets.push_back({row_index, column_index,
value});
122 obj_triplets.push_back({column_index, row_index,
value});
124 pdlp_lp.objective_matrix.setFromTriplets(obj_triplets.begin(),
126 pdlp_lp.objective_scaling_factor = obj_scale;
130 std::vector<Eigen::Triplet<double, int64_t>> mat_triplets;
131 const int nnz =
model_proto.linear_constraint_matrix().row_ids_size();
132 mat_triplets.reserve(nnz);
133 const SparseDoubleMatrixProto& proto_mat =
135 for (
int i = 0; i < nnz; ++i) {
136 const int64_t row_index =
137 result.lin_con_id_to_pdlp_index_.at(proto_mat.row_ids(i));
138 const int64_t column_index =
139 result.var_id_to_pdlp_index_.at(proto_mat.column_ids(i));
140 const double value = proto_mat.coefficients(i);
141 mat_triplets.emplace_back(row_index, column_index,
value);
143 pdlp_lp.constraint_matrix.setFromTriplets(mat_triplets.begin(),
149 const Eigen::VectorXd& primal_values,
150 const SparseVectorFilterProto& variable_filter)
const {
151 return ExtractSolution(primal_values, pdlp_index_to_var_id_, variable_filter,
155 const Eigen::VectorXd& dual_values,
156 const SparseVectorFilterProto& linear_constraint_filter)
const {
157 return ExtractSolution(dual_values, pdlp_index_to_lin_con_id_,
158 linear_constraint_filter,
159 pdlp_lp_.objective_scaling_factor);
162 const Eigen::VectorXd& reduced_costs,
163 const SparseVectorFilterProto& variable_filter)
const {
164 return ExtractSolution(reduced_costs, pdlp_index_to_var_id_, variable_filter,
165 pdlp_lp_.objective_scaling_factor);
const pdlp::QuadraticProgram & pdlp_lp() const
absl::StatusOr< SparseDoubleVectorProto > DualVariablesToProto(const Eigen::VectorXd &dual_values, const SparseVectorFilterProto &linear_constraint_filter) const
static absl::StatusOr< PdlpBridge > FromProto(const ModelProto &model_proto)
absl::StatusOr< SparseDoubleVectorProto > PrimalVariablesToProto(const Eigen::VectorXd &primal_values, const SparseVectorFilterProto &variable_filter) const
absl::StatusOr< SparseDoubleVectorProto > ReducedCostsToProto(const Eigen::VectorXd &reduced_costs, const SparseVectorFilterProto &variable_filter) const
CpModelProto const * model_proto
SparseVectorView< T > MakeView(absl::Span< const int64_t > ids, const Collection &values)
Collection of objects used to extend the Constraint Solver library.