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 }
void IndexDependentMap ( const DistMatrix<S,U,V,wrap>& A, DistMatrix<T,U,V,wrap>& B, function<T(Int,Int,const S&)> func ) { EL_DEBUG_CSE const Int mLoc = A.LocalHeight(); const Int nLoc = A.LocalWidth(); B.AlignWith( A.DistData() ); B.Resize( A.Height(), A.Width() ); auto& ALoc = A.LockedMatrix(); auto& BLoc = B.Matrix(); for( Int jLoc=0; jLoc<nLoc; ++jLoc ) { const Int j = A.GlobalCol(jLoc); for( Int iLoc=0; iLoc<mLoc; ++iLoc ) { const Int i = A.GlobalRow(iLoc); BLoc(iLoc,jLoc) = func(i,j,ALoc(iLoc,jLoc)); } } }
void TestCorrectness ( bool print, UpperOrLower uplo, const DistMatrix<F>& A, const DistMatrix<F,STAR,STAR>& t, DistMatrix<F>& AOrig ) { typedef BASE(F) Real; const Grid& g = A.Grid(); const Int m = AOrig.Height(); Int subdiagonal = ( uplo==LOWER ? -1 : +1 ); if( g.Rank() == 0 ) cout << "Testing error..." << endl; // Grab the diagonal and subdiagonal of the symmetric tridiagonal matrix DistMatrix<Real,MD,STAR> d(g); DistMatrix<Real,MD,STAR> e(g); A.GetRealPartOfDiagonal( d ); A.GetRealPartOfDiagonal( e, subdiagonal ); // Grab a full copy of e so that we may fill the opposite subdiagonal DistMatrix<Real,STAR,STAR> e_STAR_STAR(g); DistMatrix<Real,MD,STAR> eOpposite(g); e_STAR_STAR = e; eOpposite.AlignWithDiagonal( A.DistData(), -subdiagonal ); eOpposite = e_STAR_STAR; // Zero B and then fill its tridiagonal DistMatrix<F> B(g); B.AlignWith( A ); Zeros( B, m, m ); B.SetRealPartOfDiagonal( d ); B.SetRealPartOfDiagonal( e, subdiagonal ); B.SetRealPartOfDiagonal( eOpposite, -subdiagonal ); if( print ) Print( B, "Tridiagonal" ); // Reverse the accumulated Householder transforms, ignoring symmetry hermitian_tridiag::ApplyQ( LEFT, uplo, NORMAL, A, t, B ); hermitian_tridiag::ApplyQ( RIGHT, uplo, ADJOINT, A, t, B ); if( print ) Print( B, "Rotated tridiagonal" ); // Compare the appropriate triangle of AOrig and B MakeTriangular( uplo, AOrig ); MakeTriangular( uplo, B ); Axpy( F(-1), AOrig, B ); if( print ) Print( B, "Error in rotated tridiagonal" ); const Real infNormOfAOrig = HermitianInfinityNorm( uplo, AOrig ); const Real frobNormOfAOrig = HermitianFrobeniusNorm( uplo, AOrig ); const Real infNormOfError = HermitianInfinityNorm( uplo, B ); const Real frobNormOfError = HermitianFrobeniusNorm( uplo, B ); if( g.Rank() == 0 ) { cout << " ||AOrig||_1 = ||AOrig||_oo = " << infNormOfAOrig << "\n" << " ||AOrig||_F = " << frobNormOfAOrig << "\n" << " ||AOrig - Q^H A Q||_oo = " << infNormOfError << "\n" << " ||AOrig - Q^H A Q||_F = " << frobNormOfError << endl; } }