inline void MakeSymmetric( UpperOrLower uplo, Matrix<T>& A ) { #ifndef RELEASE PushCallStack("MakeSymmetric"); #endif if( A.Height() != A.Width() ) throw std::logic_error("Cannot make non-square matrix symmetric"); Matrix<T> d; A.GetDiagonal( d ); if( uplo == LOWER ) MakeTrapezoidal( LEFT, LOWER, -1, A ); else MakeTrapezoidal( LEFT, UPPER, +1, A ); Matrix<T> ATrans; Transpose( A, ATrans ); Axpy( T(1), ATrans, A ); A.SetDiagonal( d ); #ifndef RELEASE PopCallStack(); #endif }
inline SafeProduct<F> AfterLUPartialPiv( const Matrix<F>& A, const Matrix<Int>& p ) { #ifndef RELEASE CallStackEntry entry("determinant::AfterLUPartialPiv"); #endif if( A.Height() != A.Width() ) LogicError("Cannot compute determinant of nonsquare matrix"); if( A.Height() != p.Height() ) LogicError("Pivot vector is incorrect length"); typedef BASE(F) R; const Int n = A.Height(); Matrix<F> d; A.GetDiagonal( d ); const R scale(n); SafeProduct<F> det( n ); for( Int i=0; i<n; ++i ) { const F delta = d.Get(i,0); R alpha = Abs(delta); det.rho *= delta/alpha; det.kappa += Log(alpha)/scale; } const bool isOdd = PivotParity( p ); if( isOdd ) det.rho = -det.rho; return det; }
inline F Trace( const Matrix<F>& A ) { #ifndef RELEASE PushCallStack("Trace"); #endif if( A.Height() != A.Width() ) throw std::logic_error("Cannot compute trace of nonsquare matrix"); Matrix<F> d; A.GetDiagonal( d ); F trace = 0; const int n = A.Height(); for( int i=0; i<n; ++i ) trace += d.Get(i,0); #ifndef RELEASE PopCallStack(); #endif return trace; }
inline SafeProduct<F> SafeDeterminant( Matrix<F>& A ) { #ifndef RELEASE PushCallStack("SafeDeterminant"); #endif if( A.Height() != A.Width() ) throw std::logic_error ("Cannot compute determinant of nonsquare matrix"); typedef typename Base<F>::type R; const int n = A.Height(); SafeProduct<F> det( n ); try { Matrix<int> p; LU( A, p ); const bool isOdd = PivotParity( p ); Matrix<F> d; A.GetDiagonal( d ); for( int i=0; i<n; ++i ) { const F delta = d.Get(i,0); R alpha = Abs(delta); det.rho *= delta/alpha; det.kappa += std::log(alpha)/n; } if( isOdd ) det.rho = -det.rho; } catch( SingularMatrixException& e ) { det.rho = 0; det.kappa = 0; } #ifndef RELEASE PopCallStack(); #endif return det; }
inline SafeProduct<F> LUPartialPiv( Matrix<F>& A ) { #ifndef RELEASE CallStackEntry entry("determinant::LUPartialPiv"); #endif if( A.Height() != A.Width() ) throw std::logic_error ("Cannot compute determinant of nonsquare matrix"); typedef BASE(F) R; const int n = A.Height(); const R scale(n); SafeProduct<F> det( n ); try { Matrix<int> p; elem::LU( A, p ); const bool isOdd = PivotParity( p ); Matrix<F> d; A.GetDiagonal( d ); for( int i=0; i<n; ++i ) { const F delta = d.Get(i,0); R alpha = Abs(delta); det.rho *= delta/alpha; det.kappa += Log(alpha)/scale; } if( isOdd ) det.rho = -det.rho; } catch( SingularMatrixException& e ) { det.rho = 0; det.kappa = 0; } return det; }
inline SafeProduct<F> SafeHPDDeterminantWithOverwrite( UpperOrLower uplo, Matrix<F>& A ) { #ifndef RELEASE PushCallStack("internal::SafeHPDDeterminantWithOverwrite"); #endif if( A.Height() != A.Width() ) throw std::logic_error ("Cannot compute determinant of nonsquare matrix"); typedef typename Base<F>::type R; const int n = A.Height(); const R scale = R(n)/R(2); SafeProduct<F> det( n ); try { Cholesky( uplo, A ); Matrix<F> d; A.GetDiagonal( d ); det.rho = F(1); for( int i=0; i<n; ++i ) { const R delta = RealPart(d.Get(i,0)); det.kappa += Log(delta)/scale; } } catch( NonHPDMatrixException& e ) { det.rho = 0; det.kappa = 0; } #ifndef RELEASE PopCallStack(); #endif return det; }
void TestCorrectness ( const Matrix<F>& A, const Matrix<F>& tP, const Matrix<F>& tQ, Matrix<F>& AOrig, bool print, bool display ) { typedef Base<F> Real; const Int m = AOrig.Height(); const Int n = AOrig.Width(); const Real infNormAOrig = InfinityNorm( AOrig ); const Real frobNormAOrig = FrobeniusNorm( AOrig ); if( mpi::WorldRank() == 0 ) cout << "Testing error..." << endl; // Grab the diagonal and superdiagonal of the bidiagonal matrix auto d = A.GetDiagonal( 0 ); auto e = A.GetDiagonal( (m>=n ? 1 : -1) ); // Zero B and then fill its bidiagonal Matrix<F> B; Zeros( B, m, n ); B.SetDiagonal( d, 0 ); B.SetDiagonal( e, (m>=n ? 1 : -1) ); if( print && mpi::WorldRank() == 0 ) Print( B, "Bidiagonal" ); if( display && mpi::WorldRank() == 0 ) Display( B, "Bidiagonal" ); if( print || display ) { Matrix<F> Q, P; Identity( Q, m, m ); Identity( P, n, n ); bidiag::ApplyQ( LEFT, NORMAL, A, tQ, Q ); bidiag::ApplyP( RIGHT, NORMAL, A, tP, P ); if( print && mpi::WorldRank() == 0 ) { Print( Q, "Q" ); Print( P, "P" ); } if( display && mpi::WorldRank() == 0 ) { Display( Q, "Q" ); Display( P, "P" ); } } // Reverse the accumulated Householder transforms bidiag::ApplyQ( LEFT, ADJOINT, A, tQ, AOrig ); bidiag::ApplyP( RIGHT, NORMAL, A, tP, AOrig ); if( print && mpi::WorldRank() == 0 ) Print( AOrig, "Manual bidiagonal" ); if( display && mpi::WorldRank() == 0 ) Display( AOrig, "Manual bidiagonal" ); // Compare the appropriate portion of AOrig and B if( m >= n ) { MakeTriangular( UPPER, AOrig ); MakeTrapezoidal( LOWER, AOrig, 1 ); } else { MakeTriangular( LOWER, AOrig ); MakeTrapezoidal( UPPER, AOrig, -1 ); } Axpy( F(-1), AOrig, B ); if( print && mpi::WorldRank() == 0 ) Print( B, "Error in rotated bidiagonal" ); if( display && mpi::WorldRank() == 0 ) Display( B, "Error in rotated bidiagonal" ); const Real infNormError = InfinityNorm( B ); const Real frobNormError = FrobeniusNorm( B ); if( mpi::WorldRank() == 0 ) { cout << " ||A||_oo = " << infNormAOrig << "\n" << " ||A||_F = " << frobNormAOrig << "\n" << " ||B - Q^H A P||_oo = " << infNormError << "\n" << " ||B - Q^H A P||_F = " << frobNormError << endl; } }