/* Diagonalization of an mxm matrix A by a rotation R. */ int Diago(double *A, double *R, int m, double threshold) { int encore = 1; int rots = 0; int p, q; double theta, c, s; Identity(R, m); /* Sweeps until no pair gets updated */ while (encore>0) { encore = 0; for (p = 0; p<m; p++) for (q = p + 1; q<m; q++) { theta = Givens(A, m, p, q); if (fabs(theta) > threshold) { c = cos(theta); s = sin(theta); LeftRotSimple(A, m, m, p, q, c, s); RightRotSimple(A, m, m, p, q, c, s); LeftRotSimple(R, m, m, p, q, c, s); encore = 1; rots++; } } } return rots; }
void NeighborColSwap ( Matrix<F>& Q, Matrix<F>& R, Int j ) { DEBUG_CSE typedef Base<F> Real; const Int m = Q.Height(); ColSwap( R, j, j+1 ); if( j < m-1 ) { Real c; F s; Givens( R(j,j), R(j+1,j), c, s ); auto RBR = R( IR(j,END), IR(j,END) ); // RBR((0,1),:) := | c, s | RBR((0,1),:) // | -conj(s), c | RotateRows( c, s, RBR, 0, 1 ); // Since | c, s |^H = | c, -s |, the transformation // | -conj(s), c | | conj(s), c | // // s |-> -s inverts a Givens rotation matrix. // // We therefore update // // Q(:,(j,j+1)) := Q(:,(j,j+1)) | c, -s |. // | conj(s), c | RotateCols( c, -s, Q, j, j+1 ); } }
//##################################################################### // Function Implicit_QR_Step //##################################################################### template<class T,int bandwidth> void BANDED_SYMMETRIC_MATRIX<T,bandwidth>:: Implicit_QR_Step(const int start,const T shift) { // see Golub and Van Loan, 8.3.2, p. 420 T x=A(start)[1]-shift,z=A(start)[2]; for(int k=start;;k++){ // chase offdiagonal element z into oblivion T c,s;Givens(x,z,c,s); if(k>start){T& b=A(k-1)[2];b=c*b-s*z;} T &ap=A(k)[1],&bp=A(k)[2],&aq=A(k+1)[1],&bq=A(k+1)[2]; // p,q = k,k+1 T cc=c*c,cs=c*s,ss=s*s,ccap=cc*ap,csbp=cs*bp,ssaq=ss*aq,csap=cs*ap,ccbp=cc*bp,ssbp=ss*bp,csaq=cs*aq,ssap=ss*ap,ccaq=cc*aq; ap=ccap-2*csbp+ssaq;bp=csap+ccbp-ssbp-csaq;aq=ssap+2*csbp+ccaq; // TODO: save 7 flops somehow if(!bq) return; // stop if matrix decouples x=bp;z=-s*bq;bq=c*bq;} }
void NeighborColSwap ( Matrix<F>& Q, Matrix<F>& R, Int j ) { DEBUG_CSE typedef Base<F> Real; const Int m = Q.Height(); ColSwap( R, j, j+1 ); if( j < m-1 ) { Real c; F s; Givens( R.Get(j,j), R.Get(j+1,j), c, s ); auto RBR = R( IR(j,END), IR(j,END) ); RotateRows( c, s, RBR, 0, 1 ); auto col1 = Q( ALL, IR(j) ); auto col2 = Q( ALL, IR(j+1) ); RotateCols( c, Conj(s), Q, j, j+1 ); } }
void LUTUnb ( bool conjugate, const Matrix<F>& U, Matrix<F>& X, bool checkIfSingular ) { EL_DEBUG_CSE typedef Base<F> Real; const Int m = X.Height(); const Int n = X.Width(); if( conjugate ) Conjugate( X ); const F* UBuf = U.LockedBuffer(); F* XBuf = X.Buffer(); const Int ldu = U.LDim(); const Int ldx = X.LDim(); Int k=0; while( k < m ) { const bool in2x2 = ( k+1<m && UBuf[(k+1)+k*ldu] != F(0) ); if( in2x2 ) { // Solve the 2x2 linear systems via a 2x2 QR decomposition produced // by the Givens rotation // | c s | | U(k, k) | = | gamma11 | // | -conj(s) c | | U(k+1,k) | | 0 | // // and by also forming the right two entries of the 2x2 resulting // upper-triangular matrix, say gamma12 and gamma22 // // Extract the 2x2 diagonal block, D const F delta11 = UBuf[ k + k *ldu]; const F delta12 = UBuf[ k +(k+1)*ldu]; const F delta21 = UBuf[(k+1)+ k *ldu]; const F delta22 = UBuf[(k+1)+(k+1)*ldu]; // Decompose D = Q R Real c; F s; const F gamma11 = Givens( delta11, delta21, c, s ); const F gamma12 = c*delta12 + s*delta22; const F gamma22 = -Conj(s)*delta12 + c*delta22; if( checkIfSingular ) { // TODO: Check if sufficiently small instead if( gamma11 == F(0) || gamma22 == F(0) ) LogicError("Singular diagonal block detected"); } for( Int j=0; j<n; ++j ) { F* xBuf = &XBuf[j*ldx]; // Solve against R^T xBuf[k ] /= gamma11; xBuf[k+1] -= gamma12*xBuf[k]; xBuf[k+1] /= gamma22; // Solve against Q^T const F chi1 = xBuf[k ]; const F chi2 = xBuf[k+1]; xBuf[k ] = c*chi1 - Conj(s)*chi2; xBuf[k+1] = s*chi1 + c*chi2; // Update x2 := x2 - U12^T x1 blas::Axpy ( m-(k+2), -xBuf[k ], &UBuf[ k +(k+2)*ldu], ldu, &xBuf[k+2], 1 ); blas::Axpy ( m-(k+2), -xBuf[k+1], &UBuf[(k+1)+(k+2)*ldu], ldu, &xBuf[k+2], 1 ); } k += 2; } else { if( checkIfSingular ) { // TODO: Check if sufficiently small instead if( UBuf[k+k*ldu] == F(0) ) LogicError("Singular diagonal entry detected"); } for( Int j=0; j<n; ++j ) { F* xBuf = &XBuf[j*ldx]; xBuf[k] /= UBuf[k+k*ldu]; blas::Axpy ( m-(k+1), -xBuf[k], &UBuf[k+(k+1)*ldu], ldu, &xBuf[k+1], 1 ); } k += 1; } } if( conjugate ) Conjugate( X ); }
void LLTUnb ( bool conjugate, const Matrix<F>& L, Matrix<F>& X, bool checkIfSingular ) { EL_DEBUG_CSE typedef Base<F> Real; const Int m = X.Height(); const Int n = X.Width(); const F* LBuf = L.LockedBuffer(); F* XBuf = X.Buffer(); const Int ldl = L.LDim(); const Int ldx = X.LDim(); if( conjugate ) Conjugate( X ); Int k=m-1; while( k >= 0 ) { const bool in2x2 = ( k>0 && LBuf[(k-1)+k*ldl] != F(0) ); if( in2x2 ) { --k; // Solve the 2x2 linear systems via a 2x2 LQ decomposition produced // by the Givens rotation // | L(k,k) L(k,k+1) | | c -conj(s) | = | gamma11 0 | // | s c | // and by also forming the bottom two entries of the 2x2 resulting // lower-triangular matrix, say gamma21 and gamma22 // // Extract the 2x2 diagonal block, D const F delta11 = LBuf[ k + k *ldl]; const F delta12 = LBuf[ k +(k+1)*ldl]; const F delta21 = LBuf[(k+1)+ k *ldl]; const F delta22 = LBuf[(k+1)+(k+1)*ldl]; // Decompose D = L Q Real c; F s; const F gamma11 = Givens( delta11, delta12, c, s ); const F gamma21 = c*delta21 + s*delta22; const F gamma22 = -Conj(s)*delta21 + c*delta22; if( checkIfSingular ) { // TODO: Instead check if values are too small in magnitude if( gamma11 == F(0) || gamma22 == F(0) ) LogicError("Singular diagonal block detected"); } for( Int j=0; j<n; ++j ) { F* xBuf = &XBuf[j*ldx]; // Solve against Q^T const F chi1 = xBuf[k ]; const F chi2 = xBuf[k+1]; xBuf[k ] = c*chi1 + s*chi2; xBuf[k+1] = -Conj(s)*chi1 + c*chi2; // Solve against R^T xBuf[k+1] /= gamma22; xBuf[k ] -= gamma21*xBuf[k+1]; xBuf[k ] /= gamma11; // Update x0 := x0 - L10^T x1 blas::Axpy( k, -xBuf[k ], &LBuf[k ], ldl, xBuf, 1 ); blas::Axpy( k, -xBuf[k+1], &LBuf[k+1], ldl, xBuf, 1 ); } } else { if( checkIfSingular ) if( LBuf[k+k*ldl] == F(0) ) LogicError("Singular diagonal entry detected"); for( Int j=0; j<n; ++j ) { F* xBuf = &XBuf[j*ldx]; // Solve the 1x1 linear system xBuf[k] /= LBuf[k+k*ldl]; // Update x0 := x0 - l10^T chi_1 blas::Axpy( k, -xBuf[k], &LBuf[k], ldl, xBuf, 1 ); } } --k; } if( conjugate ) Conjugate( X ); }
Matrix DivideAndSolve(Matrix A,int p) { double a,b,d,e,s,c,mu,i; int h,j,k,l,m,o,rowstartt,colstartt,rowendt,colendt; Vector v,u,x,y,z; Matrix B,C,D,E,Q,U,H; U = newIdMatrix(); H = newMatrix(); v = newVector(); i = p+1; rowstartt = i; colstartt = 0; while (rowstartt<n) { rowendt = (rowstartt+i-1<n-1)?rowstartt+i-1:n-1; colstartt = rowstartt-i; colendt = colstartt+i-1; /* Now T_i has dimension (p-h)x(p-h) */ /* First zero all but row 1 in T_i */ for (m=colstartt;m<=colendt;m++) { if (norm(A,m,rowstartt,rowendt)!=0.0) { /* Find Householder(A(h:p,m)) */ House(A,v,m,rowstartt,rowendt); for (o=0;o<rowstartt;o++) v[o]=0.0; for (o=rowendt+1;o<n;o++) v[o]=0.0; ApplyHouse(A,v,rowstartt,rowendt); } printf("m=%i, rowstart=%i, rowend=%i\n",m,rowstartt,rowendt); printVector(v); printMatrix(A); } /* Now zero all but the last entry in row 1 */ WeirdHouse(A,v,rowstartt,colstartt,colendt); /* Apply the HouseHolder */ ApplyHouse(A,v,colstartt,colendt); /* Now T_i has one single non-zero entry */ /* Iterate with explicit shift to zero the last non-zero entry */ while (A[rowstartt][colendt]> (A[rowstartt-1][colendt]-A[rowstartt][colendt+1])*epsilon) { printMatrix(A); /* Wilkonson Shift?? */ d =(A[rowstartt-1][colendt]-A[rowstartt][colendt+1])/2.0; b = A[rowstartt][colendt]; mu = A[rowstartt][colendt+1]+d-sign(d)*sqrt(d*d+b*b); /* Determine the givens */ Givens(A[rowstartt-1][colendt]-mu, A[rowstartt][colendt],&s,&c); /* Apply the givens */ ApplyGivens(A,s,c,rowstartt-1,rowstartt,0,n-1); printf("%e\n",A[colstartt][colendt]); } rowstartt+=i; colstartt+=i; } }
void LUTUnb ( bool conjugate, const Matrix<Real>& U, const Matrix<Complex<Real>>& shifts, Matrix<Real>& XReal, Matrix<Real>& XImag ) { DEBUG_CSE typedef Complex<Real> C; const Int m = XReal.Height(); const Int n = XReal.Width(); if( conjugate ) XImag *= -1; const Real* UBuf = U.LockedBuffer(); Real* XRealBuf = XReal.Buffer(); Real* XImagBuf = XImag.Buffer(); const Int ldU = U.LDim(); const Int ldXReal = XReal.LDim(); const Int ldXImag = XImag.LDim(); Int k=0; while( k < m ) { const bool in2x2 = ( k+1<m && UBuf[(k+1)+k*ldU] != Real(0) ); if( in2x2 ) { // Solve the 2x2 linear systems via 2x2 QR decompositions produced // by the Givens rotation // | c s | | U(k, k)-shift | = | gamma11 | // | -conj(s) c | | U(k+1,k) | | 0 | // // and by also forming the right two entries of the 2x2 resulting // upper-triangular matrix, say gamma12 and gamma22 // // Extract the constant part of the 2x2 diagonal block, D const Real delta12 = UBuf[ k +(k+1)*ldU]; const Real delta21 = UBuf[(k+1)+ k *ldU]; for( Int j=0; j<n; ++j ) { const C delta11 = UBuf[ k + k *ldU] - shifts.Get(j,0); const C delta22 = UBuf[(k+1)+(k+1)*ldU] - shifts.Get(j,0); // Decompose D = Q R Real c; C s; const C gamma11 = Givens( delta11, C(delta21), c, s ); const C gamma12 = c*delta12 + s*delta22; const C gamma22 = -Conj(s)*delta12 + c*delta22; Real* xRealBuf = &XRealBuf[j*ldXReal]; Real* xImagBuf = &XImagBuf[j*ldXImag]; // Solve against R^T C chi1(xRealBuf[k ],xImagBuf[k ]); C chi2(xRealBuf[k+1],xImagBuf[k+1]); chi1 /= gamma11; chi2 -= gamma12*chi1; chi2 /= gamma22; // Solve against Q^T const C eta1 = c*chi1 - Conj(s)*chi2; const C eta2 = s*chi1 + c*chi2; xRealBuf[k ] = eta1.real(); xImagBuf[k ] = eta1.imag(); xRealBuf[k+1] = eta2.real(); xImagBuf[k+1] = eta2.imag(); // Update x2 := x2 - U12^T x1 blas::Axpy ( m-(k+2), -xRealBuf[k ], &UBuf[ k +(k+2)*ldU], ldU, &xRealBuf[k+2], 1 ); blas::Axpy ( m-(k+2), -xImagBuf[k ], &UBuf[ k +(k+2)*ldU], ldU, &xImagBuf[k+2], 1 ); blas::Axpy ( m-(k+2), -xRealBuf[k+1], &UBuf[(k+1)+(k+2)*ldU], ldU, &xRealBuf[k+2], 1 ); blas::Axpy ( m-(k+2), -xImagBuf[k+1], &UBuf[(k+1)+(k+2)*ldU], ldU, &xImagBuf[k+2], 1 ); } k += 2; } else { for( Int j=0; j<n; ++j ) { Real* xRealBuf = &XRealBuf[j*ldXReal]; Real* xImagBuf = &XImagBuf[j*ldXImag]; C eta1( xRealBuf[k], xImagBuf[k] ); eta1 /= UBuf[k+k*ldU] - shifts.Get(j,0); xRealBuf[k] = eta1.real(); xImagBuf[k] = eta1.imag(); blas::Axpy ( m-(k+1), -xRealBuf[k], &UBuf[k+(k+1)*ldU], ldU, &xRealBuf[k+1], 1 ); blas::Axpy ( m-(k+1), -xImagBuf[k], &UBuf[k+(k+1)*ldU], ldU, &xImagBuf[k+1], 1 ); } k += 1; } } if( conjugate ) XImag *= -1; }
void LUTUnb ( bool conjugate, const Matrix<F>& U, const Matrix<F>& shifts, Matrix<F>& X ) { DEBUG_CSE typedef Base<F> Real; const Int m = X.Height(); const Int n = X.Width(); if( conjugate ) Conjugate( X ); const F* UBuf = U.LockedBuffer(); F* XBuf = X.Buffer(); const Int ldU = U.LDim(); const Int ldX = X.LDim(); Int k=0; while( k < m ) { const bool in2x2 = ( k+1<m && UBuf[(k+1)+k*ldU] != F(0) ); if( in2x2 ) { // Solve the 2x2 linear systems via 2x2 QR decompositions produced // by the Givens rotation // | c s | | U(k, k)-shift | = | gamma11 | // | -conj(s) c | | U(k+1,k) | | 0 | // // and by also forming the right two entries of the 2x2 resulting // upper-triangular matrix, say gamma12 and gamma22 // // Extract the constant part of the 2x2 diagonal block, D const F delta12 = UBuf[ k +(k+1)*ldU]; const F delta21 = UBuf[(k+1)+ k *ldU]; for( Int j=0; j<n; ++j ) { const F delta11 = UBuf[ k + k *ldU] - shifts.Get(j,0); const F delta22 = UBuf[(k+1)+(k+1)*ldU] - shifts.Get(j,0); // Decompose D = Q R Real c; F s; const F gamma11 = Givens( delta11, delta21, c, s ); const F gamma12 = c*delta12 + s*delta22; const F gamma22 = -Conj(s)*delta12 + c*delta22; F* xBuf = &XBuf[j*ldX]; // Solve against R^T F chi1 = xBuf[k ]; F chi2 = xBuf[k+1]; chi1 /= gamma11; chi2 -= gamma12*chi1; chi2 /= gamma22; // Solve against Q^T xBuf[k ] = c*chi1 - Conj(s)*chi2; xBuf[k+1] = s*chi1 + c*chi2; // Update x2 := x2 - U12^T x1 blas::Axpy ( m-(k+2), -xBuf[k ], &UBuf[ k +(k+2)*ldU], ldU, &xBuf[k+2], 1 ); blas::Axpy ( m-(k+2), -xBuf[k+1], &UBuf[(k+1)+(k+2)*ldU], ldU, &xBuf[k+2], 1 ); } k += 2; } else { for( Int j=0; j<n; ++j ) { F* xBuf = &XBuf[j*ldX]; xBuf[k] /= UBuf[k+k*ldU] - shifts.Get(j,0); blas::Axpy ( m-(k+1), -xBuf[k], &UBuf[k+(k+1)*ldU], ldU, &xBuf[k+1], 1 ); } k += 1; } } if( conjugate ) Conjugate( X ); }
void LUNUnb( const Matrix<F>& U, Matrix<F>& X, bool checkIfSingular ) { DEBUG_CSE const Int m = X.Height(); const Int n = X.Width(); typedef Base<F> Real; const F* UBuf = U.LockedBuffer(); F* XBuf = X.Buffer(); const Int ldu = U.LDim(); const Int ldx = X.LDim(); Int k=m-1; while( k >= 0 ) { const bool in2x2 = ( k>0 && UBuf[k+(k-1)*ldu] != F(0) ); if( in2x2 ) { --k; // Solve the 2x2 linear systems via a 2x2 QR decomposition produced // by the Givens rotation // | c s | | U(k, k) | = | gamma11 | // | -conj(s) c | | U(k+1,k) | | 0 | // // and by also forming the right two entries of the 2x2 resulting // upper-triangular matrix, say gamma12 and gamma22 // // Extract the 2x2 diagonal block, D const F delta11 = UBuf[ k + k *ldu]; const F delta12 = UBuf[ k +(k+1)*ldu]; const F delta21 = UBuf[(k+1)+ k *ldu]; const F delta22 = UBuf[(k+1)+(k+1)*ldu]; // Decompose D = Q R Real c; F s; const F gamma11 = Givens( delta11, delta21, c, s ); const F gamma12 = c*delta12 + s*delta22; const F gamma22 = -Conj(s)*delta12 + c*delta22; if( checkIfSingular ) { // TODO: Instead check if values are too small in magnitude if( gamma11 == F(0) || gamma22 == F(0) ) LogicError("Singular diagonal block detected"); } for( Int j=0; j<n; ++j ) { F* xBuf = &XBuf[j*ldx]; // Solve against Q const F chi1 = xBuf[k ]; const F chi2 = xBuf[k+1]; xBuf[k ] = c*chi1 + s*chi2; xBuf[k+1] = -Conj(s)*chi1 + c*chi2; // Solve against R xBuf[k+1] /= gamma22; xBuf[k ] -= gamma12*xBuf[k+1]; xBuf[k ] /= gamma11; // Update x0 := x0 - U01 x1 blas::Axpy( k, -xBuf[k ], &UBuf[ k *ldu], 1, xBuf, 1 ); blas::Axpy( k, -xBuf[k+1], &UBuf[(k+1)*ldu], 1, xBuf, 1 ); } } else { if( checkIfSingular ) if( UBuf[k+k*ldu] == F(0) ) LogicError("Singular diagonal entry detected"); for( Int j=0; j<n; ++j ) { F* xBuf = &XBuf[j*ldx]; // Solve the 1x1 linear system xBuf[k] /= UBuf[k+k*ldu]; // Update x0 := x0 - u01 chi_1 blas::Axpy( k, -xBuf[k], &UBuf[k*ldu], 1, xBuf, 1 ); } } --k; } }
void LLNUnb( const Matrix<F>& L, Matrix<F>& X, bool checkIfSingular ) { DEBUG_CSE typedef Base<F> Real; const Int m = X.Height(); const Int n = X.Width(); const F* LBuf = L.LockedBuffer(); F* XBuf = X.Buffer(); const Int ldl = L.LDim(); const Int ldx = X.LDim(); Int k=0; while( k < m ) { const bool in2x2 = ( k+1<m && LBuf[k+(k+1)*ldl] != F(0) ); if( in2x2 ) { // Solve the 2x2 linear systems via a 2x2 LQ decomposition produced // by the Givens rotation // | L(k,k) L(k,k+1) | | c -conj(s) | = | gamma11 0 | // | s c | // and by also forming the bottom two entries of the 2x2 resulting // lower-triangular matrix, say gamma21 and gamma22 // // Extract the 2x2 diagonal block, D const F delta11 = LBuf[ k + k *ldl]; const F delta12 = LBuf[ k +(k+1)*ldl]; const F delta21 = LBuf[(k+1)+ k *ldl]; const F delta22 = LBuf[(k+1)+(k+1)*ldl]; // Decompose D = L Q Real c; F s; const F gamma11 = Givens( delta11, delta12, c, s ); const F gamma21 = c*delta21 + s*delta22; const F gamma22 = -Conj(s)*delta21 + c*delta22; if( checkIfSingular ) { // TODO: Check if sufficiently small instead if( gamma11 == F(0) || gamma22 == F(0) ) LogicError("Singular diagonal block detected"); } for( Int j=0; j<n; ++j ) { F* xBuf = &XBuf[j*ldx]; // Solve against L xBuf[k ] /= gamma11; xBuf[k+1] -= gamma21*xBuf[k]; xBuf[k+1] /= gamma22; // Solve against Q const F chi1 = xBuf[k ]; const F chi2 = xBuf[k+1]; xBuf[k ] = c*chi1 - Conj(s)*chi2; xBuf[k+1] = s*chi1 + c*chi2; // Update x2 := x2 - L21 x1 blas::Axpy ( m-(k+2), -xBuf[k ], &LBuf[(k+2)+ k *ldl], 1, &xBuf[k+2], 1 ); blas::Axpy ( m-(k+2), -xBuf[k+1], &LBuf[(k+2)+(k+1)*ldl], 1, &xBuf[k+2], 1 ); } k += 2; } else { if( checkIfSingular ) { // TODO: Check if sufficiently small instead if( LBuf[k+k*ldl] == F(0) ) LogicError("Singular diagonal entry detected"); } for( Int j=0; j<n; ++j ) { F* xBuf = &XBuf[j*ldx]; xBuf[k] /= LBuf[k+k*ldl]; blas::Axpy ( m-(k+1), -xBuf[k], &LBuf[(k+1)+k*ldl], 1, &xBuf[k+1], 1 ); } k += 1; } } }
void LLTUnb ( bool conjugate, const Matrix<F>& L, const Matrix<F>& shifts, Matrix<F>& X ) { DEBUG_CSE typedef Base<F> Real; const Int m = X.Height(); const Int n = X.Width(); const F* LBuf = L.LockedBuffer(); F* XBuf = X.Buffer(); const Int ldl = L.LDim(); const Int ldx = X.LDim(); if( conjugate ) Conjugate( X ); Int k=m-1; while( k >= 0 ) { const bool in2x2 = ( k>0 && LBuf[(k-1)+k*ldl] != F(0) ); if( in2x2 ) { --k; // Solve the 2x2 linear systems via 2x2 LQ decompositions produced // by the Givens rotation // | L(k,k)-shift L(k,k+1) | | c -conj(s) | = | gamma11 0 | // | s c | // and by also forming the bottom two entries of the 2x2 resulting // lower-triangular matrix, say gamma21 and gamma22 // // Extract the constant part of the 2x2 diagonal block, D const F delta12 = LBuf[ k +(k+1)*ldl]; const F delta21 = LBuf[(k+1)+ k *ldl]; for( Int j=0; j<n; ++j ) { const F delta11 = LBuf[ k + k *ldl] - shifts.Get(j,0); const F delta22 = LBuf[(k+1)+(k+1)*ldl] - shifts.Get(j,0); // Decompose D = L Q Real c; F s; const F gamma11 = Givens( delta11, delta12, c, s ); const F gamma21 = c*delta21 + s*delta22; const F gamma22 = -Conj(s)*delta21 + c*delta22; F* xBuf = &XBuf[j*ldx]; // Solve against Q^T const F chi1 = xBuf[k ]; const F chi2 = xBuf[k+1]; xBuf[k ] = c*chi1 + s*chi2; xBuf[k+1] = -Conj(s)*chi1 + c*chi2; // Solve against R^T xBuf[k+1] /= gamma22; xBuf[k ] -= gamma21*xBuf[k+1]; xBuf[k ] /= gamma11; // Update x0 := x0 - L10^T x1 blas::Axpy( k, -xBuf[k ], &LBuf[k ], ldl, xBuf, 1 ); blas::Axpy( k, -xBuf[k+1], &LBuf[k+1], ldl, xBuf, 1 ); } } else { for( Int j=0; j<n; ++j ) { F* xBuf = &XBuf[j*ldx]; // Solve the 1x1 linear system xBuf[k] /= LBuf[k+k*ldl] - shifts.Get(j,0); // Update x0 := x0 - l10^T chi_1 blas::Axpy( k, -xBuf[k], &LBuf[k], ldl, xBuf, 1 ); } } --k; } if( conjugate ) Conjugate( X ); }