void PhaseEnumerationLeafInner ( PhaseEnumerationCache<Field>& cache, const PhaseEnumerationCtrl& ctrl, vector<pair<Int,Field>>& y, const Int beg, const Int baseInf, const Int baseOne ) { EL_DEBUG_CSE const Int n = ctrl.phaseOffsets.back(); const Int minInf = ctrl.minInfNorms.back(); const Int maxInf = ctrl.maxInfNorms.back(); const Int minOne = ctrl.minOneNorms.back(); const Int maxOne = ctrl.maxOneNorms.back(); const bool constrained = (y.size() == 0); SpiralState<Field> spiral; spiral.Initialize( constrained ); while( true ) { const Field beta = spiral.Step(); const Int betaInf = Int(MaxAbs(beta)); const Int betaOne = Int(OneAbs(beta)); const Int newInf = Max(betaInf,baseInf); const Int newOne = betaOne + baseOne; if( newInf > maxInf || newOne > maxOne ) break; if( newOne >= minOne && newInf >= minInf ) { for( Int i=beg; i<n; ++i ) { if( ctrl.enqueueProb >= 1. || SampleUniform<double>(0,1) <= ctrl.enqueueProb ) { y.emplace_back( i, beta ); cache.Enqueue( y ); y.pop_back(); } } } if( newOne < maxOne ) { // We can insert beta into any position and still have room // left for the one norm bound, so do so and then recurse for( Int i=beg; i<n-1; ++i ) { y.emplace_back( i, beta ); PhaseEnumerationLeafInner ( cache, ctrl, y, i+1, newInf, newOne ); y.pop_back(); } } } }
Int DetectSmallSubdiagonal( const Matrix<F>& H ) { DEBUG_CSE typedef Base<F> Real; const Int n = H.Height(); const Real ulp = limits::Precision<Real>(); const Real safeMin = limits::SafeMin<Real>(); const Real smallNum = safeMin*(Real(n)/ulp); // Search up the subdiagonal for( Int k=n-2; k>=0; --k ) { const F eta00 = H(k,k); const F eta01 = H(k,k+1); const Real eta10 = RealPart( H(k+1,k) ); const F eta11 = H(k+1,k+1); if( OneAbs(eta10) <= smallNum ) { return k+1; } Real localScale = OneAbs(eta00) + OneAbs(eta11); if( localScale == Real(0) ) { // Search outward a bit to get a sense of the matrix's local scale if( k-1 >= 0 ) localScale += Abs( RealPart( H(k,k-1) ) ); if( k+2 <= n-1 ) localScale += Abs( RealPart( H(k+2,k+1) ) ); } if( Abs(eta10) <= ulp*localScale ) { const Real maxOff = Max( Abs(eta10), OneAbs(eta01) ); const Real minOff = Min( Abs(eta10), OneAbs(eta01) ); const Real diagDiff = OneAbs(eta00-eta11); const Real maxDiag = Max( OneAbs(eta11), diagDiff ); const Real minDiag = Min( OneAbs(eta11), diagDiff ); const Real sigma = maxDiag + maxOff; if( minOff*(maxOff/sigma) <= Max(smallNum,ulp*(minDiag*(maxDiag/sigma))) ) { return k+1; } } } return 0; }
const bool conjugate = ( shift0.imag() == -shift1.imag() ); if( !bothReal && !conjugate ) LogicError("Assumed shifts were either both real or conjugates"); ) if( n == 2 ) { const Real& eta00 = H(0,0); const Real& eta01 = H(0,1); const Real& eta10 = H(1,0); const Real& eta11 = H(1,1); // It seems arbitrary whether the scale is computed relative // to shift0 or shift1, but we follow LAPACK's convention. // (While the choice is irrelevant for conjugate shifts, it is not for // real shifts) const Real scale = OneAbs(eta00-shift1) + Abs(eta10); if( scale == zero ) { v[0] = v[1] = zero; } else { // Normalize the first column by the scale Real eta10Scale = eta10 / scale; v[0] = eta10Scale*eta01 + (eta00-shift0.real())*((eta00-shift1.real())/scale) - shift0.imag()*(shift1.imag()/scale); v[1] = eta10Scale*(eta00+eta11-shift0.real()-shift1.real()); } } else