inline void SimpleSingularValuesUpper ( DistMatrix<Complex<Real> >& A, DistMatrix<Real,VR,STAR>& s ) { #ifndef RELEASE PushCallStack("svd::SimpleSingularValuesUpper"); #endif typedef Complex<Real> C; const int m = A.Height(); const int n = A.Width(); const int k = std::min( m, n ); const int offdiagonal = ( m>=n ? 1 : -1 ); const char uplo = ( m>=n ? 'U' : 'L' ); const Grid& g = A.Grid(); // Bidiagonalize A DistMatrix<C,STAR,STAR> tP(g), tQ(g); Bidiag( A, tP, tQ ); // Grab copies of the diagonal and sub/super-diagonal of A DistMatrix<Real,MD,STAR> d_MD_STAR( g ), e_MD_STAR( g ); A.GetRealPartOfDiagonal( d_MD_STAR ); A.GetRealPartOfDiagonal( e_MD_STAR, offdiagonal ); // In order to use serial QR kernels, we need the full bidiagonal matrix // on each process // // NOTE: lapack::BidiagQRAlg expects e to be of length k DistMatrix<Real,STAR,STAR> d_STAR_STAR( d_MD_STAR ); DistMatrix<Real,STAR,STAR> eHat_STAR_STAR( k, 1, g ); DistMatrix<Real,STAR,STAR> e_STAR_STAR( g ); e_STAR_STAR.View( eHat_STAR_STAR, 0, 0, k-1, 1 ); e_STAR_STAR = e_MD_STAR; // Compute the singular values of the bidiagonal matrix lapack::BidiagQRAlg ( uplo, k, 0, 0, d_STAR_STAR.LocalBuffer(), e_STAR_STAR.LocalBuffer(), (C*)0, 1, (C*)0, 1 ); // Copy out the appropriate subset of the singular values s = d_STAR_STAR; #ifndef RELEASE PopCallStack(); #endif }
inline void GolubReinschUpper ( DistMatrix<F>& A, DistMatrix<BASE(F),VR,STAR>& s ) { #ifndef RELEASE CallStackEntry entry("svd::GolubReinschUpper"); #endif typedef BASE(F) Real; const Int m = A.Height(); const Int n = A.Width(); const Int k = Min( m, n ); const Int offdiagonal = ( m>=n ? 1 : -1 ); const Grid& g = A.Grid(); // Bidiagonalize A DistMatrix<F,STAR,STAR> tP(g), tQ(g); Bidiag( A, tP, tQ ); // Grab copies of the diagonal and sub/super-diagonal of A DistMatrix<Real,MD,STAR> d_MD_STAR(g), e_MD_STAR(g); A.GetRealPartOfDiagonal( d_MD_STAR ); A.GetRealPartOfDiagonal( e_MD_STAR, offdiagonal ); // In order to use serial DQDS kernels, we need the full bidiagonal matrix // on each process // // NOTE: lapack::BidiagDQDS expects e to be of length k DistMatrix<Real,STAR,STAR> d_STAR_STAR( d_MD_STAR ), eHat_STAR_STAR( k, 1, g ), e_STAR_STAR( g ); View( e_STAR_STAR, eHat_STAR_STAR, 0, 0, k-1, 1 ); e_STAR_STAR = e_MD_STAR; // Compute the singular values of the bidiagonal matrix via DQDS lapack::BidiagDQDS( k, d_STAR_STAR.Buffer(), e_STAR_STAR.Buffer() ); // Copy out the appropriate subset of the singular values s = d_STAR_STAR; }
void TestCorrectness ( UpperOrLower uplo, const DistMatrix<F>& A, const DistMatrix<F,STAR,STAR>& t, DistMatrix<F>& AOrig, bool print, bool display ) { typedef Base<F> Real; const Grid& g = A.Grid(); const Int m = AOrig.Height(); const Real infNormAOrig = HermitianInfinityNorm( uplo, AOrig ); const Real frobNormAOrig = HermitianFrobeniusNorm( uplo, AOrig ); if( g.Rank() == 0 ) cout << "Testing error..." << endl; // Grab the diagonal and subdiagonal of the symmetric tridiagonal matrix Int subdiagonal = ( uplo==LOWER ? -1 : +1 ); auto d = A.GetRealPartOfDiagonal(); auto e = A.GetRealPartOfDiagonal( subdiagonal ); // Grab a full copy of e so that we may fill the opposite subdiagonal DistMatrix<Real,STAR,STAR> e_STAR_STAR( e ); DistMatrix<Real,MD,STAR> eOpposite(g); A.ForceDiagonalAlign( eOpposite, -subdiagonal ); eOpposite = e_STAR_STAR; // Zero B and then fill its tridiagonal DistMatrix<F> B(g); B.AlignWith( A ); Zeros( B, m, m ); B.SetRealPartOfDiagonal( d ); B.SetRealPartOfDiagonal( e, subdiagonal ); B.SetRealPartOfDiagonal( eOpposite, -subdiagonal ); if( print ) Print( B, "Tridiagonal" ); if( display ) Display( B, "Tridiagonal" ); // Reverse the accumulated Householder transforms, ignoring symmetry herm_tridiag::ApplyQ( LEFT, uplo, NORMAL, A, t, B ); herm_tridiag::ApplyQ( RIGHT, uplo, ADJOINT, A, t, B ); if( print ) Print( B, "Rotated tridiagonal" ); if( display ) Display( B, "Rotated tridiagonal" ); // Compare the appropriate triangle of AOrig and B MakeTriangular( uplo, AOrig ); MakeTriangular( uplo, B ); Axpy( F(-1), AOrig, B ); if( print ) Print( B, "Error in rotated tridiagonal" ); if( display ) Display( B, "Error in rotated tridiagonal" ); const Real infNormError = HermitianInfinityNorm( uplo, B ); const Real frobNormError = HermitianFrobeniusNorm( uplo, B ); // Compute || I - Q Q^H || MakeIdentity( B ); herm_tridiag::ApplyQ( RIGHT, uplo, ADJOINT, A, t, B ); DistMatrix<F> QHAdj( g ); Adjoint( B, QHAdj ); MakeIdentity( B ); herm_tridiag::ApplyQ( LEFT, uplo, NORMAL, A, t, B ); Axpy( F(-1), B, QHAdj ); herm_tridiag::ApplyQ( RIGHT, uplo, ADJOINT, A, t, B ); UpdateDiagonal( B, F(-1) ); const Real infNormQError = InfinityNorm( B ); const Real frobNormQError = FrobeniusNorm( B ); if( g.Rank() == 0 ) { cout << " ||A||_oo = " << infNormAOrig << "\n" << " ||A||_F = " << frobNormAOrig << "\n" << " || I - Q^H Q ||_oo = " << infNormQError << "\n" << " || I - Q^H Q ||_F = " << frobNormQError << "\n" << " ||A - Q T Q^H||_oo = " << infNormError << "\n" << " ||A - Q T Q^H||_F = " << frobNormError << endl; } }
inline void GolubReinschUpper ( DistMatrix<F>& A, DistMatrix<BASE(F),VR,STAR>& s, DistMatrix<F>& V ) { #ifndef RELEASE CallStackEntry entry("svd::GolubReinschUpper"); #endif typedef BASE(F) Real; const Int m = A.Height(); const Int n = A.Width(); const Int k = Min( m, n ); const Int offdiagonal = ( m>=n ? 1 : -1 ); const char uplo = ( m>=n ? 'U' : 'L' ); const Grid& g = A.Grid(); // Bidiagonalize A DistMatrix<F,STAR,STAR> tP( g ), tQ( g ); Bidiag( A, tP, tQ ); // Grab copies of the diagonal and sub/super-diagonal of A DistMatrix<Real,MD,STAR> d_MD_STAR(g), e_MD_STAR(g); A.GetRealPartOfDiagonal( d_MD_STAR ); A.GetRealPartOfDiagonal( e_MD_STAR, offdiagonal ); // NOTE: lapack::BidiagQRAlg expects e to be of length k DistMatrix<Real,STAR,STAR> d_STAR_STAR( d_MD_STAR ), eHat_STAR_STAR( k, 1, g ), e_STAR_STAR( g ); View( e_STAR_STAR, eHat_STAR_STAR, 0, 0, k-1, 1 ); e_STAR_STAR = e_MD_STAR; // Initialize U and VAdj to the appropriate identity matrices DistMatrix<F,VC,STAR> U_VC_STAR( g ); DistMatrix<F,STAR,VC> VAdj_STAR_VC( g ); U_VC_STAR.AlignWith( A ); VAdj_STAR_VC.AlignWith( V ); Identity( U_VC_STAR, m, k ); Identity( VAdj_STAR_VC, k, n ); // Compute the SVD of the bidiagonal matrix and accumulate the Givens // rotations into our local portion of U and VAdj Matrix<F>& ULoc = U_VC_STAR.Matrix(); Matrix<F>& VAdjLoc = VAdj_STAR_VC.Matrix(); lapack::BidiagQRAlg ( uplo, k, VAdjLoc.Width(), ULoc.Height(), d_STAR_STAR.Buffer(), e_STAR_STAR.Buffer(), VAdjLoc.Buffer(), VAdjLoc.LDim(), ULoc.Buffer(), ULoc.LDim() ); // Make a copy of A (for the Householder vectors) and pull the necessary // portions of U and VAdj into a standard matrix dist. DistMatrix<F> B( A ); if( m >= n ) { DistMatrix<F> AT(g), AB(g); DistMatrix<F,VC,STAR> UT_VC_STAR(g), UB_VC_STAR(g); PartitionDown( A, AT, AB, n ); PartitionDown( U_VC_STAR, UT_VC_STAR, UB_VC_STAR, n ); AT = UT_VC_STAR; MakeZeros( AB ); Adjoint( VAdj_STAR_VC, V ); } else { DistMatrix<F> VT(g), VB(g); DistMatrix<F,STAR,VC> VAdjL_STAR_VC(g), VAdjR_STAR_VC(g); PartitionDown( V, VT, VB, m ); PartitionRight( VAdj_STAR_VC, VAdjL_STAR_VC, VAdjR_STAR_VC, m ); Adjoint( VAdjL_STAR_VC, VT ); MakeZeros( VB ); } // Backtransform U and V bidiag::ApplyU( LEFT, NORMAL, B, tQ, A ); bidiag::ApplyV( LEFT, NORMAL, B, tP, V ); // Copy out the appropriate subset of the singular values s = d_STAR_STAR; }
inline void GolubReinschUpper_FLA ( DistMatrix<F>& A, DistMatrix<BASE(F),VR,STAR>& s, DistMatrix<F>& V ) { #ifndef RELEASE CallStackEntry entry("svd::GolubReinschUpper_FLA"); #endif typedef BASE(F) Real; const Int m = A.Height(); const Int n = A.Width(); const Int k = Min( m, n ); const Int offdiagonal = ( m>=n ? 1 : -1 ); const Grid& g = A.Grid(); // Bidiagonalize A DistMatrix<F,STAR,STAR> tP(g), tQ(g); Bidiag( A, tP, tQ ); // Grab copies of the diagonal and sub/super-diagonal of A DistMatrix<Real,MD,STAR> d_MD_STAR(g), e_MD_STAR(g); A.GetRealPartOfDiagonal( d_MD_STAR ); A.GetRealPartOfDiagonal( e_MD_STAR, offdiagonal ); // In order to use serial QR kernels, we need the full bidiagonal matrix // on each process DistMatrix<Real,STAR,STAR> d_STAR_STAR( d_MD_STAR ), e_STAR_STAR( e_MD_STAR ); // Initialize U and VAdj to the appropriate identity matrices DistMatrix<F,VC,STAR> U_VC_STAR(g), V_VC_STAR(g); U_VC_STAR.AlignWith( A ); V_VC_STAR.AlignWith( V ); Identity( U_VC_STAR, m, k ); Identity( V_VC_STAR, n, k ); FlaSVD ( k, U_VC_STAR.LocalHeight(), V_VC_STAR.LocalHeight(), d_STAR_STAR.Buffer(), e_STAR_STAR.Buffer(), U_VC_STAR.Buffer(), U_VC_STAR.LDim(), V_VC_STAR.Buffer(), V_VC_STAR.LDim() ); // Make a copy of A (for the Householder vectors) and pull the necessary // portions of U and V into a standard matrix dist. DistMatrix<F> B( A ); if( m >= n ) { DistMatrix<F> AT(g), AB(g); DistMatrix<F,VC,STAR> UT_VC_STAR(g), UB_VC_STAR(g); PartitionDown( A, AT, AB, n ); PartitionDown( U_VC_STAR, UT_VC_STAR, UB_VC_STAR, n ); AT = UT_VC_STAR; MakeZeros( AB ); V = V_VC_STAR; } else { DistMatrix<F> VT(g), VB(g); DistMatrix<F,VC,STAR> VT_VC_STAR(g), VB_VC_STAR(g); PartitionDown( V, VT, VB, m ); PartitionDown( V_VC_STAR, VT_VC_STAR, VB_VC_STAR, m ); VT = VT_VC_STAR; MakeZeros( VB ); } // Backtransform U and V bidiag::ApplyU( LEFT, NORMAL, B, tQ, A ); bidiag::ApplyV( LEFT, NORMAL, B, tP, V ); // Copy out the appropriate subset of the singular values s = d_STAR_STAR; }
void TestCorrectness ( bool print, UpperOrLower uplo, const DistMatrix<F>& A, const DistMatrix<F,STAR,STAR>& t, DistMatrix<F>& AOrig ) { typedef BASE(F) Real; const Grid& g = A.Grid(); const Int m = AOrig.Height(); Int subdiagonal = ( uplo==LOWER ? -1 : +1 ); if( g.Rank() == 0 ) cout << "Testing error..." << endl; // Grab the diagonal and subdiagonal of the symmetric tridiagonal matrix DistMatrix<Real,MD,STAR> d(g); DistMatrix<Real,MD,STAR> e(g); A.GetRealPartOfDiagonal( d ); A.GetRealPartOfDiagonal( e, subdiagonal ); // Grab a full copy of e so that we may fill the opposite subdiagonal DistMatrix<Real,STAR,STAR> e_STAR_STAR(g); DistMatrix<Real,MD,STAR> eOpposite(g); e_STAR_STAR = e; eOpposite.AlignWithDiagonal( A.DistData(), -subdiagonal ); eOpposite = e_STAR_STAR; // Zero B and then fill its tridiagonal DistMatrix<F> B(g); B.AlignWith( A ); Zeros( B, m, m ); B.SetRealPartOfDiagonal( d ); B.SetRealPartOfDiagonal( e, subdiagonal ); B.SetRealPartOfDiagonal( eOpposite, -subdiagonal ); if( print ) Print( B, "Tridiagonal" ); // Reverse the accumulated Householder transforms, ignoring symmetry hermitian_tridiag::ApplyQ( LEFT, uplo, NORMAL, A, t, B ); hermitian_tridiag::ApplyQ( RIGHT, uplo, ADJOINT, A, t, B ); if( print ) Print( B, "Rotated tridiagonal" ); // Compare the appropriate triangle of AOrig and B MakeTriangular( uplo, AOrig ); MakeTriangular( uplo, B ); Axpy( F(-1), AOrig, B ); if( print ) Print( B, "Error in rotated tridiagonal" ); const Real infNormOfAOrig = HermitianInfinityNorm( uplo, AOrig ); const Real frobNormOfAOrig = HermitianFrobeniusNorm( uplo, AOrig ); const Real infNormOfError = HermitianInfinityNorm( uplo, B ); const Real frobNormOfError = HermitianFrobeniusNorm( uplo, B ); if( g.Rank() == 0 ) { cout << " ||AOrig||_1 = ||AOrig||_oo = " << infNormOfAOrig << "\n" << " ||AOrig||_F = " << frobNormOfAOrig << "\n" << " ||AOrig - Q^H A Q||_oo = " << infNormOfError << "\n" << " ||AOrig - Q^H A Q||_F = " << frobNormOfError << endl; } }
void TestCorrectness ( bool print, UpperOrLower uplo, const DistMatrix<Complex<R> >& A, const DistMatrix<Complex<R>,STAR,STAR>& t, DistMatrix<Complex<R> >& AOrig ) { typedef Complex<R> C; const Grid& g = A.Grid(); const int m = AOrig.Height(); int subdiagonal = ( uplo==LOWER ? -1 : +1 ); if( g.Rank() == 0 ) cout << "Testing error..." << endl; // Grab the diagonal and subdiagonal of the symmetric tridiagonal matrix DistMatrix<R,MD,STAR> d(g); DistMatrix<R,MD,STAR> e(g); A.GetRealPartOfDiagonal( d ); A.GetRealPartOfDiagonal( e, subdiagonal ); // Grab a full copy of e so that we may fill the opposite subdiagonal DistMatrix<R,STAR,STAR> e_STAR_STAR(g); DistMatrix<R,MD,STAR> eOpposite(g); e_STAR_STAR = e; eOpposite.AlignWithDiagonal( A, -subdiagonal ); eOpposite = e_STAR_STAR; // Zero B and then fill its tridiagonal DistMatrix<C> B(g); B.AlignWith( A ); Zeros( m, m, B ); B.SetRealPartOfDiagonal( d ); B.SetRealPartOfDiagonal( e, subdiagonal ); B.SetRealPartOfDiagonal( eOpposite, -subdiagonal ); // Reverse the accumulated Householder transforms, ignoring symmetry if( uplo == LOWER ) { ApplyPackedReflectors ( LEFT, LOWER, VERTICAL, BACKWARD, UNCONJUGATED, subdiagonal, A, t, B ); ApplyPackedReflectors ( RIGHT, LOWER, VERTICAL, BACKWARD, CONJUGATED, subdiagonal, A, t, B ); } else { ApplyPackedReflectors ( LEFT, UPPER, VERTICAL, FORWARD, UNCONJUGATED, subdiagonal, A, t, B ); ApplyPackedReflectors ( RIGHT, UPPER, VERTICAL, FORWARD, CONJUGATED, subdiagonal, A, t, B ); } // Compare the appropriate triangle of AOrig and B MakeTriangular( uplo, AOrig ); MakeTriangular( uplo, B ); Axpy( C(-1), AOrig, B ); const R infNormOfAOrig = HermitianNorm( uplo, AOrig, INFINITY_NORM ); const R frobNormOfAOrig = HermitianNorm( uplo, AOrig, FROBENIUS_NORM ); const R infNormOfError = HermitianNorm( uplo, B, INFINITY_NORM ); const R frobNormOfError = HermitianNorm( uplo, B, FROBENIUS_NORM ); if( g.Rank() == 0 ) { cout << " ||AOrig||_1 = ||AOrig||_oo = " << infNormOfAOrig << "\n" << " ||AOrig||_F = " << frobNormOfAOrig << "\n" << " ||AOrig - Q^H A Q||_oo = " << infNormOfError << "\n" << " ||AOrig - Q^H A Q||_F = " << frobNormOfError << endl; } }
inline void SimpleSVDUpper ( DistMatrix<Complex<double> >& A, DistMatrix<double,VR,STAR>& s, DistMatrix<Complex<double> >& V ) { #ifndef RELEASE PushCallStack("svd::SimpleSVDUpper"); #endif typedef double Real; typedef Complex<Real> C; const int m = A.Height(); const int n = A.Width(); const int k = std::min( m, n ); const int offdiagonal = ( m>=n ? 1 : -1 ); const char uplo = ( m>=n ? 'U' : 'L' ); const Grid& g = A.Grid(); // Bidiagonalize A DistMatrix<C,STAR,STAR> tP( g ), tQ( g ); Bidiag( A, tP, tQ ); // Grab copies of the diagonal and sub/super-diagonal of A DistMatrix<Real,MD,STAR> d_MD_STAR( g ), e_MD_STAR( g ); A.GetRealPartOfDiagonal( d_MD_STAR ); A.GetRealPartOfDiagonal( e_MD_STAR, offdiagonal ); // In order to use serial QR kernels, we need the full bidiagonal matrix // on each process DistMatrix<Real,STAR,STAR> d_STAR_STAR( d_MD_STAR ), e_STAR_STAR( e_MD_STAR ); // Initialize U and VAdj to the appropriate identity matrices DistMatrix<C,VC,STAR> U_VC_STAR( g ); DistMatrix<C,VC,STAR> V_VC_STAR( g ); U_VC_STAR.AlignWith( A ); V_VC_STAR.AlignWith( V ); Identity( m, k, U_VC_STAR ); Identity( n, k, V_VC_STAR ); // Compute the SVD of the bidiagonal matrix and accumulate the Givens // rotations into our local portion of U and V // NOTE: This _only_ works in the case where m >= n const int numAccum = 32; const int maxNumIts = 30; const int bAlg = 512; std::vector<C> GBuffer( (k-1)*numAccum ), HBuffer( (k-1)*numAccum ); FLA_Bsvd_v_opz_var1 ( k, U_VC_STAR.LocalHeight(), V_VC_STAR.LocalHeight(), numAccum, maxNumIts, d_STAR_STAR.LocalBuffer(), 1, e_STAR_STAR.LocalBuffer(), 1, &GBuffer[0], 1, k-1, &HBuffer[0], 1, k-1, U_VC_STAR.LocalBuffer(), 1, U_VC_STAR.LocalLDim(), V_VC_STAR.LocalBuffer(), 1, V_VC_STAR.LocalLDim(), bAlg ); // Make a copy of A (for the Householder vectors) and pull the necessary // portions of U and V into a standard matrix dist. DistMatrix<C> B( A ); if( m >= n ) { DistMatrix<C> AT( g ), AB( g ); DistMatrix<C,VC,STAR> UT_VC_STAR( g ), UB_VC_STAR( g ); PartitionDown( A, AT, AB, n ); PartitionDown( U_VC_STAR, UT_VC_STAR, UB_VC_STAR, n ); AT = UT_VC_STAR; MakeZeros( AB ); V = V_VC_STAR; } else { DistMatrix<C> VT( g ), VB( g ); DistMatrix<C,VC,STAR> VT_VC_STAR( g ), VB_VC_STAR( g ); PartitionDown( V, VT, VB, m ); PartitionDown ( V_VC_STAR, VT_VC_STAR, VB_VC_STAR, m ); VT = VT_VC_STAR; MakeZeros( VB ); } // Backtransform U and V if( m >= n ) { ApplyPackedReflectors ( LEFT, LOWER, VERTICAL, BACKWARD, UNCONJUGATED, 0, B, tQ, A ); ApplyPackedReflectors ( LEFT, UPPER, HORIZONTAL, BACKWARD, UNCONJUGATED, 1, B, tP, V ); } else { ApplyPackedReflectors ( LEFT, LOWER, VERTICAL, BACKWARD, UNCONJUGATED, -1, B, tQ, A ); ApplyPackedReflectors ( LEFT, UPPER, HORIZONTAL, BACKWARD, UNCONJUGATED, 0, B, tP, V ); } // Copy out the appropriate subset of the singular values s = d_STAR_STAR; #ifndef RELEASE PopCallStack(); #endif }
inline void SimpleSVDUpper ( DistMatrix<Complex<Real> >& A, DistMatrix<Real,VR,STAR>& s, DistMatrix<Complex<Real> >& V ) { #ifndef RELEASE PushCallStack("svd::SimpleSVDUpper"); #endif typedef Complex<Real> C; const int m = A.Height(); const int n = A.Width(); const int k = std::min( m, n ); const int offdiagonal = ( m>=n ? 1 : -1 ); const char uplo = ( m>=n ? 'U' : 'L' ); const Grid& g = A.Grid(); // Bidiagonalize A DistMatrix<C,STAR,STAR> tP( g ), tQ( g ); Bidiag( A, tP, tQ ); // Grab copies of the diagonal and sub/super-diagonal of A DistMatrix<Real,MD,STAR> d_MD_STAR( g ), e_MD_STAR( g ); A.GetRealPartOfDiagonal( d_MD_STAR ); A.GetRealPartOfDiagonal( e_MD_STAR, offdiagonal ); // NOTE: lapack::BidiagQRAlg expects e to be of length k DistMatrix<Real,STAR,STAR> d_STAR_STAR( d_MD_STAR ); DistMatrix<Real,STAR,STAR> eHat_STAR_STAR( k, 1, g ); DistMatrix<Real,STAR,STAR> e_STAR_STAR( g ); e_STAR_STAR.View( eHat_STAR_STAR, 0, 0, k-1, 1 ); e_STAR_STAR = e_MD_STAR; // Initialize U and VAdj to the appropriate identity matrices DistMatrix<C,VC,STAR> U_VC_STAR( g ); DistMatrix<C,STAR,VC> VAdj_STAR_VC( g ); U_VC_STAR.AlignWith( A ); VAdj_STAR_VC.AlignWith( V ); Identity( m, k, U_VC_STAR ); Identity( k, n, VAdj_STAR_VC ); // Compute the SVD of the bidiagonal matrix and accumulate the Givens // rotations into our local portion of U and VAdj Matrix<C>& ULocal = U_VC_STAR.LocalMatrix(); Matrix<C>& VAdjLocal = VAdj_STAR_VC.LocalMatrix(); lapack::BidiagQRAlg ( uplo, k, VAdjLocal.Width(), ULocal.Height(), d_STAR_STAR.LocalBuffer(), e_STAR_STAR.LocalBuffer(), VAdjLocal.Buffer(), VAdjLocal.LDim(), ULocal.Buffer(), ULocal.LDim() ); // Make a copy of A (for the Householder vectors) and pull the necessary // portions of U and VAdj into a standard matrix dist. DistMatrix<C> B( A ); if( m >= n ) { DistMatrix<C> AT( g ), AB( g ); DistMatrix<C,VC,STAR> UT_VC_STAR( g ), UB_VC_STAR( g ); PartitionDown( A, AT, AB, n ); PartitionDown( U_VC_STAR, UT_VC_STAR, UB_VC_STAR, n ); AT = UT_VC_STAR; MakeZeros( AB ); Adjoint( VAdj_STAR_VC, V ); } else { DistMatrix<C> VT( g ), VB( g ); DistMatrix<C,STAR,VC> VAdjL_STAR_VC( g ), VAdjR_STAR_VC( g ); PartitionDown( V, VT, VB, m ); PartitionRight( VAdj_STAR_VC, VAdjL_STAR_VC, VAdjR_STAR_VC, m ); Adjoint( VAdjL_STAR_VC, VT ); MakeZeros( VB ); } // Backtransform U and V if( m >= n ) { ApplyPackedReflectors ( LEFT, LOWER, VERTICAL, BACKWARD, UNCONJUGATED, 0, B, tQ, A ); ApplyPackedReflectors ( LEFT, UPPER, HORIZONTAL, BACKWARD, UNCONJUGATED, 1, B, tP, V ); } else { ApplyPackedReflectors ( LEFT, LOWER, VERTICAL, BACKWARD, UNCONJUGATED, -1, B, tQ, A ); ApplyPackedReflectors ( LEFT, UPPER, HORIZONTAL, BACKWARD, UNCONJUGATED, 0, B, tP, V ); } // Copy out the appropriate subset of the singular values s = d_STAR_STAR; #ifndef RELEASE PopCallStack(); #endif }