UnitaryCoherence( DistMatrix<F>& U ) { #ifndef RELEASE CallStackEntry entry("UnitaryCoherence"); #endif typedef BASE(F) R; const Grid& grid = U.Grid(); const Int n = U.Height(); const Int r = U.Width(); // Z := U U' in n^2 r work DistMatrix<F> Z( grid ); Herk( UPPER, NORMAL, F(1), U, Z ); // Now make Z explicitly Hermitian so that our job is easier MakeHermitian( UPPER, Z ); // Compute the maximum column two-norm squared const Int localWidth = Z.LocalWidth(); const Int localHeight = Z.LocalHeight(); std::vector<R> normsSquared( localWidth ); for( Int jLocal=0; jLocal<localWidth; ++jLocal ) { const R localNorm = blas::Nrm2( localHeight, Z.LockedBuffer(0,jLocal), 1 ); normsSquared[jLocal] = localNorm*localNorm; } mpi::AllReduce( &normsSquared[0], localWidth, grid.ColComm() ); R maxLocalNormSquared = *std::max_element( normsSquared.begin(), normsSquared.end() ); const R maxNormSquared = mpi::AllReduce( maxLocalNormSquared, mpi::MAX, grid.RowComm() ); return (n*maxNormSquared)/r; }
void QP ( const SparseMatrix<Real>& A, const Matrix<Real>& B, Matrix<Real>& X, const qp::direct::Ctrl<Real>& ctrl ) { DEBUG_CSE const Int n = A.Width(); const Int k = B.Width(); SparseMatrix<Real> Q, AHat; Matrix<Real> bHat, c; Herk( LOWER, ADJOINT, Real(1), A, Q ); MakeHermitian( LOWER, Q ); Zeros( AHat, 0, n ); Zeros( bHat, 0, 1 ); Zeros( X, n, k ); Matrix<Real> y, z; for( Int j=0; j<k; ++j ) { auto x = X( ALL, IR(j) ); auto b = B( ALL, IR(j) ); Zeros( c, n, 1 ); Multiply( ADJOINT, Real(-1), A, b, Real(0), c ); El::QP( Q, AHat, bHat, c, x, y, z, ctrl ); } }
UnitaryCoherence( Matrix<F>& U ) { #ifndef RELEASE CallStackEntry entry("UnitaryCoherence"); #endif typedef BASE(F) R; const Int n = U.Height(); const Int r = U.Width(); // Z := U U' in n^2 r work Matrix<F> Z; Herk( UPPER, NORMAL, F(1), U, Z ); // Now make Z explicitly Hermitian so that our job is easier MakeHermitian( UPPER, Z ); // Compute the maximum column two-norm R maxColNorm = 0; for( Int j=0; j<n; ++j ) { const R colNorm = blas::Nrm2( n, Z.LockedBuffer(0,j), 1 ); maxColNorm = std::max( colNorm, maxColNorm ); } return (n*maxColNorm*maxColNorm)/r; }
QDWHInfo QDWH( Matrix<F>& A, Matrix<F>& P, const QDWHCtrl& ctrl ) { EL_DEBUG_CSE Matrix<F> ACopy( A ); auto info = QDWH( A, ctrl ); Zeros( P, A.Height(), A.Height() ); Trrk( LOWER, NORMAL, NORMAL, F(1), A, ACopy, F(0), P ); MakeHermitian( LOWER, P ); return info; }
inline void HermitianSVD ( UpperOrLower uplo, DistMatrix<F>& A, DistMatrix<BASE(F),VR,STAR>& s, DistMatrix<F>& U, DistMatrix<F>& V ) { #ifndef RELEASE CallStackEntry entry("HermitianSVD"); #endif #ifdef HAVE_PMRRR typedef BASE(F) R; // Grab an eigenvalue decomposition of A HermitianEig( uplo, A, s, V ); // Redistribute the singular values into an [MR,* ] distribution const Grid& grid = A.Grid(); DistMatrix<R,MR,STAR> s_MR_STAR( grid ); s_MR_STAR.AlignWith( V.DistData() ); s_MR_STAR = s; // Set the singular values to the absolute value of the eigenvalues const Int numLocalVals = s.LocalHeight(); for( Int iLoc=0; iLoc<numLocalVals; ++iLoc ) { const R sigma = s.GetLocal(iLoc,0); s.SetLocal(iLoc,0,Abs(sigma)); } // Copy V into U (flipping the sign as necessary) U.AlignWith( V ); U.ResizeTo( V.Height(), V.Width() ); const Int localHeight = V.LocalHeight(); const Int localWidth = V.LocalWidth(); for( Int jLoc=0; jLoc<localWidth; ++jLoc ) { const R sigma = s_MR_STAR.GetLocal( jLoc, 0 ); F* UCol = U.Buffer( 0, jLoc ); const F* VCol = V.LockedBuffer( 0, jLoc ); if( sigma >= 0 ) for( Int iLoc=0; iLoc<localHeight; ++iLoc ) UCol[iLoc] = VCol[iLoc]; else for( Int iLoc=0; iLoc<localHeight; ++iLoc ) UCol[iLoc] = -VCol[iLoc]; } #else U = A; MakeHermitian( uplo, U ); SVD( U, s, V ); #endif // ifdef HAVE_PMRRR }
inline void HermitianSVD ( UpperOrLower uplo, Matrix<F>& A, Matrix<BASE(F)>& s ) { #ifndef RELEASE CallStackEntry entry("HermitianSVD"); #endif #if 1 // Grab the eigenvalues of A HermitianEig( uplo, A, s ); // Set the singular values to the absolute value of the eigenvalues for( Int i=0; i<s.Height(); ++i ) s.Set(i,0,Abs(s.Get(i,0))); #else MakeHermitian( uplo, A ); SVD( A, s ); #endif }
inline void HPSDCholesky( UpperOrLower uplo, DistMatrix<R>& A ) { #ifndef RELEASE CallStackEntry entry("HPSDCholesky"); #endif HPSDSquareRoot( uplo, A ); MakeHermitian( uplo, A ); if( uplo == LOWER ) { LQ( A ); MakeTriangular( LOWER, A ); } else { QR( A ); MakeTriangular( UPPER, A ); } }
QDWHInfo QDWH ( AbstractDistMatrix<F>& APre, AbstractDistMatrix<F>& PPre, const QDWHCtrl& ctrl ) { EL_DEBUG_CSE DistMatrixReadWriteProxy<F,F,MC,MR> AProx( APre ); DistMatrixWriteProxy<F,F,MC,MR> PProx( PPre ); auto& A = AProx.Get(); auto& P = PProx.Get(); DistMatrix<F> ACopy( A ); auto info = QDWH( A, ctrl ); Zeros( P, A.Height(), A.Height() ); Trrk( LOWER, NORMAL, NORMAL, F(1), A, ACopy, F(0), P ); MakeHermitian( LOWER, P ); return info; }
void QP ( const DistSparseMatrix<Real>& A, const DistMultiVec<Real>& B, DistMultiVec<Real>& X, const qp::direct::Ctrl<Real>& ctrl ) { DEBUG_CSE const Int m = A.Height(); const Int n = A.Width(); const Int k = B.Width(); mpi::Comm comm = A.Comm(); DistSparseMatrix<Real> Q(comm), AHat(comm); DistMultiVec<Real> bHat(comm), c(comm); Herk( LOWER, ADJOINT, Real(1), A, Q ); MakeHermitian( LOWER, Q ); Zeros( AHat, 0, n ); Zeros( bHat, 0, 1 ); Zeros( X, n, k ); DistMultiVec<Real> q(comm), y(comm), z(comm); auto& qLoc = q.Matrix(); auto& XLoc = X.Matrix(); auto& BLoc = B.LockedMatrix(); for( Int j=0; j<k; ++j ) { auto xLoc = XLoc( ALL, IR(j) ); auto bLoc = BLoc( ALL, IR(j) ); Zeros( c, n, 1 ); Zeros( q, m, 1 ); qLoc = bLoc; Multiply( ADJOINT, Real(-1), A, q, Real(0), c ); Zeros( q, n, 1 ); qLoc = xLoc; El::QP( Q, AHat, bHat, c, q, y, z, ctrl ); xLoc = qLoc; } }
void Covariance( const Matrix<F>& D, Matrix<F>& S ) { DEBUG_CSE const Int numObs = D.Height(); const Int n = D.Width(); // Compute the average column Matrix<F> ones, xMean; Ones( ones, numObs, 1 ); Gemv( TRANSPOSE, F(1)/F(numObs), D, ones, xMean ); // Subtract the mean from each column of D Matrix<F> DDev( D ); for( Int i=0; i<numObs; ++i ) blas::Axpy ( n, F(-1), xMean.LockedBuffer(), 1, DDev.Buffer(i,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 ValueInt<BASE(F)> QDWHDivide ( UpperOrLower uplo, DistMatrix<F>& A, DistMatrix<F>& G, bool returnQ=false ) { DEBUG_ONLY(CallStackEntry cse("herm_eig::QDWHDivide")) // G := sgn(G) // G := 1/2 ( G + I ) herm_polar::QDWH( uplo, G ); UpdateDiagonal( G, F(1) ); Scale( F(1)/F(2), G ); // Compute the pivoted QR decomposition of the spectral projection const Grid& g = A.Grid(); DistMatrix<F,MD,STAR> t(g); DistMatrix<Int,VR,STAR> p(g); elem::QR( G, t, p ); // A := Q^H A Q MakeHermitian( uplo, A ); const Base<F> oneA = OneNorm( A ); if( returnQ ) { ExpandPackedReflectors( LOWER, VERTICAL, CONJUGATED, 0, G, t ); DistMatrix<F> B(g); Gemm( ADJOINT, NORMAL, F(1), G, A, B ); Gemm( NORMAL, NORMAL, F(1), B, G, A ); } else { qr::ApplyQ( LEFT, ADJOINT, G, t, A ); qr::ApplyQ( RIGHT, NORMAL, G, t, A ); } // Return || E21 ||1 / || A ||1 and the chosen rank auto part = ComputePartition( A ); part.value /= oneA; return part; }
inline void HermitianSVD ( UpperOrLower uplo, Matrix<F>& A, Matrix<BASE(F)>& s, Matrix<F>& U, Matrix<F>& V ) { #ifndef RELEASE CallStackEntry entry("HermitianSVD"); #endif #if 1 typedef BASE(F) R; // Grab an eigenvalue decomposition of A HermitianEig( uplo, A, s, V ); // Set the singular values to the absolute value of the eigenvalues for( Int i=0; i<s.Height(); ++i ) s.Set(i,0,Abs(s.Get(i,0))); // Copy V into U (flipping the sign as necessary) const Int n = A.Height(); U.ResizeTo( n, n ); for( Int j=0; j<n; ++j ) { const R sigma = s.Get( j, 0 ); F* UCol = U.Buffer( 0, j ); const F* VCol = V.LockedBuffer( 0, j ); if( sigma >= 0 ) for( Int i=0; i<n; ++i ) UCol[i] = VCol[i]; else for( Int i=0; i<n; ++i ) UCol[i] = -VCol[i]; } #else U = A; MakeHermitian( uplo, U ); SVD( U, s, V ); #endif }
inline void HPSDCholesky( UpperOrLower uplo, DistMatrix<Complex<R> >& A ) { #ifndef RELEASE CallStackEntry entry("HPSDCholesky"); #endif HPSDSquareRoot( uplo, A ); MakeHermitian( uplo, A ); const Grid& g = A.Grid(); if( uplo == LOWER ) { DistMatrix<Complex<R>,MD,STAR> t(g); LQ( A, t ); MakeTriangular( LOWER, A ); } else { DistMatrix<Complex<R>,MD,STAR> t(g); QR( A, t ); MakeTriangular( UPPER, A ); } }
void HermitianSVD ( UpperOrLower uplo, Matrix<F>& A, Matrix<Base<F>>& s, Matrix<F>& U, Matrix<F>& V ) { DEBUG_ONLY(CallStackEntry cse("HermitianSVD")) #if 1 // Grab an eigenvalue decomposition of A HermitianEig( uplo, A, s, V ); // Copy V into U (flipping the sign as necessary) const Int n = A.Height(); U.Resize( n, n ); for( Int j=0; j<n; ++j ) { const Base<F> sigma = s.Get( j, 0 ); F* UCol = U.Buffer( 0, j ); const F* VCol = V.LockedBuffer( 0, j ); if( sigma >= 0 ) { for( Int i=0; i<n; ++i ) UCol[i] = VCol[i]; } else { for( Int i=0; i<n; ++i ) UCol[i] = -VCol[i]; s.Set( j, 0, -sigma ); } } // TODO: Descending sort of triplets #else U = A; MakeHermitian( uplo, U ); SVD( U, s, V ); #endif }
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 HermitianSVD ( UpperOrLower uplo, DistMatrix<F>& A, DistMatrix<BASE(F),VR,STAR>& s ) { #ifndef RELEASE CallStackEntry entry("HermitianSVD"); #endif #ifdef HAVE_PMRRR typedef BASE(F) R; // Grab the eigenvalues of A HermitianEig( uplo, A, s ); // Replace the eigenvalues with their absolute values const Int numLocalVals = s.LocalHeight(); for( Int iLoc=0; iLoc<numLocalVals; ++iLoc ) { const R sigma = s.GetLocal(iLoc,0); s.SetLocal(iLoc,0,Abs(sigma)); } #else MakeHermitian( uplo, A ); SVD( A, s ); #endif // ifdef HAVE_PMRRR }
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; }
void Wigner( ElementalMatrix<F>& A, Int n, F mean, Base<F> stddev ) { EL_DEBUG_CSE Gaussian( A, n, n, mean, stddev ); MakeHermitian( LOWER, A ); }
void Wigner( AbstractDistMatrix<F>& A, Int n, F mean, Base<F> stddev ) { DEBUG_ONLY(CSE cse("Wigner")) Gaussian( A, n, n, mean, stddev ); MakeHermitian( LOWER, A ); }