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"
31 #include "ortools/math_opt/model.pb.h"
32 #include "ortools/math_opt/solution.pb.h"
33 #include "ortools/math_opt/sparse_containers.pb.h"
40 constexpr SupportedProblemStructures kPdlpSupportedStructures = {
43 absl::StatusOr<SparseDoubleVectorProto> ExtractSolution(
44 const Eigen::VectorXd& values,
const std::vector<int64_t>& pdlp_index_to_id,
45 const SparseVectorFilterProto& filter,
const double scale) {
46 if (values.size() != pdlp_index_to_id.size()) {
47 return absl::InternalError(
48 absl::StrCat(
"Expected solution vector with ", pdlp_index_to_id.size(),
49 " elements, found: ", values.size()));
51 SparseVectorFilterPredicate predicate(filter);
52 SparseDoubleVectorProto result;
53 for (
int i = 0; i < pdlp_index_to_id.size(); ++i) {
54 const double value = scale * values[i];
55 const int64_t
id = pdlp_index_to_id[i];
56 if (predicate.AcceptsAndUpdate(
id,
value)) {
58 result.add_values(
value);
65 Eigen::VectorXd EncodeSolution(
66 const SparseDoubleVectorProto& values,
67 const absl::flat_hash_map<int64_t, int64_t>& id_to_pdlp_index,
70 const int num_values = values.values_size();
71 for (
int k = 0; k < num_values; ++k) {
72 const int64_t
index = id_to_pdlp_index.at(values.ids(k));
73 pdlp_vector[
index] = values.values(k) / scale;
86 const VariablesProto& variables =
model_proto.variables();
87 const LinearConstraintsProto& linear_constraints =
90 linear_constraints.ids_size());
94 if (variables.names_size() > 0) {
96 variables.names().end()};
98 if (linear_constraints.names_size() > 0) {
100 linear_constraints.names().end()};
102 for (
int i = 0; i < variables.ids_size(); ++i) {
103 result.var_id_to_pdlp_index_[variables.ids(i)] = i;
104 result.pdlp_index_to_var_id_.push_back(variables.ids(i));
108 for (
int i = 0; i < linear_constraints.ids_size(); ++i) {
109 result.lin_con_id_to_pdlp_index_[linear_constraints.ids(i)] = i;
110 result.pdlp_index_to_lin_con_id_.push_back(linear_constraints.ids(i));
114 const bool is_maximize =
model_proto.objective().maximize();
115 const double obj_scale = is_maximize ? -1.0 : 1.0;
117 for (
const auto [var_id,
coef] :
122 const SparseDoubleMatrixProto& quadratic_objective =
124 const int obj_nnz = quadratic_objective.row_ids().size();
129 for (
int i = 0; i < obj_nnz; ++i) {
130 const int64_t row_index =
131 result.var_id_to_pdlp_index_.at(quadratic_objective.row_ids(i));
132 const int64_t column_index =
133 result.var_id_to_pdlp_index_.at(quadratic_objective.column_ids(i));
134 const double value = obj_scale * quadratic_objective.coefficients(i);
135 if (row_index != column_index) {
136 return absl::InvalidArgumentError(
137 "PDLP cannot solve problems with non-diagonal objective matrices");
151 std::vector<Eigen::Triplet<double, int64_t>> mat_triplets;
152 const int nnz =
model_proto.linear_constraint_matrix().row_ids_size();
153 mat_triplets.reserve(nnz);
154 const SparseDoubleMatrixProto& proto_mat =
156 for (
int i = 0; i < nnz; ++i) {
157 const int64_t row_index =
158 result.lin_con_id_to_pdlp_index_.at(proto_mat.row_ids(i));
159 const int64_t column_index =
160 result.var_id_to_pdlp_index_.at(proto_mat.column_ids(i));
161 const double value = proto_mat.coefficients(i);
162 mat_triplets.emplace_back(row_index, column_index,
value);
171 for (int64_t var_index = 0; var_index < pdlp_index_to_var_id_.size();
175 inverted_bounds.
variables.push_back(pdlp_index_to_var_id_[var_index]);
178 for (int64_t lin_con_index = 0;
179 lin_con_index < pdlp_index_to_lin_con_id_.size(); ++lin_con_index) {
183 pdlp_index_to_lin_con_id_[lin_con_index]);
186 return inverted_bounds;
190 const Eigen::VectorXd& primal_values,
191 const SparseVectorFilterProto& variable_filter)
const {
192 return ExtractSolution(primal_values, pdlp_index_to_var_id_, variable_filter,
196 const Eigen::VectorXd& dual_values,
197 const SparseVectorFilterProto& linear_constraint_filter)
const {
198 return ExtractSolution(dual_values, pdlp_index_to_lin_con_id_,
199 linear_constraint_filter,
203 const Eigen::VectorXd& reduced_costs,
204 const SparseVectorFilterProto& variable_filter)
const {
205 return ExtractSolution(reduced_costs, pdlp_index_to_var_id_, variable_filter,
210 const SolutionHintProto& solution_hint)
const {
213 result.
primal_solution = EncodeSolution(solution_hint.variable_values(),
214 var_id_to_pdlp_index_, 1.0);
216 EncodeSolution(solution_hint.dual_values(), lin_con_id_to_pdlp_index_,
#define RETURN_IF_ERROR(expr)
absl::StatusOr< SparseDoubleVectorProto > DualVariablesToProto(const Eigen::VectorXd &dual_values, const SparseVectorFilterProto &linear_constraint_filter) const
const pdlp::QuadraticProgram & pdlp_lp() const
static absl::StatusOr< PdlpBridge > FromProto(const ModelProto &model_proto)
InvertedBounds ListInvertedBounds() const
pdlp::PrimalAndDualSolution SolutionHintToWarmStart(const SolutionHintProto &solution_hint) 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
CpModelProto const * model_proto
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)
Collection of objects used to extend the Constraint Solver library.
std::vector< int64_t > variables
std::vector< int64_t > linear_constraints
Eigen::VectorXd dual_solution
Eigen::VectorXd primal_solution
Eigen::VectorXd variable_upper_bounds
Eigen::VectorXd variable_lower_bounds
double objective_scaling_factor
std::optional< std::vector< std::string > > constraint_names
Eigen::VectorXd constraint_lower_bounds
std::optional< std::string > problem_name
std::optional< std::vector< std::string > > variable_names
void ResizeAndInitialize(int64_t num_variables, int64_t num_constraints)
Eigen::SparseMatrix< double, Eigen::ColMajor, int64_t > constraint_matrix
std::optional< Eigen::DiagonalMatrix< double, Eigen::Dynamic > > objective_matrix
Eigen::VectorXd constraint_upper_bounds
Eigen::VectorXd objective_vector