Пример #1
0
Base<F> Norm( const Matrix<F>& A, NormType type )
{
    DEBUG_CSE
    Base<F> norm = 0;
    switch( type )
    {
    // The following norms are rather cheap to compute
    case ENTRYWISE_ONE_NORM:
        norm = EntrywiseNorm( A, Base<F>(1) );
        break;
    case FROBENIUS_NORM: 
        norm = FrobeniusNorm( A );
        break;
    case INFINITY_NORM:
        norm = InfinityNorm( A );
        break;
    case MAX_NORM:
        norm = MaxNorm( A );
        break;
    case ONE_NORM:
        norm = OneNorm( A );
        break;
    // The following two norms make use of an SVD
    case NUCLEAR_NORM:
        norm = NuclearNorm( A );
        break;
    case TWO_NORM:
        norm = TwoNorm( A );
        break;
    }
    return norm;
}
Пример #2
0
void FrobeniusProx( AbstractDistMatrix<Field>& A, const Base<Field>& tau )
{
    EL_DEBUG_CSE
    const Base<Field> frobNorm = FrobeniusNorm( A );
    if( frobNorm > 1/tau )
        A *= 1-1/(tau*frobNorm);
    else
        Zero( A );
}
Пример #3
0
Base<Field> TransposedCoordinatesToNorm
( const Matrix<Base<Field>>& d,
  const Matrix<Field>& NTrans,
  const Matrix<Field>& v )
{
    EL_DEBUG_CSE
    Matrix<Field> z( v );
    Trmv( LOWER, TRANSPOSE, UNIT, NTrans, z );
    DiagonalScale( LEFT, NORMAL, d, z );
    return FrobeniusNorm( z );
}
Пример #4
0
Base<Field> CoordinatesToNorm
( const Matrix<Base<Field>>& d,
  const Matrix<Field>& N,
  const Matrix<Field>& v )
{
    EL_DEBUG_CSE
    Matrix<Field> z( v );
    Trmv( UPPER, NORMAL, UNIT, N, z );
    DiagonalScale( LEFT, NORMAL, d, z );
    return FrobeniusNorm( z );
}
Пример #5
0
int main(int argc, char *argv[])
{
	// tests();
	// srand(time(10));
	srand(10);
	if(argc < 4)
	{
		std::cout << "Input arguments:\n\t1: Filename for A matrix (as in A ~= WH)\n\t2: New desired dimension\n\t3: Max NMF iterations\n\t4: Max NNLS iterations\n\t5 (optional): delimiter (space is default)\n";
	}
	else
	{
		std::string filename = argv[1];
		int newDimension = atoi(argv[2]);
		int max_iter_nmf = atoi(argv[3]);
		int max_iter_nnls = atoi(argv[4]);
		char delimiter = (argc > 5) ? *argv[5] : ' ';

		DenseMatrix* A = readMatrix(filename,delimiter);
		A->copyColumnToRow();
		printf("Sparsity of A: %f\n",sparsity(A));

		DenseMatrix W = DenseMatrix(A->rows,newDimension);
		DenseMatrix H = DenseMatrix(newDimension,A->cols);
		NMF_Input input = NMF_Input(&W,&H,A,max_iter_nmf,max_iter_nnls);

		std::cout << "Starting NMF computation." << std::endl;
		std::clock_t start = std::clock();
		double duration;
		// nmf_cpu(input);
		nmf_cpu_profile(input);
		duration = ( std::clock() - start ) / (double) CLOCKS_PER_SEC;
		std::cout << "NMF computation complete. Time: " << duration << " s." << std::endl;

		W.copyColumnToRow();
		dtype AF = FrobeniusNorm(A);
		dtype WH_AF = Fnorm(W,H,*A);
		printf("Objective value: %f\n",WH_AF/AF);
		// DenseMatrix z1 = DenseMatrix(A->rows,newDimension);
		// DenseMatrix z2 = DenseMatrix(newDimension,A->cols);
		// printf("Calculated solution approximate Frobenius norm: %f\n",Fnorm(z1,z2,*A));
		// printcolmajor(H.colmajor,H.rows,H.cols);
		if(A) delete A;
	}
	return 0;
}
Пример #6
0
/* Returns the Matrix A diagonalized. The Matrix V is such that        *
 * V'*A*V is diagonal                                                  */
