QDWHInfo QDWH( Matrix<F>& A, const QDWHCtrl& ctrl ) { EL_DEBUG_CSE typedef Base<F> Real; const Real twoEst = TwoNormEstimate( A ); A *= 1/twoEst; // The one-norm of the inverse can be replaced with an estimate which is // a few times cheaper, e.g., via Higham and Tisseur's block algorithm // from "A Block Algorithm for Matrix 1-Norm Estimation, with an Application // to 1-Norm Pseudospectra". Real sMinUpper; Matrix<F> Y( A ); if( A.Height() > A.Width() ) { qr::ExplicitTriang( Y ); try { TriangularInverse( UPPER, NON_UNIT, Y ); sMinUpper = Real(1) / OneNorm( Y ); } catch( SingularMatrixException& e ) { sMinUpper = 0; } } else { try { Inverse( Y ); sMinUpper = Real(1) / OneNorm( Y ); } catch( SingularMatrixException& e ) { sMinUpper = 0; } } return QDWHInner( A, sMinUpper, ctrl ); }
Base<F> Norm( const Matrix<F>& A, NormType type ) { DEBUG_ONLY(CSE cse("Norm")) Base<F> norm = 0; switch( type ) { // The following norms are rather cheap to compute case ENTRYWISE_ONE_NORM: norm = EntrywiseNorm( A, Base<F>(1) ); break; case FROBENIUS_NORM: norm = FrobeniusNorm( A ); break; case INFINITY_NORM: norm = InfinityNorm( A ); break; case MAX_NORM: norm = MaxNorm( A ); break; case ONE_NORM: norm = OneNorm( A ); break; // The following two norms make use of an SVD case NUCLEAR_NORM: norm = NuclearNorm( A ); break; case TWO_NORM: norm = TwoNorm( A ); break; } return norm; }
T InfinityNorm(const SparseMatrix<T>& A) { // the infinity norm is the max absolute row sum; easier to transpose first // and return the one norm of the transpose SparseMatrix<T> Atranspose; Transpose(A, Atranspose); return OneNorm(Atranspose); }
Int Newton( DistMatrix<Field>& A, const SignCtrl<Base<Field>>& ctrl ) { EL_DEBUG_CSE typedef Base<Field> Real; Real tol = ctrl.tol; if( tol == Real(0) ) tol = A.Height()*limits::Epsilon<Real>(); Int numIts=0; DistMatrix<Field> B( A.Grid() ); DistMatrix<Field> *X=&A, *XNew=&B; while( numIts < ctrl.maxIts ) { // Overwrite XNew with the new iterate NewtonStep( *X, *XNew, ctrl.scaling ); // Use the difference in the iterates to test for convergence Axpy( Real(-1), *XNew, *X ); const Real oneDiff = OneNorm( *X ); const Real oneNew = OneNorm( *XNew ); // Ensure that X holds the current iterate and break if possible ++numIts; std::swap( X, XNew ); if( ctrl.progress && A.Grid().Rank() == 0 ) cout << "after " << numIts << " Newton iter's: " << "oneDiff=" << oneDiff << ", oneNew=" << oneNew << ", oneDiff/oneNew=" << oneDiff/oneNew << ", tol=" << tol << endl; if( oneDiff/oneNew <= Pow(oneNew,ctrl.power)*tol ) break; } if( X != &A ) A = *X; return numIts; }
ValueInt<Base<F>> InverseFreeSignDivide( ElementalMatrix<F>& XPre ) { DEBUG_CSE DistMatrixReadWriteProxy<F,F,MC,MR> XProx( XPre ); auto& X = XProx.Get(); typedef Base<F> Real; const Grid& g = X.Grid(); const Int n = X.Width(); if( X.Height() != 2*n ) LogicError("Matrix should be 2n x n"); // Expose A and B, and then copy A auto B = X( IR(0,n ), ALL ); auto A = X( IR(n,2*n), ALL ); DistMatrix<F> ACopy( A ); // Run the inverse-free alternative to Sign InverseFreeSign( X ); // Compute the pivoted QR decomp of inv(A + B) A [See LAWN91] // 1) B := A + B // 2) [Q,R,Pi] := QRP(A) // 3) B := Q^H B // 4) [R,Q] := RQ(B) B += A; DistMatrix<F,MD,STAR> t(g); DistMatrix<Base<F>,MD,STAR> d(g); DistMatrix<Int,VR,STAR> p(g); QR( A, t, d, p ); qr::ApplyQ( LEFT, ADJOINT, A, t, d, B ); RQ( B, t, d ); // A := Q^H A Q A = ACopy; rq::ApplyQ( LEFT, ADJOINT, B, t, d, A ); rq::ApplyQ( RIGHT, NORMAL, B, t, d, A ); // Return || E21 ||1 / || A ||1 // Return || E21 ||1 / || A ||1 ValueInt<Real> part = ComputePartition( A ); part.value /= OneNorm(ACopy); return part; }
TwoNormUpperBound( const DistMatrix<F>& A ) { #ifndef RELEASE CallStackEntry entry("TwoNormUpperBound"); #endif typedef BASE(F) R; const R m = A.Height(); const R n = A.Width(); const R maxNorm = MaxNorm( A ); const R oneNorm = OneNorm( A ); const R infNorm = InfinityNorm( A ); R upperBound = std::min( Sqrt(m*n)*maxNorm, Sqrt(m)*infNorm ); upperBound = std::min( upperBound, Sqrt(n)*oneNorm ); upperBound = std::min( upperBound, Sqrt( oneNorm*infNorm ) ); return upperBound; }
Base<F> InverseFreeSignDivide( Matrix<F>& X ) { DEBUG_CSE typedef Base<F> Real; const Int n = X.Width(); if( X.Height() != 2*n ) LogicError("Matrix should be 2n x n"); // Expose A and B, and then copy A auto B = X( IR(0,n ), ALL ); auto A = X( IR(n,2*n), ALL ); Matrix<F> ACopy( A ); // Run the inverse-free alternative to Sign InverseFreeSign( X ); // Compute the pivoted QR decomp of inv(A + B) A [See LAWN91] // 1) B := A + B // 2) [Q,R,Pi] := QRP(A) // 3) B := Q^H B // 4) [R,Q] := RQ(B) B += A; Matrix<F> t; Matrix<Base<F>> d; Matrix<Int> p; QR( A, t, d, p ); qr::ApplyQ( LEFT, ADJOINT, A, t, d, B ); RQ( B, t, d ); // A := Q^H A Q A = ACopy; rq::ApplyQ( LEFT, ADJOINT, B, t, d, A ); rq::ApplyQ( RIGHT, NORMAL, B, t, d, A ); // Return || E21 ||1 / || A ||1 ValueInt<Real> part = ComputePartition( A ); part.value /= OneNorm(ACopy); return part; }
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; }
int InverseFreeSign( ElementalMatrix<F>& XPre, Int maxIts=100, Base<F> tau=0 ) { DEBUG_CSE DistMatrixReadWriteProxy<F,F,MC,MR> XProx( XPre ); auto& X = XProx.Get(); typedef Base<F> Real; const Grid& g = X.Grid(); const Int n = X.Width(); if( X.Height() != 2*n ) LogicError("X must be 2n x n"); // Compute the tolerance if it is unset if( tau == Real(0) ) tau = n*limits::Epsilon<Real>(); // Expose A and B in the original and temporary DistMatrix<F> XAlt( 2*n, n, g ); auto B = X( IR(0,n ), ALL ); auto A = X( IR(n,2*n), ALL ); auto BAlt = XAlt( IR(0,n ), ALL ); auto AAlt = XAlt( IR(n,2*n), ALL ); // Flip the sign of A A *= -1; // Set up the space for explicitly computing the left half of Q DistMatrix<F,MD,STAR> t(g); DistMatrix<Base<F>,MD,STAR> d(g); DistMatrix<F> Q( 2*n, n, g ); auto Q12 = Q( IR(0,n ), ALL ); auto Q22 = Q( IR(n,2*n), ALL ); // Run the iterative algorithm Int numIts=0; DistMatrix<F> R(g), RLast(g); while( numIts < maxIts ) { XAlt = X; QR( XAlt, t, d ); // Form the left half of Q Zero( Q12 ); MakeIdentity( Q22 ); qr::ApplyQ( LEFT, NORMAL, XAlt, t, d, Q ); // Save a copy of R R = BAlt; MakeTrapezoidal( UPPER, R ); // Form the new iterate Gemm( ADJOINT, NORMAL, F(1), Q12, A, F(0), AAlt ); Gemm( ADJOINT, NORMAL, F(1), Q22, B, F(0), BAlt ); X = XAlt; // Use the difference in the iterates to test for convergence ++numIts; if( numIts > 1 ) { const Real oneRLast = OneNorm(RLast); AxpyTrapezoid( UPPER, F(-1), R, RLast ); const Real oneRDiff = OneNorm(RLast); if( oneRDiff <= tau*oneRLast ) break; } RLast = R; } // Revert the sign of A and return A *= -1; return numIts; }
This file is part of Elemental and is under the BSD 2-Clause License, which can be found in the LICENSE file in the root directory, or at http://opensource.org/licenses/BSD-2-Clause */ #include <El.hpp> namespace El { template<typename F> Base<F> OneCondition( const Matrix<F>& A ) { DEBUG_ONLY(CSE cse("OneCondition")) typedef Base<F> Real; Matrix<F> B( A ); const Real oneNorm = OneNorm( B ); try { Inverse( B ); } catch( SingularMatrixException& e ) { return limits::Infinity<Real>(); } const Real oneNormInv = OneNorm( B ); return oneNorm*oneNormInv; } template<typename F> Base<F> OneCondition( const ElementalMatrix<F>& A ) { DEBUG_ONLY(CSE cse("OneCondition")) typedef Base<F> Real; DistMatrix<F> B( A ); const Real oneNorm = OneNorm( B ); try { Inverse( B ); }
part.value /= oneA; return part; } template<typename F> inline ValueInt<BASE(F)> RandomizedSignDivide ( UpperOrLower uplo, Matrix<F>& A, Matrix<F>& G, bool returnQ=false, Int maxIts=1, BASE(F) relTol=0 ) { DEBUG_ONLY(CallStackEntry cse("herm_eig::RandomizedSignDivide")) typedef Base<F> Real; const Int n = A.Height(); MakeHermitian( uplo, A ); const Real oneA = OneNorm( A ); if( relTol == Real(0) ) relTol = 500*n*lapack::MachineEpsilon<Real>(); // S := sgn(G) // S := 1/2 ( S + I ) auto S( G ); herm_polar::QDWH( uplo, S ); UpdateDiagonal( S, F(1) ); Scale( F(1)/F(2), S ); ValueInt<Real> part; Matrix<F> V, B, t; Int it=0; while( it < maxIts ) {
#ifndef ELEM_SVD_UTIL_HPP #define ELEM_SVD_UTIL_HPP #include ELEM_ADJOINT_INC #include ELEM_ONENORM_INC namespace elem { namespace svd { template<typename F> inline bool CheckScale( DistMatrix<F>& A, BASE(F)& scale ) { scale = 1; typedef Base<F> Real; const Real oneNormOfA = OneNorm( A ); const Real safeMin = lapack::MachineSafeMin<Real>(); const Real precision = lapack::MachinePrecision<Real>(); const Real smallNumber = safeMin/precision; const Real bigNumber = 1/smallNumber; const Real rhoMin = Sqrt(smallNumber); const Real rhoMax = Min( Sqrt(bigNumber), 1/Sqrt(Sqrt(safeMin)) ); if( oneNormOfA > 0 && oneNormOfA < rhoMin ) { scale = rhoMin/oneNormOfA; return true; } else if( oneNormOfA > rhoMax ) { scale = rhoMax/oneNormOfA;