99 * @brief
1010 */
1111#include " pdhg.hpp"
12+ #include " HConst.h"
1213
1314#include < cmath>
1415#include < iostream>
@@ -29,15 +30,16 @@ void PDLPSolver::preprocessLp() {
2930 " Preprocessing LP using cupdlp formulation (slack variables for "
3031 " bounds)..." );
3132
32- HighsLp& processed_lp = lp_;
33-
3433 int nRows_orig = original_lp_->num_row_ ;
3534 int nCols_orig = original_lp_->num_col_ ;
3635
36+ if (original_lp_->a_matrix_ .isRowwise ()){
37+ logger_.info (" Original LP matrix must be in column-wise format," );
38+ }
39+
3740 int num_new_cols = 0 ;
38- int nEqs = 0 ;
41+ int nEqs = 0 ; // Count of equality-like constraints (EQ, BOUND, FREE)
3942 constraint_types_.resize (nRows_orig);
40- constraint_new_idx_.resize (nRows_orig);
4143
4244 // 1. First pass: Classify constraints and count slack variables needed
4345 for (int i = 0 ; i < nRows_orig; ++i) {
@@ -47,9 +49,11 @@ void PDLPSolver::preprocessLp() {
4749 if (has_lower && has_upper) {
4850 if (original_lp_->row_lower_ [i] == original_lp_->row_upper_ [i]) {
4951 constraint_types_[i] = EQ;
52+ nEqs++;
5053 } else {
5154 constraint_types_[i] = BOUND;
5255 num_new_cols++; // Need one slack variable for each ranged constraint
56+ nEqs++;
5357 }
5458 } else if (has_lower) {
5559 constraint_types_[i] = GEQ;
@@ -59,21 +63,34 @@ void PDLPSolver::preprocessLp() {
5963 constraint_types_[i] =
6064 FREE; // Free rows become bounded equalities Ax=0, z=[-inf,inf]
6165 num_new_cols++;
66+ nEqs++;
6267 }
6368 }
6469
6570 // 2. Set new dimensions
71+ HighsLp& processed_lp = lp_;
6672 processed_lp.num_col_ = nCols_orig + num_new_cols;
6773 processed_lp.num_row_ = nRows_orig;
6874 original_num_col_ = nCols_orig; // store for postsolve
75+ constraint_new_idx_.resize (nRows_orig);
6976
70- // 3. Resize all vectors in the processed_lp
7177 processed_lp.col_cost_ .resize (processed_lp.num_col_ );
7278 processed_lp.col_lower_ .resize (processed_lp.num_col_ );
7379 processed_lp.col_upper_ .resize (processed_lp.num_col_ );
7480 processed_lp.row_lower_ .resize (processed_lp.num_row_ );
7581 processed_lp.row_upper_ .resize (processed_lp.num_row_ );
7682
83+ // 3. Determine row permutation: EQ/BOUND/FREE first, then LEQ/GEQ
84+ int eq_idx = 0 ;
85+ int ineq_idx = nEqs;
86+ for (int i = 0 ; i < nRows_orig; ++i){
87+ if (constraint_types_[i] == EQ || constraint_types_[i] == BOUND || constraint_types_[i] == FREE){
88+ constraint_new_idx_[i] = eq_idx++;
89+ } else {
90+ constraint_new_idx_[i] = ineq_idx++;
91+ }
92+ }
93+
7794 // 4. Populate costs and bounds for original and new slack variables
7895 for (int i = 0 ; i < nCols_orig; ++i) {
7996 processed_lp.col_cost_ [i] = original_lp_->col_cost_ [i];
@@ -140,6 +157,7 @@ void PDLPSolver::preprocessLp() {
140157
141158 // 6. Set the new RHS (row bounds)
142159 for (int i = 0 ; i < nRows_orig; ++i) {
160+ const int new_idx = constraint_new_idx_[i];
143161 switch (constraint_types_[i]) {
144162 case EQ:
145163 processed_lp.row_lower_ [i] = original_lp_->row_lower_ [i];
0 commit comments