From 82ad37c730264a8acd119f328a7007b93257246c Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 3 Sep 2009 17:08:38 +0200 Subject: implement the continuous generation algorithm of Givens rotations by Anderson (2000) --- Eigen/src/Jacobi/Jacobi.h | 107 +++++++++++++++++++++++++++++++++------------- 1 file changed, 78 insertions(+), 29 deletions(-) (limited to 'Eigen/src/Jacobi') diff --git a/Eigen/src/Jacobi/Jacobi.h b/Eigen/src/Jacobi/Jacobi.h index 3e3cce665..7fd57ed5f 100644 --- a/Eigen/src/Jacobi/Jacobi.h +++ b/Eigen/src/Jacobi/Jacobi.h @@ -87,7 +87,7 @@ template class PlanarRotation }; /** Makes \c *this as a Jacobi rotation \a J such that applying \a J on both the right and left sides of the selfadjoint 2x2 matrix - * \f$ B = \left ( \begin{array}{cc} x & y \\ * & z \end{array} \right )\f$ yields a diagonal matrix \f$ A = J^* B J \f$ + * \f$ B = \left ( \begin{array}{cc} x & y \\ \overline y & z \end{array} \right )\f$ yields a diagonal matrix \f$ A = J^* B J \f$ * * \sa MatrixBase::makeJacobi(const MatrixBase&, int, int), MatrixBase::applyOnTheLeft(), MatrixBase::applyOnTheRight() */ @@ -123,7 +123,7 @@ bool PlanarRotation::makeJacobi(RealScalar x, Scalar y, RealScalar z) } /** Makes \c *this as a Jacobi rotation \c J such that applying \a J on both the right and left sides of the 2x2 selfadjoint matrix - * \f$ B = \left ( \begin{array}{cc} \text{this}_{pp} & \text{this}_{pq} \\ * & \text{this}_{qq} \end{array} \right )\f$ yields + * \f$ B = \left ( \begin{array}{cc} \text{this}_{pp} & \text{this}_{pq} \\ \overline \text{this}_{pq} & \text{this}_{qq} \end{array} \right )\f$ yields * a diagonal matrix \f$ A = J^* B J \f$ * * Example: \include Jacobi_makeJacobi.cpp @@ -140,7 +140,7 @@ inline bool PlanarRotation::makeJacobi(const MatrixBase& m, int /** Makes \c *this as a Givens rotation \c G such that applying \f$ G^* \f$ to the left of the vector * \f$ V = \left ( \begin{array}{c} p \\ q \end{array} \right )\f$ yields: - * \f$ G^* V = \left ( \begin{array}{c} z \\ 0 \end{array} \right )\f$. + * \f$ G^* V = \left ( \begin{array}{c} r \\ 0 \end{array} \right )\f$. * * The value of \a z is returned if \a z is not null (the default is null). * Also note that G is built such that the cosine is always real. @@ -148,6 +148,10 @@ inline bool PlanarRotation::makeJacobi(const MatrixBase& m, int * Example: \include Jacobi_makeGivens.cpp * Output: \verbinclude Jacobi_makeGivens.out * + * This function implements the continuous Givens rotation generation algorithm + * found in Anderson (2000), Discontinuous Plane Rotations and the Symmetric Eigenvalue Problem. + * LAPACK Working Note 150, University of Tennessee, UT-CS-00-454, December 4, 2000. + * * \sa MatrixBase::applyOnTheLeft(), MatrixBase::applyOnTheRight() */ template @@ -159,52 +163,97 @@ void PlanarRotation::makeGivens(const Scalar& p, const Scalar& q, Scalar // specialization for complexes template -void PlanarRotation::makeGivens(const Scalar& p, const Scalar& q, Scalar* z, ei_meta_true) +void PlanarRotation::makeGivens(const Scalar& p, const Scalar& q, Scalar* r, ei_meta_true) { - RealScalar scale, absx, absxy; if(q==Scalar(0)) { - // return identity - m_c = Scalar(1); - m_s = Scalar(0); - if(z) *z = p; + m_c = ei_real(p)<0 ? Scalar(-1) : Scalar(1); + m_s = 0; + if(r) *r = m_c * p; + } + else if(p==Scalar(0)) + { + m_c = 0; + m_s = -q/ei_abs(q); + if(r) *r = ei_abs(q); } else { - scale = ei_norm1(p); - absx = scale * ei_sqrt(ei_abs2(p/scale)); - scale = ei_abs(scale) + ei_norm1(q); - absxy = scale * ei_sqrt((absx/scale)*(absx/scale) + ei_abs2(q/scale)); - m_c = Scalar(absx / absxy); - Scalar np = p/absx; - m_s = -ei_conj(np) * q / absxy; - if(z) *z = np * absxy; + RealScalar p1 = ei_norm1(p); + RealScalar q1 = ei_norm1(q); + if(p1>=q1) + { + Scalar ps = p / p1; + RealScalar p2 = ei_abs2(ps); + Scalar qs = q / p1; + RealScalar q2 = ei_abs2(qs); + + RealScalar u = ei_sqrt(RealScalar(1) + q2/p2); + if(ei_real(p) -void PlanarRotation::makeGivens(const Scalar& p, const Scalar& q, Scalar* z, ei_meta_false) +void PlanarRotation::makeGivens(const Scalar& p, const Scalar& q, Scalar* r, ei_meta_false) { - ei_assert(z==0 && "not implemented yet"); - // from Golub's "Matrix Computations", algorithm 5.1.3 + if(q==0) { - m_c = 1; m_s = 0; + m_c = pei_abs(p)) + else if(p==0) { - Scalar t = -p/q; - m_s = Scalar(1)/ei_sqrt(1+t*t); - m_c = m_s * t; + m_c = 0; + m_s = qq) + { + Scalar t = q/p; + Scalar u = ei_sqrt(Scalar(1) + ei_abs2(t)); + if(p