@@ -568,12 +568,14 @@ void PDLPSolver::solve(std::vector<double>& x, std::vector<double>& y) {
568568 // Compute residuals for current iterate
569569 bool current_converged =
570570 checkConvergence (iter, x_current_, y_current_, Ax_cache_, ATy_cache_,
571- params_.tolerance , current_results, " [L]" );
571+ params_.tolerance , current_results, " [L]" ,
572+ dSlackPos_, dSlackNeg_);
572573
573574 // Compute residuals for average iterate
574575 bool average_converged =
575576 checkConvergence (iter, x_avg_, y_avg_, Ax_avg, ATy_avg,
576- params_.tolerance , average_results, " [A]" );
577+ params_.tolerance , average_results, " [A]" ,
578+ dSlackPosAvg_, dSlackNegAvg_);
577579 hipdlpTimerStop (kHipdlpClockConvergenceCheck );
578580
579581 debugPdlpIterHeaderLog (debug_pdlp_log_file_);
@@ -598,6 +600,8 @@ void PDLPSolver::solve(std::vector<double>& x, std::vector<double>& y) {
598600 final_iter_count_ = iter;
599601 x = x_avg_;
600602 y = y_avg_;
603+ dSlackPos_ = dSlackPosAvg_;
604+ dSlackNeg_ = dSlackNegAvg_;
601605 results_ = average_results;
602606 return solveReturn (TerminationStatus::OPTIMAL);
603607 }
@@ -753,6 +757,8 @@ void PDLPSolver::initialize() {
753757 K_times_x_diff_.resize (lp_.num_row_ , 0.0 );
754758 dSlackPos_.resize (lp_.num_col_ , 0.0 );
755759 dSlackNeg_.resize (lp_.num_col_ , 0.0 );
760+ dSlackPosAvg_.resize (lp_.num_col_ , 0.0 );
761+ dSlackNegAvg_.resize (lp_.num_col_ , 0.0 );
756762}
757763
758764// Update primal weight
@@ -875,42 +881,48 @@ double PDLPSolver::computePrimalFeasibility(
875881 return linalg::vector_norm (primal_residual);
876882}
877883
878- void PDLPSolver::computeDualSlacks (const std::vector<double >& ATy_vector) {
884+ void PDLPSolver::computeDualSlacks (const std::vector<double >& dualResidual,
885+ std::vector<double >& dSlackPos,
886+ std::vector<double >& dSlackNeg) {
879887 // Ensure vectors are correctly sized
880- if (dSlackPos_ .size () != lp_.num_col_ ) dSlackPos_ .resize (lp_.num_col_ );
881- if (dSlackNeg_ .size () != lp_.num_col_ ) dSlackNeg_ .resize (lp_.num_col_ );
888+ if (dSlackPos .size () != lp_.num_col_ ) dSlackPos .resize (lp_.num_col_ );
889+ if (dSlackNeg .size () != lp_.num_col_ ) dSlackNeg .resize (lp_.num_col_ );
882890
883891 for (HighsInt i = 0 ; i < lp_.num_col_ ; ++i) {
884- double dual_residual = lp_.col_cost_ [i] - ATy_vector[i];
885-
886892 // Compute positive slack (for lower bounds)
887- // CUPDLP: max(dual_residual, 0) * hasLower
888- if (lp_.col_lower_ [i] > -kHighsInf ) {
889- dSlackPos_ [i] = std::max (0.0 , dual_residual );
890- } else {
891- dSlackPos_ [i] = 0.0 ;
892- }
893-
894- // Compute negative slack (for upper bounds)
895- // CUPDLP: -min(dual_residual, 0) * hasUpper
896- if (lp_.col_upper_ [i] < kHighsInf ) {
897- dSlackNeg_ [i] = std::max (0.0 , -dual_residual );
898- } else {
899- dSlackNeg_ [i] = 0.0 ;
900- }
893+ // CUPDLP: max(dual_residual, 0) * hasLower
894+ if (lp_.col_lower_ [i] > -kHighsInf ) {
895+ dSlackPos [i] = std::max (0.0 , dualResidual[i] );
896+ } else {
897+ dSlackPos [i] = 0.0 ;
898+ }
899+
900+ // Compute negative slack (for upper bounds)
901+ // CUPDLP: -min(dual_residual, 0) * hasUpper
902+ if (lp_.col_upper_ [i] < kHighsInf ) {
903+ dSlackNeg [i] = std::max (0.0 , -dualResidual[i] );
904+ } else {
905+ dSlackNeg [i] = 0.0 ;
906+ }
901907 }
902908}
903909
904910double PDLPSolver::computeDualFeasibility (
905- const std::vector<double >& ATy_vector) {
906- computeDualSlacks (ATy_vector); // This updates dSlackPos_ and dSlackNeg_
911+ const std::vector<double >& ATy_vector, std::vector<double >& dSlackPos,
912+ std::vector<double >& dSlackNeg) {
913+ std::vector<double > dualResidual (lp_.num_col_ , 0.0 );
914+ // dualResidual = c-A'y
915+ dualResidual = linalg::vector_subtrac (lp_.col_cost_ , ATy_vector);
916+ double dualResidualNorm = linalg::vector_norm (dualResidual);
917+
918+ // Call the refactored function to populate dSlackPos and dSlackNeg
919+ computeDualSlacks (dualResidual, dSlackPos, dSlackNeg);
907920
908921 std::vector<double > dual_residual (lp_.num_col_ );
909922
910923 for (HighsInt i = 0 ; i < lp_.num_col_ ; ++i) {
911924 // Matching CUPDLP: c - A'y - dSlackPos + dSlackNeg
912- dual_residual[i] =
913- lp_.col_cost_ [i] - ATy_vector[i] - dSlackPos_[i] + dSlackNeg_[i];
925+ dual_residual[i] = dualResidual[i] - dSlackPos[i] + dSlackNeg[i];
914926 }
915927
916928 // Apply scaling if needed
@@ -973,7 +985,9 @@ PDLPSolver::computeDualityGap(const std::vector<double>& x,
973985 cTx);
974986}
975987
976- double PDLPSolver::computeDualObjective (const std::vector<double >& y) {
988+ double PDLPSolver::computeDualObjective (
989+ const std::vector<double >& y, const std::vector<double >& dSlackPos,
990+ const std::vector<double >& dSlackNeg) {
977991 double dual_obj = lp_.offset_ ;
978992
979993 // Compute b'y (or rhs'y in cuPDLP notation)
@@ -984,14 +998,14 @@ double PDLPSolver::computeDualObjective(const std::vector<double>& y) {
984998 // Add contribution from lower bounds: l'*slackPos
985999 for (int i = 0 ; i < lp_.num_col_ ; ++i) {
9861000 if (lp_.col_lower_ [i] > -kHighsInf ) {
987- dual_obj += lp_.col_lower_ [i] * dSlackPos_ [i];
1001+ dual_obj += lp_.col_lower_ [i] * dSlackPos [i];
9881002 }
9891003 }
9901004
9911005 // Subtract contribution from upper bounds: u'*slackNeg
9921006 for (int i = 0 ; i < lp_.num_col_ ; ++i) {
9931007 if (lp_.col_upper_ [i] < kHighsInf ) {
994- dual_obj -= lp_.col_upper_ [i] * dSlackNeg_ [i];
1008+ dual_obj -= lp_.col_upper_ [i] * dSlackNeg [i];
9951009 }
9961010 }
9971011
@@ -1003,16 +1017,20 @@ bool PDLPSolver::checkConvergence(const int iter, const std::vector<double>& x,
10031017 const std::vector<double >& ax_vector,
10041018 const std::vector<double >& aty_vector,
10051019 double epsilon, SolverResults& results,
1006- const char * type) {
1007- // Compute dual slacks first
1008- computeDualSlacks (aty_vector);
1020+ const char * type,
1021+ // Add slack vectors as non-const references
1022+ std::vector<double >& dSlackPos,
1023+ std::vector<double >& dSlackNeg) {
1024+ // computeDualSlacks is now called inside computeDualFeasibility
10091025
10101026 // Compute primal feasibility
10111027 double primal_feasibility = computePrimalFeasibility (ax_vector);
10121028 results.primal_feasibility = primal_feasibility;
10131029
10141030 // Compute dual feasibility
1015- double dual_feasibility = computeDualFeasibility (aty_vector);
1031+ // This will populate dSlackPos and dSlackNeg
1032+ double dual_feasibility =
1033+ computeDualFeasibility (aty_vector, dSlackPos, dSlackNeg);
10161034 results.dual_feasibility = dual_feasibility;
10171035
10181036 // Compute objectives
@@ -1022,7 +1040,8 @@ bool PDLPSolver::checkConvergence(const int iter, const std::vector<double>& x,
10221040 }
10231041 results.primal_obj = primal_obj;
10241042
1025- double dual_obj = computeDualObjective (y);
1043+ // Pass the now-populated slack vectors to computeDualObjective
1044+ double dual_obj = computeDualObjective (y, dSlackPos, dSlackNeg);
10261045 results.dual_obj = dual_obj;
10271046
10281047 // Compute duality gap
@@ -1282,8 +1301,6 @@ void PDLPSolver::unscaleSolution(std::vector<double>& x,
12821301 const std::vector<double >& col_scale = scaling_.GetColScaling ();
12831302 if (!dSlackPos_.empty () && col_scale.size () == dSlackPos_.size ()) {
12841303 for (size_t i = 0 ; i < dSlackPos_.size (); ++i) {
1285- std::cout << " dSlackPos_ before unscale[" << i << " ] = " << dSlackPos_[i]
1286- << std::endl;
12871304 dSlackPos_[i] *= col_scale[i];
12881305 dSlackNeg_[i] *= col_scale[i];
12891306 }
0 commit comments