22#include "Eigen/SparseCore"
23#include "absl/container/flat_hash_map.h"
24#include "absl/status/status.h"
25#include "absl/status/statusor.h"
26#include "absl/strings/str_cat.h"
27#include "absl/types/span.h"
44absl::StatusOr<SparseDoubleVectorProto> ExtractSolution(
45 const Eigen::VectorXd& values, absl::Span<const int64_t> pdlp_index_to_id,
47 if (values.size() != pdlp_index_to_id.size()) {
48 return absl::InternalError(
49 absl::StrCat(
"Expected solution vector with ", pdlp_index_to_id.size(),
50 " elements, found: ", values.size()));
54 for (
int i = 0;
i < pdlp_index_to_id.size(); ++
i) {
55 const double value = scale * values[
i];
56 const int64_t
id = pdlp_index_to_id[
i];
57 if (predicate.AcceptsAndUpdate(
id, value)) {
59 result.add_values(value);
66Eigen::VectorXd EncodeSolution(
68 const absl::flat_hash_map<int64_t, int64_t>& id_to_pdlp_index,
70 Eigen::VectorXd pdlp_vector(Eigen::VectorXd::Zero(id_to_pdlp_index.size()));
71 const int num_values = values.values_size();
72 for (
int k = 0; k < num_values; ++k) {
73 const int64_t index = id_to_pdlp_index.at(values.ids(k));
74 pdlp_vector[index] = values.values(k) / scale;
92 if (!model_proto.
name().empty()) {
97 variables.
names().end()};
100 pdlp_lp.constraint_names = {linear_constraints.
names().begin(),
101 linear_constraints.
names().end()};
103 for (
int i = 0; i < variables.
ids_size(); ++i) {
104 result.var_id_to_pdlp_index_[variables.
ids(i)] = i;
105 result.pdlp_index_to_var_id_.push_back(variables.
ids(i));
109 for (
int i = 0; i < linear_constraints.
ids_size(); ++i) {
110 result.lin_con_id_to_pdlp_index_[linear_constraints.
ids(i)] = i;
111 result.pdlp_index_to_lin_con_id_.push_back(linear_constraints.
ids(i));
116 const double obj_scale = is_maximize ? -1.0 : 1.0;
118 for (
const auto [var_id, coef] :
120 pdlp_lp.objective_vector[result.var_id_to_pdlp_index_.at(var_id)] =
125 const int obj_nnz = quadratic_objective.
row_ids().size();
127 pdlp_lp.objective_matrix.emplace();
130 for (
int i = 0; i < obj_nnz; ++i) {
131 const int64_t row_index =
132 result.var_id_to_pdlp_index_.at(quadratic_objective.
row_ids(i));
133 const int64_t column_index =
134 result.var_id_to_pdlp_index_.at(quadratic_objective.
column_ids(i));
135 const double value = obj_scale * quadratic_objective.
coefficients(i);
136 if (row_index != column_index) {
137 return absl::InvalidArgumentError(
138 "PDLP cannot solve problems with non-diagonal objective matrices");
146 pdlp_lp.objective_matrix->diagonal()[row_index] = 2 * value;
148 pdlp_lp.objective_scaling_factor = obj_scale;
152 std::vector<Eigen::Triplet<double, int64_t>> mat_triplets;
154 mat_triplets.reserve(nnz);
157 for (
int i = 0; i < nnz; ++i) {
158 const int64_t row_index =
159 result.lin_con_id_to_pdlp_index_.at(proto_mat.
row_ids(i));
160 const int64_t column_index =
161 result.var_id_to_pdlp_index_.at(proto_mat.
column_ids(i));
163 mat_triplets.emplace_back(row_index, column_index, value);
165 pdlp_lp.constraint_matrix.setFromTriplets(mat_triplets.begin(),
172 for (int64_t var_index = 0; var_index < pdlp_index_to_var_id_.size();
174 if (pdlp_lp_.variable_lower_bounds[var_index] >
175 pdlp_lp_.variable_upper_bounds[var_index]) {
176 inverted_bounds.
variables.push_back(pdlp_index_to_var_id_[var_index]);
179 for (int64_t lin_con_index = 0;
180 lin_con_index < pdlp_index_to_lin_con_id_.size(); ++lin_con_index) {
181 if (pdlp_lp_.constraint_lower_bounds[lin_con_index] >
182 pdlp_lp_.constraint_upper_bounds[lin_con_index]) {
184 pdlp_index_to_lin_con_id_[lin_con_index]);
187 return inverted_bounds;
191 const Eigen::VectorXd& primal_values,
193 return ExtractSolution(primal_values, pdlp_index_to_var_id_, variable_filter,
197 const Eigen::VectorXd& dual_values,
199 return ExtractSolution(dual_values, pdlp_index_to_lin_con_id_,
200 linear_constraint_filter,
201 pdlp_lp_.objective_scaling_factor);
204 const Eigen::VectorXd& reduced_costs,
206 return ExtractSolution(reduced_costs, pdlp_index_to_var_id_, variable_filter,
207 pdlp_lp_.objective_scaling_factor);
215 var_id_to_pdlp_index_, 1.0);
217 EncodeSolution(solution_hint.
dual_values(), lin_con_id_to_pdlp_index_,
218 pdlp_lp_.objective_scaling_factor);
#define RETURN_IF_ERROR(expr)
::int64_t ids(int index) const
double upper_bounds(int index) const
int ids_size() const
repeated int64 ids = 1;
const ::std::string & names(int index) const
double lower_bounds(int index) const
int names_size() const
repeated string names = 4;
const ::operations_research::math_opt::VariablesProto & variables() const
const ::operations_research::math_opt::LinearConstraintsProto & linear_constraints() const
const ::std::string & name() const
const ::operations_research::math_opt::ObjectiveProto & objective() const
const ::operations_research::math_opt::SparseDoubleMatrixProto & linear_constraint_matrix() const
const ::operations_research::math_opt::SparseDoubleVectorProto & linear_coefficients() const
const ::operations_research::math_opt::SparseDoubleMatrixProto & quadratic_coefficients() const
InvertedBounds ListInvertedBounds() const
Returns the ids of variables and linear constraints with inverted bounds.
absl::StatusOr< SparseDoubleVectorProto > DualVariablesToProto(const Eigen::VectorXd &dual_values, const SparseVectorFilterProto &linear_constraint_filter) const
static absl::StatusOr< PdlpBridge > FromProto(const ModelProto &model_proto)
const pdlp::QuadraticProgram & pdlp_lp() const
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
pdlp::PrimalAndDualSolution SolutionHintToWarmStart(const SolutionHintProto &solution_hint) const
const ::operations_research::math_opt::SparseDoubleVectorProto & variable_values() const
const ::operations_research::math_opt::SparseDoubleVectorProto & dual_values() const
double coefficients(int index) const
::int64_t row_ids(int index) const
int row_ids_size() const
repeated int64 row_ids = 1;
::int64_t column_ids(int index) const
const ::std::string & names(int index) const
double lower_bounds(int index) const
double upper_bounds(int index) const
::int64_t ids(int index) const
int ids_size() const
repeated int64 ids = 1;
int names_size() const
repeated string names = 5;
An object oriented wrapper for quadratic constraints in ModelStorage.
absl::Status ModelIsSupported(const ModelProto &model, const SupportedProblemStructures &support_menu, const absl::string_view solver_name)
SparseVectorView< T > MakeView(absl::Span< const int64_t > ids, const Collection &values)
constexpr SupportedProblemStructures kPdlpSupportedStructures
In SWIG mode, we don't want anything besides these top-level includes.
std::vector< int64_t > linear_constraints
Ids of the linear constraints with inverted bounds.
std::vector< int64_t > variables
Ids of the variables with inverted bounds.
Eigen::VectorXd primal_solution
Eigen::VectorXd dual_solution