@@ -803,10 +803,22 @@ HighsStatus PDLPSolver::PowerMethod(HighsLp &lp, double& op_norm_sq) {
803803 linalg::normalize (x_vec); // Assumes a normalize function in linalg
804804
805805 const HighsInt kYanyuPowerMethod = 0 ;
806- const HighsInt kATAPowerMethod = 1 ;
806+ const HighsInt kYanyuPowerMethodDev = 1 ;
807807 const HighsInt kCuPdlpAATPowerMethod = 2 ;
808808
809- const HighsInt power_method = kYanyuPowerMethod ;// kCuPdlpAATPowerMethod;//
809+ const HighsInt power_method =
810+ kYanyuPowerMethod ;
811+ // kYanyuPowerMethodDev;
812+ // kCuPdlpAATPowerMethod;
813+ printf (" Power method: %s\n " , power_method == kYanyuPowerMethod ? " Yanyu" : power_method == kYanyuPowerMethodDev ? " Yanyu dev" : " CuPdlp-C" );
814+ // Dev version of Yanyu power method (based on A'A) has
815+ //
816+ // * First iterate as vector of ones
817+ //
818+ // * No "convergence" check
819+
820+ // cuPDLP-C version of power method is based on AA'
821+ //
810822 // Allocate memory for matrix-vector products
811823 std::vector<double > y_vec;
812824 std::vector<double > z_vec;
@@ -821,11 +833,12 @@ HighsStatus PDLPSolver::PowerMethod(HighsLp &lp, double& op_norm_sq) {
821833 double op_norm_sq_old = 0.0 ;
822834 LogLevel log_level = logger_.getLogLevel ();
823835 int log_iters = log_level == LogLevel::kVerbose || log_level == LogLevel::kDebug ;
824- // log_iters = 1;
836+ log_iters = 1 ;
825837
826838 if (log_iters) printf (" It lambda dl_lambda\n " );
827839
828- if (power_method == kATAPowerMethod ) {
840+ if (power_method == kYanyuPowerMethodDev ) {
841+ // Start from a vector
829842 x_vec.assign (lp.num_col_ , 1 );
830843 } else if (power_method == kCuPdlpAATPowerMethod ) {
831844 x_vec.assign (lp.num_row_ , 1 );
@@ -837,11 +850,11 @@ HighsStatus PDLPSolver::PowerMethod(HighsLp &lp, double& op_norm_sq) {
837850 if (power_method == kYanyuPowerMethod ) {
838851 // Original Yanyu power method
839852 //
840- // Compute ATAx = A^T * (A * x )
853+ // Compute A'Ax = A'(Ax )
841854 linalg::Ax (lp, x_vec, y_vec);
842- linalg::ATy (lp, y_vec, z_vec); // Note: ATy computes A^T * vector
855+ linalg::ATy (lp, y_vec, z_vec); // Note: ATy computes A' * vector
843856
844- // Estimate the squared operator norm (largest eigenvalue of A^T* A)
857+ // Estimate the squared operator norm (largest eigenvalue of A' A)
845858 op_norm_sq = linalg::dot (x_vec, z_vec); // Assumes a dot product function in linalg
846859
847860 // Check for convergence
@@ -856,38 +869,32 @@ HighsStatus PDLPSolver::PowerMethod(HighsLp &lp, double& op_norm_sq) {
856869 x_vec = z_vec;
857870 if (log_iters) printf (" %2d %12.6g %11.4g\n " , iter, op_norm_sq, dl_op_norm_sq);
858871 } else {
859- if (power_method == kATAPowerMethod ) {
860- // Yanyu power method corrected - with Rayleigh quotient
872+ if (power_method == kYanyuPowerMethodDev ) {
873+ // Yanyu power method without "convergence" check
861874 //
862- // Compute z = ATAx = A^T * (A * x )
875+ // Compute z = A'Ax = A'(Ax )
863876 matrix.product (y_vec, x_vec);
864877 matrix.productTranspose (z_vec, y_vec);
865- // q = z / norm(z)
878+ // Compute the Rayleigh quotient of x which, since x'x=1, is
879+ //
880+ // lambda = x'A'Ax = x'(A'Ax) = x'z
881+ lambda = linalg::dot (x_vec, z_vec);
882+ // x = z / norm(z)
866883 double z_norm = std::sqrt (linalg::dot (z_vec, z_vec));
867- double denom = 1.0 / z_norm;
868884 for (HighsInt iCol = 0 ; iCol < lp.num_col_ ; iCol++)
869- z_vec[iCol] *= denom;
870- // Now compute the Rayleigh quotient of q which, since q'q=1 is
871- //
872- // lambda = q'A'Aq = w^Tw = ||w||_2
873- //
874- // where w = Aq
875- //
876- // y_vec is no longer needed, so w is stored in it
877- matrix.product (y_vec, z_vec);
878- lambda = linalg::dot (y_vec, y_vec);
885+ x_vec[iCol] = z_vec[iCol] / z_norm;
886+
879887 } else {
880888 // cuPDLP-C power method
881889 //
882- // Compute z = AA^Tx = A * (A^T * x)
890+ // Compute z = AA'x = A(A' x)
883891 matrix.productTranspose (y_vec, x_vec);
884892 matrix.product (z_vec, y_vec);
885893 // q = z / norm(z)
886894 double z_norm = std::sqrt (linalg::dot (z_vec, z_vec));
887- double denom = 1.0 / z_norm;
888895 for (HighsInt iRow = 0 ; iRow < lp.num_row_ ; iRow++)
889- z_vec[iRow] *= denom ;
890- // Now compute the Rayleigh quotient of q which, since q'q=1 is
896+ z_vec[iRow] /= z_norm ;
897+ // Compute the Rayleigh quotient of q which, since q'q=1, is
891898 //
892899 // lambda = q'AA'q = w^Tw = ||w||_2
893900 //
@@ -896,11 +903,10 @@ HighsStatus PDLPSolver::PowerMethod(HighsLp &lp, double& op_norm_sq) {
896903 // y_vec is no longer needed, so w is stored in it
897904 matrix.productTranspose (y_vec, z_vec);
898905 lambda = linalg::dot (y_vec, y_vec);
906+ x_vec = z_vec;
899907 }
900908 double dl_lambda = std::fabs (lambda - previous_lambda);
901909 previous_lambda = lambda;
902-
903- x_vec = z_vec;
904910 if (log_iters) printf (" %2d %12.6g %11.4g\n " , iter, lambda, dl_lambda);
905911 }
906912 }
0 commit comments