void Jacobi(Matrix *A, Matrix *V, double tolerance)
{
  register int i,j,N ;
  h_schur S ;
  int itmax=1000;
  int iter = 0 ;
  register double eps,off,old_off ;
  N = A->N ;
  /* Initialize V to the unit matrix */
  for(i=0;i<N;i++)
    {
      V->M[i][i].real = 1.0 ;
      V->M[i][i].imag = 0.0 ;
      for(j=i+1;j<N;j++)
	V->M[i][j].real=V->M[i][j].imag=V->M[j][i].real=V->M[j][i].imag = 0.0 ;
    }
  
  eps = FrobeniusNorm(A)*tolerance ;
#ifdef DEBUG
  printf("In jacobi::Jacobi -- convergence eps: %g\n",eps) ;
  printf("%i off(A): %g\n", iter, OffDiag(A) ) ;
#endif
  old_off  = 1.0e+32 ;
  off = OffDiag(A) ;
  while((off>eps)&&(fabs(old_off-off)>eps)&&(iter<itmax))
    {
      iter++ ;
      for(i=0;i<N;i++)
	for(j=i+1;j<N;j++)
	  {
	    HermitianSchur(A, i, j, &S) ;
	    rightMultiplySchur(A, &S) ;
	    leftMultiplySchur(A, &S) ;
	    rightMultiplySchur(V, &S) ;
	  }
      old_off = off ;
      off = OffDiag(A) ;
#ifdef DEBUG
      printf("%i off(A): %g\n", iter, off ) ;
#endif
    }
if(iter==itmax)printf("Jacobi didn't converge in %d steps\n",iter);
}
Пример #7
0
   which can be found in the LICENSE file in the root directory, or at 
   http://opensource.org/licenses/BSD-2-Clause
*/
#include "El.hpp"

// The Frobenius norm prox returns the solution to
//     arg min || A ||_F + tau/2 || A - A0 ||_F^2
//        A

