diff options
author | Gael Guennebaud <g.gael@free.fr> | 2009-09-03 17:08:38 +0200 |
---|---|---|
committer | Gael Guennebaud <g.gael@free.fr> | 2009-09-03 17:08:38 +0200 |
commit | 82ad37c730264a8acd119f328a7007b93257246c (patch) | |
tree | d099dea56a3875d8f8eed78bae84efcc2618396f /Eigen | |
parent | 41aea9508e55b83f3834d189ef87118b9066b106 (diff) |
implement the continuous generation algorithm of Givens rotations by Anderson (2000)
Diffstat (limited to 'Eigen')
-rw-r--r-- | Eigen/src/Jacobi/Jacobi.h | 107 |
1 files changed, 78 insertions, 29 deletions
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<typename Scalar> 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<Derived>&, int, int), MatrixBase::applyOnTheLeft(), MatrixBase::applyOnTheRight() */ @@ -123,7 +123,7 @@ bool PlanarRotation<Scalar>::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<Scalar>::makeJacobi(const MatrixBase<Derived>& 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<Scalar>::makeJacobi(const MatrixBase<Derived>& 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<typename Scalar> @@ -159,52 +163,97 @@ void PlanarRotation<Scalar>::makeGivens(const Scalar& p, const Scalar& q, Scalar // specialization for complexes template<typename Scalar> -void PlanarRotation<Scalar>::makeGivens(const Scalar& p, const Scalar& q, Scalar* z, ei_meta_true) +void PlanarRotation<Scalar>::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)<RealScalar(0)) + u = -u; + + m_c = Scalar(1)/u; + m_s = -qs*ei_conj(ps)*(m_c/p2); + if(r) *r = p * u; + } + else + { + Scalar ps = p / q1; + RealScalar p2 = ei_abs2(ps); + Scalar qs = q / q1; + RealScalar q2 = ei_abs2(qs); + + RealScalar u = q1 * ei_sqrt(p2 + q2); + if(ei_real(p)<RealScalar(0)) + u = -u; + + p1 = ei_abs(p); + ps = p/p1; + m_c = p1/u; + m_s = -ei_conj(ps) * (q/u); + if(r) *r = ps * u; + } } } // specialization for reals -// TODO compute z template<typename Scalar> -void PlanarRotation<Scalar>::makeGivens(const Scalar& p, const Scalar& q, Scalar* z, ei_meta_false) +void PlanarRotation<Scalar>::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 = p<Scalar(0) ? Scalar(-1) : Scalar(1); + m_s = 0; + if(r) *r = ei_abs(p); } - else if(ei_abs(q)>ei_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 = q<Scalar(0) ? Scalar(1) : Scalar(-1); + if(r) *r = ei_abs(q); + } + else if(p>q) + { + Scalar t = q/p; + Scalar u = ei_sqrt(Scalar(1) + ei_abs2(t)); + if(p<Scalar(0)) + u = -u; + m_c = Scalar(1)/u; + m_s = -t * m_c; + if(r) *r = p * u; } else { - Scalar t = -q/p; - m_c = Scalar(1)/ei_sqrt(1+t*t); - m_s = m_c * t; + Scalar t = p/q; + Scalar u = ei_sqrt(Scalar(1) + ei_abs2(t)); + if(q<Scalar(0)) + u = -u; + m_s = -Scalar(1)/u; + m_c = t * m_s; + if(r) *r = q * u; } + } /**************************************************************************************** |