Int ZeroNorm( const AbstractDistMatrix<T>& A, Base<T> tol ) { DEBUG_ONLY(CSE cse("ZeroNorm")) Int numNonzeros; if( A.Participating() ) { const Int numLocalNonzeros = ZeroNorm( A.LockedMatrix(), tol ); numNonzeros = mpi::AllReduce( numLocalNonzeros, A.DistComm() ); } mpi::Broadcast( numNonzeros, A.Root(), A.CrossComm() ); return numNonzeros; }
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 Matrix<F>& M, Matrix<F>& L, Matrix<F>& S, const RPCACtrl<Base<F>>& ctrl ) { typedef Base<F> Real; const Int m = M.Height(); const Int n = M.Width(); // 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(); Matrix<F> E, Y; Zeros( Y, m, n ); const Real frobM = FrobeniusNorm( M ); const Real maxM = MaxNorm( M ); if( ctrl.progress ) 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 ) 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 ) cout << "Aborting after " << numIts << " iterations and " << mpi::Time()-startTime << " total secs" << endl; break; } else { if( ctrl.progress ) 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 ); } }
inline void ADMM ( const AbstractDistMatrix<F>& MPre, AbstractDistMatrix<F>& LPre, AbstractDistMatrix<F>& SPre, const RPCACtrl<Base<F>>& ctrl ) { auto MPtr = ReadProxy<F,MC,MR>( &MPre ); auto& M = *MPtr; auto LPtr = WriteProxy<F,MC,MR>( &LPre ); auto& L = *LPtr; auto SPtr = WriteProxy<F,MC,MR>( &SPre ); auto& S = *SPtr; 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; Axpy( F(-1), L, S ); Axpy( F(1)/beta, Y, S ); SoftThreshold( S, tau/beta ); const Int numNonzeros = ZeroNorm( S ); // SVT_{1/beta}(M - S + Y/beta) L = M; Axpy( F(-1), S, L ); 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; Axpy( F(-1), L, E ); Axpy( F(-1), S, E ); 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 ); } }