@@ -35,6 +35,113 @@ void vecPrint(const std::vector<double>& vec, const char* name) {
3535 std::cout << " ]" << std::endl;
3636}
3737
38+ void PDLPSolver::printConstraintInfo () {
39+ if (original_lp_ == nullptr ) return ;
40+
41+ int nRows = original_lp_->num_row_ ;
42+ int nCols = original_lp_->num_col_ ;
43+
44+ // Count constraint types BEFORE preprocessing
45+ int eq_count = 0 , leq_count = 0 , geq_count = 0 , bound_count = 0 , free_count = 0 ;
46+
47+ for (int i = 0 ; i < nRows; ++i) {
48+ bool has_lower = original_lp_->row_lower_ [i] > -kHighsInf ;
49+ bool has_upper = original_lp_->row_upper_ [i] < kHighsInf ;
50+
51+ if (has_lower && has_upper) {
52+ if (original_lp_->row_lower_ [i] == original_lp_->row_upper_ [i]) {
53+ eq_count++;
54+ } else {
55+ bound_count++;
56+ }
57+ } else if (has_lower) {
58+ geq_count++;
59+ } else if (has_upper) {
60+ leq_count++;
61+ } else {
62+ free_count++;
63+ }
64+ }
65+
66+ // Count variable bound types
67+ int var_fixed = 0 , var_lower_only = 0 , var_upper_only = 0 ;
68+ int var_boxed = 0 , var_free = 0 ;
69+
70+ for (int i = 0 ; i < nCols; ++i) {
71+ bool has_lower = original_lp_->col_lower_ [i] > -kHighsInf ;
72+ bool has_upper = original_lp_->col_upper_ [i] < kHighsInf ;
73+
74+ if (has_lower && has_upper) {
75+ if (original_lp_->col_lower_ [i] == original_lp_->col_upper_ [i]) {
76+ var_fixed++;
77+ } else {
78+ var_boxed++;
79+ }
80+ } else if (has_lower) {
81+ var_lower_only++;
82+ } else if (has_upper) {
83+ var_upper_only++;
84+ } else {
85+ var_free++;
86+ }
87+ }
88+
89+ logger_.info (" === BEFORE PREPROCESSING ===" );
90+ logger_.info (" Rows: " + std::to_string (nRows) + " , Cols: " + std::to_string (nCols));
91+ logger_.info (" \n Constraint types:" );
92+ logger_.info (" Equality constraints (=): " + std::to_string (eq_count));
93+ logger_.info (" One-sided inequality (>=): " + std::to_string (geq_count));
94+ logger_.info (" One-sided inequality (<=): " + std::to_string (leq_count));
95+ logger_.info (" Two-sided inequality: " + std::to_string (bound_count));
96+ logger_.info (" Free constraints: " + std::to_string (free_count));
97+
98+ logger_.info (" \n Variable bound types:" );
99+ logger_.info (" Fixed variables (l = u): " + std::to_string (var_fixed));
100+ logger_.info (" Boxed variables (l <= x <= u): " + std::to_string (var_boxed));
101+ logger_.info (" Lower bounded only (l <= x): " + std::to_string (var_lower_only));
102+ logger_.info (" Upper bounded only (x <= u): " + std::to_string (var_upper_only));
103+ logger_.info (" Free variables: " + std::to_string (var_free));
104+
105+ logger_.info (" \n === AFTER PREPROCESSING ===" );
106+ logger_.info (" Rows: " + std::to_string (lp_.num_row_ ) +
107+ " , Cols: " + std::to_string (lp_.num_col_ ));
108+ logger_.info (" Equality rows (first " + std::to_string (num_eq_rows_) + " rows)" );
109+ logger_.info (" Inequality rows (remaining " +
110+ std::to_string (lp_.num_row_ - num_eq_rows_) + " rows)" );
111+ logger_.info (" Slack variables added: " +
112+ std::to_string (lp_.num_col_ - nCols));
113+
114+ // Count variable bounds in processed LP
115+ int proc_var_fixed = 0 , proc_var_lower_only = 0 , proc_var_upper_only = 0 ;
116+ int proc_var_boxed = 0 , proc_var_free = 0 ;
117+
118+ for (int i = 0 ; i < lp_.num_col_ ; ++i) {
119+ bool has_lower = lp_.col_lower_ [i] > -kHighsInf ;
120+ bool has_upper = lp_.col_upper_ [i] < kHighsInf ;
121+
122+ if (has_lower && has_upper) {
123+ if (lp_.col_lower_ [i] == lp_.col_upper_ [i]) {
124+ proc_var_fixed++;
125+ } else {
126+ proc_var_boxed++;
127+ }
128+ } else if (has_lower) {
129+ proc_var_lower_only++;
130+ } else if (has_upper) {
131+ proc_var_upper_only++;
132+ } else {
133+ proc_var_free++;
134+ }
135+ }
136+
137+ logger_.info (" \n Processed variable bound types:" );
138+ logger_.info (" Fixed variables: " + std::to_string (proc_var_fixed));
139+ logger_.info (" Boxed variables: " + std::to_string (proc_var_boxed));
140+ logger_.info (" Lower bounded only: " + std::to_string (proc_var_lower_only));
141+ logger_.info (" Upper bounded only: " + std::to_string (proc_var_upper_only));
142+ logger_.info (" Free variables: " + std::to_string (proc_var_free));
143+ }
144+
38145void PDLPSolver::preprocessLp () {
39146 logger_.info (
40147 " Preprocessing LP using cupdlp formulation (slack variables for "
@@ -228,6 +335,8 @@ void PDLPSolver::preprocessLp() {
228335 std::to_string (processed_lp.num_col_ ) + " cols." );
229336 logger_.info (" Unscaled norms: ||c|| = " + std::to_string (unscaled_c_norm_) +
230337 " , ||b|| = " + std::to_string (unscaled_rhs_norm_));
338+
339+ printConstraintInfo ();
231340}
232341
233342PostSolveRetcode PDLPSolver::postprocess (HighsSolution& solution) {
@@ -283,11 +392,18 @@ PostSolveRetcode PDLPSolver::postprocess(HighsSolution& solution) {
283392 results_.primal_obj = final_primal_objective;
284393
285394 // 4. Recover Dual Row Values (y)
286- for (int i = 0 ; i < original_lp_->num_row_ ; ++i) {
287- if (constraint_types_[i] == LEQ) {
288- solution.row_dual [i] = -y_current_[i];
395+ std::vector<double > y_reordered = y_current_;
396+ for (int orig_row = 0 ; orig_row < original_lp_->num_row_ ; ++orig_row) {
397+ int reordered_row = constraint_new_idx_[orig_row];
398+
399+ // Get the dual value from the reordered position
400+ double dual_value = y_reordered[reordered_row];
401+
402+ // Apply sign correction for LEQ constraints
403+ if (constraint_types_[orig_row] == LEQ) {
404+ solution.row_dual [orig_row] = -dual_value;
289405 } else {
290- solution.row_dual [i ] = y_current_[i] ;
406+ solution.row_dual [orig_row ] = dual_value ;
291407 }
292408 }
293409
@@ -311,15 +427,15 @@ PostSolveRetcode PDLPSolver::postprocess(HighsSolution& solution) {
311427 linalg::Ax (unscaled_processed_lp_, x_current_, ax_current_);
312428
313429 int slack_variable_idx = original_num_col_;
314- for (int i = 0 ; i < original_lp_->num_row_ ; ++i ) {
315- if (constraint_types_[i] == BOUND || constraint_types_[i] == FREE) {
316- solution. row_value [i] = x_current_[slack_variable_idx++];
317- } else if (constraint_types_[i ] == LEQ ) {
318- // We transformed Ax <= b to -Ax >= -b. The original row value is Ax.
319- // The calculated ax_current_ is for -Ax, so we flip the sign back.
320- solution.row_value [i ] = -ax_current_[i ];
430+ for (int orig_row = 0 ; orig_row < original_lp_->num_row_ ; ++orig_row ) {
431+ int reordered_row = constraint_new_idx_[orig_row];
432+
433+ if (constraint_types_[orig_row ] == BOUND || constraint_types_[orig_row] == FREE ) {
434+ solution. row_value [orig_row] = x_current_[slack_variable_idx++];
435+ } else if (constraint_types_[orig_row] == LEQ) {
436+ solution.row_value [orig_row ] = -ax_current_[reordered_row ];
321437 } else { // EQ, GEQ
322- solution.row_value [i ] = ax_current_[i ];
438+ solution.row_value [orig_row ] = ax_current_[reordered_row ];
323439 }
324440 }
325441
0 commit comments