void HermitianPseudoinverse ( UpperOrLower uplo, ElementalMatrix<F>& APre, Base<F> tolerance ) { DEBUG_CSE typedef Base<F> Real; DistMatrixReadWriteProxy<F,F,MC,MR> AProx( APre ); auto& A = AProx.Get(); const Grid& g = A.Grid(); // Get the EVD of A // TODO: Use a relative eigenvalue lower-bound DistMatrix<Real,VR,STAR> w(g); DistMatrix<F> Z(g); HermitianEig( uplo, A, w, Z ); if( tolerance == Real(0) ) { // Set the tolerance equal to n ||A||_2 eps const Int n = Z.Height(); const Real eps = limits::Epsilon<Real>(); const Real twoNorm = MaxNorm( w ); tolerance = n*twoNorm*eps; } // Invert above the tolerance auto omegaMap = [=]( Real omega ) { return ( omega < tolerance ? Real(0) : 1/omega ); }; EntrywiseMap( w, function<Real(Real)>(omegaMap) ); // Form the pseudoinverse HermitianFromEVD( uplo, A, w, Z ); }
void HermitianSign ( UpperOrLower uplo, Matrix<Field>& A, const HermitianEigCtrl<Field>& ctrl ) { EL_DEBUG_CSE typedef Base<Field> Real; // Get the EVD of A Matrix<Real> w; Matrix<Field> Q; auto ctrlMod( ctrl ); ctrlMod.tridiagEigCtrl.sort = UNSORTED; HermitianEig( uplo, A, w, Q, ctrlMod ); const Int n = A.Height(); for( Int i=0; i<n; ++i ) { const Real omega = w(i); if( omega >= 0 ) w(i) = Real(1); else w(i) = Real(-1); } // Reform the Hermitian matrix with the modified eigenvalues HermitianFromEVD( uplo, A, w, Q ); }
void HermitianPseudoinverse ( UpperOrLower uplo, Matrix<F>& A, Base<F> tolerance ) { DEBUG_CSE typedef Base<F> Real; // Get the EVD of A // TODO: Use a relative eigenvalue lower bound Matrix<Real> w; Matrix<F> Z; HermitianEig( uplo, A, w, Z ); if( tolerance == Real(0) ) { // Set the tolerance equal to n ||A||_2 eps const Int n = Z.Height(); const Real eps = limits::Epsilon<Real>(); const Real twoNorm = MaxNorm( w ); tolerance = n*twoNorm*eps; } // Invert above the tolerance auto omegaMap = [=]( Real omega ) { return ( omega < tolerance ? Real(0) : 1/omega ); }; EntrywiseMap( w, function<Real(Real)>(omegaMap) ); // Form the pseudoinverse HermitianFromEVD( uplo, A, w, Z ); }
inline void HermitianSign( UpperOrLower uplo, Matrix<F>& A ) { #ifndef RELEASE CallStackEntry entry("HermitianSign"); #endif typedef BASE(F) R; // Get the EVD of A Matrix<R> w; Matrix<F> Z; HermitianEig( uplo, A, w, Z ); // Compute the two-norm of A as the maximum absolute value of its eigvals const R twoNorm = MaxNorm( w ); // Set the tolerance equal to n ||A||_2 eps, and invert values above it const int n = A.Height(); const R eps = lapack::MachineEpsilon<R>(); const R tolerance = n*twoNorm*eps; for( int i=0; i<n; ++i ) { const R omega = w.Get(i,0); if( Abs(omega) < tolerance ) w.Set(i,0,0); else if( omega > 0 ) w.Set(i,0,R(1)); else w.Set(i,0,R(-1)); } // Reform the Hermitian matrix with the modified eigenvalues hermitian_function::ReformHermitianMatrix( uplo, A, w, Z ); }
void HermitianSign ( UpperOrLower uplo, AbstractDistMatrix<Field>& APre, const HermitianEigCtrl<Field>& ctrl ) { EL_DEBUG_CSE DistMatrixReadWriteProxy<Field,Field,MC,MR> AProx( APre ); auto& A = AProx.Get(); // Get the EVD of A typedef Base<Field> Real; const Grid& g = A.Grid(); DistMatrix<Real,VR,STAR> w(g); DistMatrix<Field> Q(g); auto ctrlMod( ctrl ); ctrlMod.tridiagEigCtrl.sort = UNSORTED; HermitianEig( uplo, A, w, Q, ctrlMod ); const Int numLocalEigs = w.LocalHeight(); for( Int iLoc=0; iLoc<numLocalEigs; ++iLoc ) { const Real omega = w.GetLocal(iLoc,0); if( omega >= 0 ) w.SetLocal(iLoc,0,Real(1)); else w.SetLocal(iLoc,0,Real(-1)); } // Reform the Hermitian matrix with the modified eigenvalues HermitianFromEVD( uplo, A, w, Q ); }
inline void HermitianPseudoinverse ( UpperOrLower uplo, DistMatrix<Complex<R>,MC,MR>& A ) { #ifndef RELEASE PushCallStack("HermitianPseudoinverse"); #endif // Get the EVD of A const Grid& g = A.Grid(); DistMatrix<R,VR,STAR> w(g); DistMatrix<Complex<R>,MC,MR> Z(g); HermitianEig( uplo, A, w, Z ); // Compute the two-norm of A as the maximum absolute value of its // eigenvalues R maxLocalAbsEig = 0; const int localHeight = w.LocalHeight(); for( int iLocal=0; iLocal<localHeight; ++iLocal ) maxLocalAbsEig = std::max(maxLocalAbsEig,Abs(w.GetLocalEntry(iLocal,0))); R twoNorm; mpi::AllReduce( &maxLocalAbsEig, &twoNorm, 1, mpi::MAX, g.VCComm() ); // Set the tolerance equal to n ||A||_2 eps const int n = A.Height(); const R eps = lapack::MachineEpsilon<R>(); const R tolerance = n*twoNorm*eps; // Form the pseudoinverse hermitian_pseudoinverse::Functor<R> f( tolerance ); hermitian_function::ReformHermitianMatrix( uplo, A, w, Z, f ); #ifndef RELEASE PopCallStack(); #endif }
void SkewHermitianEig ( UpperOrLower uplo, const Matrix<F>& G, Matrix<Base<F>>& wImag, SortType sort, const HermitianEigSubset<Base<F>>& subset, const HermitianEigCtrl<Complex<Base<F>>>& ctrl ) { DEBUG_ONLY(CSE cse("SkewHermitianEig")) Matrix<Complex<Base<F>>> A; Copy( G, A ); ScaleTrapezoid( Complex<Base<F>>(0,-1), uplo, A ); HermitianEig( uplo, A, wImag, sort, subset, ctrl ); }
void SkewHermitianEig ( UpperOrLower uplo, const AbstractDistMatrix<F>& G, AbstractDistMatrix<Base<F>>& wImag, SortType sort, const HermitianEigSubset<Base<F>>& subset, const HermitianEigCtrl<Complex<Base<F>>>& ctrl ) { DEBUG_ONLY(CallStackEntry cse("SkewHermitianEig")) DistMatrix<Complex<Base<F>>> A(G.Grid()); Copy( G, A ); ScaleTrapezoid( Complex<Base<F>>(0,-1), uplo, A ); HermitianEig( uplo, A, wImag, sort, subset, ctrl ); }
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, DistMatrix<F>& A, DistMatrix<typename Base<F>::type,VR,STAR>& s, DistMatrix<F>& U, DistMatrix<F>& V ) { #ifndef RELEASE PushCallStack("HermitianSVD"); #endif typedef typename Base<F>::type 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 ); s_MR_STAR = s; // Set the singular values to the absolute value of the eigenvalues const int numLocalVals = s.LocalHeight(); for( int iLocal=0; iLocal<numLocalVals; ++iLocal ) { const R sigma = s.GetLocal(iLocal,0); s.SetLocal(iLocal,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 jLocal=0; jLocal<localWidth; ++jLocal ) { const R sigma = s_MR_STAR.GetLocal( jLocal, 0 ); F* UCol = U.LocalBuffer( 0, jLocal ); const F* VCol = V.LockedLocalBuffer( 0, jLocal ); if( sigma >= 0 ) for( int iLocal=0; iLocal<localHeight; ++iLocal ) UCol[iLocal] = VCol[iLocal]; else for( int iLocal=0; iLocal<localHeight; ++iLocal ) UCol[iLocal] = -VCol[iLocal]; } #ifndef RELEASE PopCallStack(); #endif }
void HermitianSign ( UpperOrLower uplo, ElementalMatrix<F>& APre, ElementalMatrix<F>& NPre, const HermitianEigCtrl<F>& ctrl ) { DEBUG_CSE DistMatrixReadWriteProxy<F,F,MC,MR> AProx( APre ); DistMatrixWriteProxy<F,F,MC,MR> NProx( NPre ); auto& A = AProx.Get(); auto& N = NProx.Get(); // Get the EVD of A typedef Base<F> Real; const Grid& g = A.Grid(); DistMatrix<Real,VR,STAR> w(g); DistMatrix<F> Q(g); auto ctrlMod( ctrl ); ctrlMod.tridiagEigCtrl.sort = UNSORTED; HermitianEig( uplo, A, w, Q, ctrlMod ); const Int n = A.Height(); const Int numLocalEigs = w.LocalHeight(); DistMatrix<Real,VR,STAR> wSgn(g), wAbs(g); wSgn.AlignWith( w ); wAbs.AlignWith( w ); wSgn.Resize( n, 1 ); wAbs.Resize( n, 1 ); for( Int iLoc=0; iLoc<numLocalEigs; ++iLoc ) { const Real omega = w.GetLocal(iLoc,0); if( omega >= 0 ) { wSgn.SetLocal(iLoc,0,Real(1)); wAbs.SetLocal(iLoc,0,omega); } else { wSgn.SetLocal(iLoc,0,Real(-1)); wAbs.SetLocal(iLoc,0,-omega); } } // Form the Hermitian matrix with the modified eigenvalues HermitianFromEVD( uplo, A, wSgn, Q ); HermitianFromEVD( uplo, N, wAbs, Q ); }
inline void HermitianPseudoinverse ( UpperOrLower uplo, DistMatrix<F>& A ) { #ifndef RELEASE PushCallStack("HermitianPseudoinverse"); #endif typedef typename Base<F>::type R; // Get the EVD of A const Grid& g = A.Grid(); DistMatrix<R,VR,STAR> w(g); DistMatrix<F> Z(g); HermitianEig( uplo, A, w, Z ); // Compute the two-norm of A as the maximum absolute value of its // eigenvalues R maxLocalAbsEig = 0; const int numLocalEigs = w.LocalHeight(); for( int iLocal=0; iLocal<numLocalEigs; ++iLocal ) { const R omega = w.GetLocal(iLocal,0); maxLocalAbsEig = std::max(maxLocalAbsEig,Abs(omega)); } R twoNorm; mpi::AllReduce( &maxLocalAbsEig, &twoNorm, 1, mpi::MAX, g.VCComm() ); // Set the tolerance equal to n ||A||_2 eps, and invert values above it const int n = A.Height(); const R eps = lapack::MachineEpsilon<R>(); const R tolerance = n*twoNorm*eps; for( int iLocal=0; iLocal<numLocalEigs; ++iLocal ) { const R omega = w.GetLocal(iLocal,0); if( Abs(omega) < tolerance ) w.SetLocal(iLocal,0,0); else w.SetLocal(iLocal,0,1/omega); } // Form the pseudoinverse hermitian_function::ReformHermitianMatrix( uplo, A, w, Z ); #ifndef RELEASE PopCallStack(); #endif }
inline void HPSDSquareRoot( UpperOrLower uplo, DistMatrix<R,MC,MR>& A ) { #ifndef RELEASE PushCallStack("HPSDSquareRoot"); #endif // Get the EVD of A const Grid& g = A.Grid(); DistMatrix<R,VR,STAR> w(g); DistMatrix<R,MC,MR> Z(g); HermitianEig( uplo, A, w, Z ); // Compute the two-norm of A as the maximum absolute value // of its eigenvalues R maxLocalAbsEig = 0; const int localHeight = w.LocalHeight(); for( int iLocal=0; iLocal<localHeight; ++iLocal ) maxLocalAbsEig = std::max(maxLocalAbsEig,Abs(w.GetLocalEntry(iLocal,0))); R twoNorm; mpi::AllReduce( &maxLocalAbsEig, &twoNorm, 1, mpi::MAX, g.VCComm() ); // Compute the smallest eigenvalue of A R minLocalEig = twoNorm; for( int iLocal=0; iLocal<localHeight; ++iLocal ) minLocalEig = std::min(minLocalEig,w.GetLocalEntry(iLocal,0)); R minEig; mpi::AllReduce( &minLocalEig, &minEig, 1, mpi::MIN, g.VCComm() ); // Set the tolerance equal to n ||A||_2 eps const int n = A.Height(); const R eps = lapack::MachineEpsilon<R>(); const R tolerance = n*twoNorm*eps; // Ensure that the minimum eigenvalue is not less than - n ||A||_2 eps if( minEig < -tolerance ) throw NonHPSDMatrixException(); // Form the pseudoinverse square_root::Functor<R> f( tolerance ); hermitian_function::ReformHermitianMatrix( uplo, A, w, Z, f ); #ifndef RELEASE PopCallStack(); #endif }
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 RealHermitianFunction ( UpperOrLower uplo, DistMatrix<R,MC,MR>& A, const RealFunctor& f ) { #ifndef RELEASE PushCallStack("RealHermitianFunction"); #endif if( A.Height() != A.Width() ) throw std::logic_error("Hermitian matrices must be square"); // Get the EVD of A const Grid& g = A.Grid(); DistMatrix<R,VR,STAR> w(g); DistMatrix<R,MC,MR> Z(g); HermitianEig( uplo, A, w, Z ); // Form the custom outer product, Z f(Omega) Z^T hermitian_function::ReformHermitianMatrix( uplo, A, w, Z, f ); #ifndef RELEASE PopCallStack(); #endif }
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 HermitianSingularValues ( UpperOrLower uplo, DistMatrix<F>& A, DistMatrix<typename Base<F>::type,VR,STAR>& s ) { #ifndef RELEASE PushCallStack("HermitianSingularValues"); #endif typedef typename Base<F>::type R; // Grab an eigenvalue decomposition of A HermitianEig( uplo, A, s ); // Replace the eigenvalues with their absolute values const int numLocalVals = s.LocalHeight(); for( int iLocal=0; iLocal<numLocalVals; ++iLocal ) { const R sigma = s.GetLocal(iLocal,0); s.SetLocal(iLocal,0,Abs(sigma)); } #ifndef RELEASE PopCallStack(); #endif }
void HermitianSVD ( UpperOrLower uplo, AbstractDistMatrix<F>& A, AbstractDistMatrix<Base<F>>& s, AbstractDistMatrix<F>& U, AbstractDistMatrix<F>& V ) { DEBUG_ONLY(CallStackEntry cse("HermitianSVD")) // Grab an eigenvalue decomposition of A HermitianEig( uplo, A, s, V ); // Copy V into U (flipping the sign as necessary) Copy( U, V ); typedef Base<F> Real; DistMatrix<Real,VR,STAR> sSgn( s ); auto sgnLambda = []( Real sigma ) { return Sgn(sigma,false); }; EntrywiseMap( sSgn, function<Real(Real)>(sgnLambda) ); DiagonalScale( RIGHT, NORMAL, sSgn, U ); // Set the singular values to the absolute value of the eigenvalues auto absLambda = []( Real sigma ) { return Abs(sigma); }; EntrywiseMap( s, function<Real(Real)>(absLambda) ); // TODO: Descending sort of triplets }
void HermitianSign ( UpperOrLower uplo, Matrix<Field>& A, Matrix<Field>& N, const HermitianEigCtrl<Field>& ctrl ) { EL_DEBUG_CSE typedef Base<Field> Real; // Get the EVD of A Matrix<Real> w; Matrix<Field> Q; auto ctrlMod( ctrl ); ctrlMod.tridiagEigCtrl.sort = UNSORTED; HermitianEig( uplo, A, w, Q, ctrlMod ); const Int n = A.Height(); Matrix<Real> wSgn( n, 1 ), wAbs( n, 1 ); for( Int i=0; i<n; ++i ) { const Real omega = w(i); if( omega >= 0 ) { wSgn(i) = Real(1); wAbs(i) = omega; } else { wSgn(i) = Real(-1); wAbs(i) = -omega; } } // Form the Hermitian matrices with modified eigenvalues HermitianFromEVD( uplo, A, wSgn, Q ); HermitianFromEVD( uplo, N, wAbs, Q ); }
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 }
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 }