void Covariance ( const ElementalMatrix<F>& DPre, ElementalMatrix<F>& SPre ) { DEBUG_CSE DistMatrixReadProxy<F,F,MC,MR> DProx( DPre ); DistMatrixWriteProxy<F,F,MC,MR> SProx( SPre ); auto& D = DProx.GetLocked(); auto& S = SProx.Get(); const Grid& g = D.Grid(); const Int numObs = D.Height(); // Compute the average column DistMatrix<F> ones(g), xMean(g); Ones( ones, numObs, 1 ); Gemv( TRANSPOSE, F(1)/F(numObs), D, ones, xMean ); DistMatrix<F,MR,STAR> xMean_MR(g); xMean_MR.AlignWith( D ); xMean_MR = xMean; // Subtract the mean from each column of D DistMatrix<F> DDev( D ); for( Int iLoc=0; iLoc<DDev.LocalHeight(); ++iLoc ) blas::Axpy ( DDev.LocalWidth(), F(-1), xMean_MR.LockedBuffer(), 1, DDev.Buffer(iLoc,0), DDev.LDim() ); // Form S := 1/(numObs-1) DDev DDev' Herk( LOWER, ADJOINT, Base<F>(1)/Base<F>(numObs-1), DDev, S ); Conjugate( S ); MakeHermitian( LOWER, S ); }
inline void ALM ( const ElementalMatrix<F>& MPre, ElementalMatrix<F>& LPre, ElementalMatrix<F>& SPre, const RPCACtrl<Base<F>>& ctrl ) { DistMatrixReadProxy<F,F,MC,MR> MProx( MPre ); DistMatrixWriteProxy<F,F,MC,MR> LProx( LPre ), SProx( SPre ); auto& M = MProx.GetLocked(); auto& L = LProx.Get(); auto& S = SProx.Get(); typedef Base<F> Real; const Int m = M.Height(); const Int n = M.Width(); const int commRank = mpi::Rank( M.Grid().Comm() ); // If tau is unspecified, set it to 1/sqrt(max(m,n)) const Base<F> tau = ( ctrl.tau <= Real(0) ? Real(1) / sqrt(Real(Max(m,n))) : ctrl.tau ); if( ctrl.tol <= Real(0) ) LogicError("tol cannot be non-positive"); const Base<F> tol = ctrl.tol; const double startTime = mpi::Time(); DistMatrix<F> Y( M ); NormalizeEntries( Y ); const Real twoNorm = TwoNorm( Y ); const Real maxNorm = MaxNorm( Y ); const Real infNorm = maxNorm / tau; const Real dualNorm = Max( twoNorm, infNorm ); Y *= F(1)/dualNorm; // If beta is unspecified, set it to 1 / 2 || sign(M) ||_2 Base<F> beta = ( ctrl.beta <= Real(0) ? Real(1) / (2*twoNorm) : ctrl.beta ); const Real frobM = FrobeniusNorm( M ); const Real maxM = MaxNorm( M ); if( ctrl.progress && commRank == 0 ) cout << "|| M ||_F = " << frobM << "\n" << "|| M ||_max = " << maxM << endl; Zeros( L, m, n ); Zeros( S, m, n ); Int numIts=0, numPrimalIts=0; DistMatrix<F> LLast( M.Grid() ), SLast( M.Grid() ), E( M.Grid() ); while( true ) { ++numIts; Int rank, numNonzeros; while( true ) { ++numPrimalIts; LLast = L; SLast = S; // ST_{tau/beta}(M - L + Y/beta) S = M; S -= L; Axpy( F(1)/beta, Y, S ); SoftThreshold( S, tau/beta ); numNonzeros = ZeroNorm( S ); // SVT_{1/beta}(M - S + Y/beta) L = M; L -= S; Axpy( F(1)/beta, Y, L ); if( ctrl.usePivQR ) rank = SVT( L, Real(1)/beta, ctrl.numPivSteps ); else rank = SVT( L, Real(1)/beta ); LLast -= L; SLast -= S; const Real frobLDiff = FrobeniusNorm( LLast ); const Real frobSDiff = FrobeniusNorm( SLast ); if( frobLDiff/frobM < tol && frobSDiff/frobM < tol ) { if( ctrl.progress && commRank == 0 ) cout << "Primal loop converged: " << mpi::Time()-startTime << " total secs" << endl; break; } else { if( ctrl.progress && commRank == 0 ) cout << " " << numPrimalIts << ": \n" << " || Delta L ||_F / || M ||_F = " << frobLDiff/frobM << "\n" << " || Delta S ||_F / || M ||_F = " << frobSDiff/frobM << "\n" << " rank=" << rank << ", numNonzeros=" << numNonzeros << ", " << mpi::Time()-startTime << " total secs" << endl; } } // E := M - (L + S) E = M; E -= L; E -= S; const Real frobE = FrobeniusNorm( E ); if( frobE/frobM <= tol ) { if( ctrl.progress && commRank == 0 ) cout << "Converged after " << numIts << " iterations and " << numPrimalIts << " primal iterations with rank=" << rank << ", numNonzeros=" << numNonzeros << " and " << "|| E ||_F / || M ||_F = " << frobE/frobM << ", " << mpi::Time()-startTime << " total secs" << endl; break; } else if( numIts >= ctrl.maxIts ) { if( ctrl.progress && commRank == 0 ) cout << "Aborting after " << numIts << " iterations and " << mpi::Time()-startTime << " total secs" << endl; break; } else { if( ctrl.progress && commRank == 0 ) cout << numPrimalIts << ": || E ||_F / || M ||_F = " << frobE/frobM << ", rank=" << rank << ", numNonzeros=" << numNonzeros << ", " << mpi::Time()-startTime << " total secs" << endl; } // Y := Y + beta E Axpy( beta, E, Y ); beta *= ctrl.rho; } }
inline void ADMM ( const ElementalMatrix<F>& MPre, ElementalMatrix<F>& LPre, ElementalMatrix<F>& SPre, const RPCACtrl<Base<F>>& ctrl ) { DistMatrixReadProxy<F,F,MC,MR> MProx( MPre ); DistMatrixWriteProxy<F,F,MC,MR> LProx( LPre ), SProx( SPre ); auto& M = MProx.GetLocked(); auto& L = LProx.Get(); auto& S = SProx.Get(); typedef Base<F> Real; const Int m = M.Height(); const Int n = M.Width(); const int commRank = mpi::Rank( M.Grid().Comm() ); // If tau is not specified, then set it to 1/sqrt(max(m,n)) const Base<F> tau = ( ctrl.tau <= Real(0) ? Real(1)/sqrt(Real(Max(m,n))) : ctrl.tau ); if( ctrl.beta <= Real(0) ) LogicError("beta cannot be non-positive"); if( ctrl.tol <= Real(0) ) LogicError("tol cannot be non-positive"); const Base<F> beta = ctrl.beta; const Base<F> tol = ctrl.tol; const double startTime = mpi::Time(); DistMatrix<F> E( M.Grid() ), Y( M.Grid() ); Zeros( Y, m, n ); const Real frobM = FrobeniusNorm( M ); const Real maxM = MaxNorm( M ); if( ctrl.progress && commRank == 0 ) cout << "|| M ||_F = " << frobM << "\n" << "|| M ||_max = " << maxM << endl; Zeros( L, m, n ); Zeros( S, m, n ); Int numIts = 0; while( true ) { ++numIts; // ST_{tau/beta}(M - L + Y/beta) S = M; S -= L; Axpy( F(1)/beta, Y, S ); SoftThreshold( S, tau/beta ); const Int numNonzeros = ZeroNorm( S ); // SVT_{1/beta}(M - S + Y/beta) L = M; L -= S; Axpy( F(1)/beta, Y, L ); Int rank; if( ctrl.usePivQR ) rank = SVT( L, Real(1)/beta, ctrl.numPivSteps ); else rank = SVT( L, Real(1)/beta ); // E := M - (L + S) E = M; E -= L; E -= S; const Real frobE = FrobeniusNorm( E ); if( frobE/frobM <= tol ) { if( ctrl.progress && commRank == 0 ) cout << "Converged after " << numIts << " iterations " << " with rank=" << rank << ", numNonzeros=" << numNonzeros << " and " << "|| E ||_F / || M ||_F = " << frobE/frobM << ", and " << mpi::Time()-startTime << " total secs" << endl; break; } else if( numIts >= ctrl.maxIts ) { if( ctrl.progress && commRank == 0 ) cout << "Aborting after " << numIts << " iterations and " << mpi::Time()-startTime << " total secs" << endl; break; } else { if( ctrl.progress && commRank == 0 ) cout << numIts << ": || E ||_F / || M ||_F = " << frobE/frobM << ", rank=" << rank << ", numNonzeros=" << numNonzeros << ", " << mpi::Time()-startTime << " total secs" << endl; } // Y := Y + beta E Axpy( beta, E, Y ); } }