void HermitianUniformSpectrum ( DistMatrix<F,U,V>& A, Int n, Base<F> lower, Base<F> upper ) { DEBUG_ONLY(CallStackEntry cse("HermitianUniformSpectrum")) A.Resize( n, n ); const Grid& grid = A.Grid(); typedef Base<F> Real; const bool isComplex = IsComplex<F>::val; const bool standardDist = ( U == MC && V == MR ); // Form d and D std::vector<F> d( n ); if( grid.Rank() == 0 ) for( Int j=0; j<n; ++j ) d[j] = SampleUniform<Real>( lower, upper ); mpi::Broadcast( d.data(), n, 0, grid.Comm() ); DistMatrix<F> ABackup( grid ); ABackup.AlignWith( A ); Diagonal( ABackup, d ); // Apply a Haar matrix from both sides DistMatrix<F> Q(grid); DistMatrix<F,MD,STAR> t(grid); DistMatrix<Real,MD,STAR> s(grid); ImplicitHaar( Q, t, s, n ); // Copy the result into the correct distribution qr::ApplyQ( LEFT, NORMAL, Q, t, s, ABackup ); qr::ApplyQ( RIGHT, ADJOINT, Q, t, s, ABackup ); A = ABackup; // Force the diagonal to be real-valued if( isComplex ) { const Int localHeight = A.LocalHeight(); const Int localWidth = A.LocalWidth(); for( Int jLoc=0; jLoc<localWidth; ++jLoc ) { const Int j = A.GlobalCol(jLoc); for( Int iLoc=0; iLoc<localHeight; ++iLoc ) { const Int i = A.GlobalRow(iLoc); if( i == j ) A.SetLocalImagPart( iLoc, jLoc, Real(0) ); } } } }
inline void MakeNormalUniformSpectrum ( DistMatrix<Complex<R>,U,V>& A, Complex<R> center=0, R radius=1 ) { #ifndef RELEASE CallStackEntry entry("MakeNormalUniformSpectrum"); #endif typedef Complex<R> C; if( A.Height() != A.Width() ) LogicError("Cannot make a non-square matrix normal"); const Grid& grid = A.Grid(); const bool standardDist = ( U == MC && V == MR ); // Sample the diagonal matrix D from the ball B_radius(center) // and then rotate it with a random Householder similarity transformation: // // (I-2uu^H) D (I-2uu^H)^H = D - 2(u (Conj(D) u)^H + (D u) u^H) + // (4 u^H D u) u u^H // // Form d and D const Int n = A.Height(); std::vector<C> d( n ); if( grid.Rank() == 0 ) for( Int j=0; j<n; ++j ) d[j] = SampleBall<C>( center, radius ); mpi::Broadcast( &d[0], n, 0, grid.Comm() ); DistMatrix<C> ABackup( grid ); if( standardDist ) Diagonal( A, d ); else { ABackup.AlignWith( A ); Diagonal( ABackup, d ); } // Form u DistMatrix<C> u( grid ); if( standardDist ) u.AlignWith( A ); else u.AlignWith( ABackup ); Uniform( u, n, 1 ); const R origNorm = Nrm2( u ); Scale( 1/origNorm, u ); // Form v := D u DistMatrix<C> v( grid ); if( standardDist ) v.AlignWith( A ); else v.AlignWith( ABackup ); v.ResizeTo( n, 1 ); if( v.LocalWidth() == 1 ) { const Int colShift = v.ColShift(); const Int colStride = v.ColStride(); const Int localHeight = v.LocalHeight(); for( Int iLoc=0; iLoc<localHeight; ++iLoc ) { const Int i = colShift + iLoc*colStride; v.SetLocal( iLoc, 0, d[i]*u.GetLocal(iLoc,0) ); } } // Form w := Conj(D) u DistMatrix<C> w( grid ); if( standardDist ) w.AlignWith( A ); else w.AlignWith( ABackup ); w.ResizeTo( n, 1 ); if( w.LocalWidth() == 1 ) { const Int colShift = w.ColShift(); const Int colStride = w.ColStride(); const Int localHeight = w.LocalHeight(); for( Int iLoc=0; iLoc<localHeight; ++iLoc ) { const Int i = colShift + iLoc*colStride; w.SetLocal( iLoc, 0, Conj(d[i])*u.GetLocal(iLoc,0) ); } } // Update A := A - 2(u w^H + v u^H) if( standardDist ) { Ger( C(-2), u, w, A ); Ger( C(-2), v, u, A ); } else { Ger( C(-2), u, w, ABackup ); Ger( C(-2), v, u, ABackup ); } // Form \gamma := 4 u^H (D u) = 4 (u,Du) const C gamma = 4*Dot(u,v); // Update A := A + gamma u u^H if( standardDist ) Ger( gamma, u, u, A ); else Ger( gamma, u, u, ABackup ); // Copy the result into the correct distribution if( !standardDist ) A = ABackup; }