namespace El {

template<typename F>
void FrobeniusProx( Matrix<F>& A, Base<F> tau )
{
    DEBUG_ONLY(CSE cse("FrobeniusProx"))
    const Base<F> frobNorm = FrobeniusNorm( A );
    if( frobNorm > 1/tau )
        A *= 1-1/(tau*frobNorm);
    else
        Zero( A );
}

template<typename F>
void FrobeniusProx( AbstractDistMatrix<F>& A, Base<F> tau )
{
    DEBUG_ONLY(CSE cse("FrobeniusProx"))
    const Base<F> frobNorm = FrobeniusNorm( A );
    if( frobNorm > 1/tau )
        A *= 1-1/(tau*frobNorm);
    else
        Zero( A );
Пример #8
0
   which can be found in the LICENSE file in the root directory, or at 
   http://opensource.org/licenses/BSD-2-Clause
*/
#pragma once
#ifndef EL_CONDITION_FROBENIUS_HPP
#define EL_CONDITION_FROBENIUS_HPP

namespace El {

template<typename F> 
Base<F> FrobeniusCondition( const Matrix<F>& A )
{
    DEBUG_ONLY(CallStackEntry cse("FrobeniusCondition"))
    typedef Base<F> Real;
    Matrix<F> B( A );
    const Real oneNorm = FrobeniusNorm( B );
    try { Inverse( B ); }
    catch( SingularMatrixException& e )
    { return std::numeric_limits<Real>::infinity(); }
    const Real oneNormInv = FrobeniusNorm( B );
    return oneNorm*oneNormInv;
}

template<typename F> 
Base<F> FrobeniusCondition( const AbstractDistMatrix<F>& A )
{
    DEBUG_ONLY(CallStackEntry cse("FrobeniusCondition"))
    typedef Base<F> Real;
    DistMatrix<F> B( A );
    const Real oneNorm = FrobeniusNorm( B );
    try { Inverse( B ); }
Пример #9
0
bool LatticeCoordinates
( const Matrix<F>& B,
  const Matrix<F>& y,
        Matrix<F>& x ) 
{
    DEBUG_CSE
    typedef Base<F> Real;
    const Int m = B.Height();
    const Int n = B.Width();
    if( y.Height() != m || y.Width() != 1 )
        LogicError("y should have been an ",m," x 1 vector");

    if( FrobeniusNorm(y) == Real(0) )
    {
        Zeros( x, n, 1 );
        return true;
    }
    
    Matrix<F> BRed( B );
    Matrix<F> UB, RB;
    auto infoB = LLL( BRed, UB, RB );
    auto MB = BRed( ALL, IR(0,infoB.rank) );

    Matrix<F> A;
    Zeros( A, m, infoB.rank+1 );
    {
        auto AL = A( ALL, IR(0,infoB.rank) ); 
        auto aR = A( ALL, IR(infoB.rank) );
        AL = MB;
        aR = y;
    }
    // Reduce A in-place
    Matrix<F> UA, RA;
    auto infoA = LLL( A, UA, RA );
    if( infoA.nullity != 1 )
        return false;

    // Solve for x_M such that M_B x_M = y
    // NOTE: The last column of U_A should hold the coordinates of the single
    //       member of the null-space of (the original) A
    Matrix<F> xM;
    xM = UA( IR(0,infoA.rank), IR(infoB.rank) );
    const F gamma = UA(infoA.rank,infoB.rank);
    if( Abs(gamma) != Real(1) )
        LogicError("Invalid member of null space");
    else
        xM *= -Conj(gamma);

    // Map xM back to the original coordinates using the portion of the 
    // unimodular transformation of B (U_B) which produced the image of B 
    auto UBM = UB( ALL, IR(0,infoB.rank) );
    Zeros( x, n, 1 );
    Gemv( NORMAL, F(1), UBM, xM, F(0), x );
    
    /*
    if( infoB.nullity != 0 )
    {
        Matrix<F> C;
        Zeros( C, m, infoB.nullity+1 );
        auto cL = C( ALL, IR(infoB.rank-1) );
        auto CR = C( ALL, IR(infoB.rank,END) );

        // Reduce the kernel of B
        CR = UB( ALL, IR(infoB.rank,END) );
        LLL( CR );

        // Attempt to reduce the (reduced) kernel out of the coordinates
        // TODO: Which column to grab from the result?!?
        cL = x;
        LLL( C );
        x = cL;
    }
    */

    return true;
}
Пример #10
0
Int ADMM
( const Matrix<Real>& A,
  const Matrix<Real>& b,
  const Matrix<Real>& c,
        Matrix<Real>& z,
  const ADMMCtrl<Real>& ctrl )
{
    EL_DEBUG_CSE

    // Cache a custom partially-pivoted LU factorization of
    //    |  rho*I   A^H | = | B11  B12 |
    //    |  A       0   |   | B21  B22 |
    // by (justifiably) avoiding pivoting in the first n steps of
    // the factorization, so that
    //    [I,rho*I] = lu(rho*I).
    // The factorization would then proceed with
    //    B21 := B21 U11^{-1} = A (rho*I)^{-1} = A/rho
    //    B12 := L11^{-1} B12 = I A^H = A^H.
    // The Schur complement would then be
    //    B22 := B22 - B21 B12 = 0 - (A*A^H)/rho.
    // We then factor said matrix with LU with partial pivoting and
    // swap the necessary rows of B21 in order to implicitly commute
    // the row pivots with the Gauss transforms in the manner standard
    // for GEPP. Unless A A' is singular, pivoting should not be needed,
    // as Cholesky factorization of the negative matrix should be valid.
    //
    // The result is the factorization
    //   | I 0   | | rho*I A^H | = | I   0   | | rho*I U12 |,
    //   | 0 P22 | | A     0   |   | L21 L22 | | 0     U22 |
    // where [L22,U22] are stored within B22.
    Matrix<Real> U12, L21, B22, bPiv;
    Adjoint( A, U12 );
    L21 = A;
    L21 *= 1/ctrl.rho;
    Herk( LOWER, NORMAL, -1/ctrl.rho, A, B22 );
    MakeHermitian( LOWER, B22 );
    // TODO: Replace with sparse-direct Cholesky version?
    Permutation P2;
    LU( B22, P2 );
    P2.PermuteRows( L21 );
    bPiv = b;
    P2.PermuteRows( bPiv );

    // Possibly form the inverse of L22 U22
    Matrix<Real> X22;
    if( ctrl.inv )
    {
        X22 = B22;
        MakeTrapezoidal( LOWER, X22 );
        FillDiagonal( X22, Real(1) );
        TriangularInverse( LOWER, UNIT, X22 );
        Trsm( LEFT, UPPER, NORMAL, NON_UNIT, Real(1), B22, X22 );
    }

    Int numIter=0;
    const Int m = A.Height();
    const Int n = A.Width();
    Matrix<Real> g, xTmp, y, t;
    Zeros( g, m+n, 1 );
    PartitionDown( g, xTmp, y, n );
    Matrix<Real> x, u, zOld, xHat;
    Zeros( z, n, 1 );
    Zeros( u, n, 1 );
    Zeros( t, n, 1 );
    while( numIter < ctrl.maxIter )
    {
        zOld = z;

        // Find x from
        //  | rho*I  A^H | | x | = | rho*(z-u)-c |
        //  | A      0   | | y |   | b           |
        // via our cached custom factorization:
        //
        // |x| = inv(U) inv(L) P' |rho*(z-u)-c|
        // |y|                    |b          |
        //     = |rho*I U12|^{-1} |I   0  | |I 0   | |rho*(z-u)-c|
        //     = |0     U22|      |L21 L22| |0 P22'| |b          |
        //     = "                        " |rho*(z-u)-c|
        //                                  | P22' b    |
        xTmp = z;
        xTmp -= u;
        xTmp *= ctrl.rho;
        xTmp -= c;
        y = bPiv;
        Gemv( NORMAL, Real(-1), L21, xTmp, Real(1), y );
        if( ctrl.inv )
        {
            Gemv( NORMAL, Real(1), X22, y, t );
            y = t;
        }
        else
        {
            Trsv( LOWER, NORMAL, UNIT, B22, y );
            Trsv( UPPER, NORMAL, NON_UNIT, B22, y );
        }
        Gemv( NORMAL, Real(-1), U12, y, Real(1), xTmp );
        xTmp *= 1/ctrl.rho;

        // xHat := alpha*x + (1-alpha)*zOld
        xHat = xTmp;
        xHat *= ctrl.alpha;
        Axpy( 1-ctrl.alpha, zOld, xHat );

        // z := pos(xHat+u)
        z = xHat;
        z += u;
        LowerClip( z, Real(0) );

        // u := u + (xHat-z)
        u += xHat;
        u -= z;

        const Real objective = Dot( c, xTmp );

        // rNorm := || x - z ||_2
        t = xTmp;
        t -= z;
        const Real rNorm = FrobeniusNorm( t );
        // sNorm := |rho| || z - zOld ||_2
        t = z;
        t -= zOld;
        const Real sNorm = Abs(ctrl.rho)*FrobeniusNorm( t );

        const Real epsPri = Sqrt(Real(n))*ctrl.absTol +
            ctrl.relTol*Max(FrobeniusNorm(xTmp),FrobeniusNorm(z));
        const Real epsDual = Sqrt(Real(n))*ctrl.absTol +
            ctrl.relTol*Abs(ctrl.rho)*FrobeniusNorm(u);

        if( ctrl.print )
        {
            t = xTmp;
            LowerClip( t, Real(0) );
            t -= xTmp;
            const Real clipDist = FrobeniusNorm( t );
            cout << numIter << ": "
              << "||x-z||_2=" << rNorm << ", "
              << "epsPri=" << epsPri << ", "
              << "|rho| ||z-zOld||_2=" << sNorm << ", "
              << "epsDual=" << epsDual << ", "
              << "||x-Pos(x)||_2=" << clipDist << ", "
              << "c'x=" << objective << endl;
        }
        if( rNorm < epsPri && sNorm < epsDual )
            break;
        ++numIter;
    }
    if( ctrl.maxIter == numIter )
        cout << "ADMM failed to converge" << endl;
    x = xTmp;
    return numIter;
}
Пример #11
0
    void Flush()
    {
        if( numQueued_ == 0 )
            return;

        auto YActive = Y_( ALL, IR(0,numQueued_) );

        Matrix<Base<Field>> colNorms;
        if( useTranspose_ )
        {
            // TODO(poulson): Add this as an option
            /*
            Timer timer;
            timer.Start();
            BatchTransposedSparseToCoordinates
            ( NTrans_, YActive, VCand_, blocksize_ );
            const double transformTime = timer.Stop();
            const double n = YActive.Height();
            const double transformGflops =
              double(numQueued_)*n*n/(1.e9*transformTime);
            Output
            (numQueued_," transforms: ",timer.Stop()," seconds (",
             transformGflops," GFlop/s");
            timer.Start();
            colNorms =
              BatchTransposedCoordinatesToNorms
              ( d_, NTrans_, VCand_, insertionBound_ );
            const double normTime = timer.Stop();
            const double normGflops = double(numQueued_)*n*n/(1.e9*normTime);
            Output
            (numQueued_," norms: ",timer.Stop()," seconds (",
             normGflops," GFlop/s");
            */

            BatchTransposedSparseToCoordinates
            ( NTrans_, YActive, VCand_, blocksize_ );
            colNorms =
              BatchTransposedCoordinatesToNorms
              ( d_, NTrans_, VCand_, insertionBound_ );
        }
        else
        {
            BatchSparseToCoordinates( N_, YActive, VCand_, blocksize_ );
            colNorms =
              BatchCoordinatesToNorms( d_, N_, VCand_, insertionBound_ );
        }

        for( Int j=0; j<numQueued_; ++j )
        {
            for( Int k=0; k<insertionBound_; ++k )
            {
                const Base<Field> bNorm = colNorms(j,k);
                if( bNorm < normUpperBounds_(k) && bNorm != Base<Field>(0) )
                {
                    const Range<Int> subInd(k,END);

                    auto y = YActive(subInd,IR(j));
                    auto vCand = VCand_(subInd,IR(j));

                    Output
                    ("normUpperBound=",normUpperBounds_(k),
                     ", bNorm=",bNorm,", k=",k);
                    Print( y, "y" );

                    // Check that the reverse transformation holds
                    Matrix<Field> yCheck;
                    CoordinatesToSparse( N_(subInd,subInd), vCand, yCheck );
                    yCheck -= y;
                    if( FrobeniusNorm(yCheck) != Base<Field>(0) )
                    {
                        Print( B_(ALL,subInd), "B" );
                        Print( d_(subInd,ALL), "d" );
                        Print( N_(subInd,subInd), "N" );
                        Print( vCand, "vCand" );
                        Print( yCheck, "eCheck" );
                        LogicError("Invalid sparse transformation");
                    }

                    Copy( vCand, v_ );
                    Print( v_, "v" );

                    Matrix<Field> b;
                    Zeros( b, B_.Height(), 1 );
                    Gemv( NORMAL, Field(1), B_(ALL,subInd), v_, Field(0), b );
                    Print( b, "b" );

                    normUpperBounds_(k) = bNorm;
                    foundVector_ = true;
                    insertionBound_ = k+1;
                }
                // TODO(poulson): Keep track of 'stock' vectors?
            }
        }
        numQueued_ = 0;
        Zero( Y_ );
    }
Пример #12
0
QDWHInfo QDWHInner( Matrix<F>& A, Base<F> sMinUpper, const QDWHCtrl& ctrl )
{
    EL_DEBUG_CSE
    typedef Base<F> Real;
    typedef Complex<Real> Cpx;
    const Int m = A.Height();
    const Int n = A.Width();
    const Real oneThird = Real(1)/Real(3);
    if( m < n )
        LogicError("Height cannot be less than width");

    QDWHInfo info;

    QRCtrl<Base<F>> qrCtrl;
    qrCtrl.colPiv = ctrl.colPiv;

    const Real eps = limits::Epsilon<Real>();
    const Real tol = 5*eps;
    const Real cubeRootTol = Pow(tol,oneThird);
    Real L = sMinUpper / Sqrt(Real(n));

    Real frobNormADiff;
    Matrix<F> ALast, ATemp, C;
    Matrix<F> Q( m+n, n );
    auto QT = Q( IR(0,m  ), ALL );
    auto QB = Q( IR(m,END), ALL );
    while( info.numIts < ctrl.maxIts )
    {
        ALast = A;

        Real L2;
        Cpx dd, sqd;
        if( Abs(1-L) < tol )
        {
            L2 = 1;
            dd = 0;
            sqd = 1;
        }
        else
        {
            L2 = L*L;
            dd = Pow( 4*(1-L2)/(L2*L2), oneThird );
            sqd = Sqrt( Real(1)+dd );
        }
        const Cpx arg = Real(8) - Real(4)*dd + Real(8)*(2-L2)/(L2*sqd);
        const Real a = (sqd + Sqrt(arg)/Real(2)).real();
        const Real b = (a-1)*(a-1)/4;
        const Real c = a+b-1;
        const Real alpha = a-b/c;
        const Real beta = b/c;

        L = L*(a+b*L2)/(1+c*L2);

        if( c > 100 )
        {
            //
            // The standard QR-based algorithm
            //
            QT = A;
            QT *= Sqrt(c);
            MakeIdentity( QB );
            qr::ExplicitUnitary( Q, true, qrCtrl );
            Gemm( NORMAL, ADJOINT, F(alpha/Sqrt(c)), QT, QB, F(beta), A );
            ++info.numQRIts;
        }
        else
        {
            //
            // Use faster Cholesky-based algorithm since A is well-conditioned
            //
            Identity( C, n, n );
            Herk( LOWER, ADJOINT, c, A, Real(1), C );
            Cholesky( LOWER, C );
            ATemp = A;
            Trsm( RIGHT, LOWER, ADJOINT, NON_UNIT, F(1), C, ATemp );
            Trsm( RIGHT, LOWER, NORMAL, NON_UNIT, F(1), C, ATemp );
            A *= beta;
            Axpy( alpha, ATemp, A );
            ++info.numCholIts;
        }

        ++info.numIts;
        ALast -= A;
        frobNormADiff = FrobeniusNorm( ALast );
        if( frobNormADiff <= cubeRootTol && Abs(1-L) <= tol )
            break;
    }
    return info;
}
Пример #13
0
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 );
    }
}
Пример #14
0
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;
    }
}
Пример #15
0
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 );
    }
}