xref: /aosp_15_r20/external/eigen/Eigen/src/Jacobi/Jacobi.h (revision bf2c37156dfe67e5dfebd6d394bad8b2ab5804d4)
1*bf2c3715SXin Li // This file is part of Eigen, a lightweight C++ template library
2*bf2c3715SXin Li // for linear algebra.
3*bf2c3715SXin Li //
4*bf2c3715SXin Li // Copyright (C) 2009 Benoit Jacob <[email protected]>
5*bf2c3715SXin Li // Copyright (C) 2009 Gael Guennebaud <[email protected]>
6*bf2c3715SXin Li //
7*bf2c3715SXin Li // This Source Code Form is subject to the terms of the Mozilla
8*bf2c3715SXin Li // Public License v. 2.0. If a copy of the MPL was not distributed
9*bf2c3715SXin Li // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
10*bf2c3715SXin Li 
11*bf2c3715SXin Li #ifndef EIGEN_JACOBI_H
12*bf2c3715SXin Li #define EIGEN_JACOBI_H
13*bf2c3715SXin Li 
14*bf2c3715SXin Li namespace Eigen {
15*bf2c3715SXin Li 
16*bf2c3715SXin Li /** \ingroup Jacobi_Module
17*bf2c3715SXin Li   * \jacobi_module
18*bf2c3715SXin Li   * \class JacobiRotation
19*bf2c3715SXin Li   * \brief Rotation given by a cosine-sine pair.
20*bf2c3715SXin Li   *
21*bf2c3715SXin Li   * This class represents a Jacobi or Givens rotation.
22*bf2c3715SXin Li   * This is a 2D rotation in the plane \c J of angle \f$ \theta \f$ defined by
23*bf2c3715SXin Li   * its cosine \c c and sine \c s as follow:
24*bf2c3715SXin Li   * \f$ J = \left ( \begin{array}{cc} c & \overline s \\ -s  & \overline c \end{array} \right ) \f$
25*bf2c3715SXin Li   *
26*bf2c3715SXin Li   * You can apply the respective counter-clockwise rotation to a column vector \c v by
27*bf2c3715SXin Li   * applying its adjoint on the left: \f$ v = J^* v \f$ that translates to the following Eigen code:
28*bf2c3715SXin Li   * \code
29*bf2c3715SXin Li   * v.applyOnTheLeft(J.adjoint());
30*bf2c3715SXin Li   * \endcode
31*bf2c3715SXin Li   *
32*bf2c3715SXin Li   * \sa MatrixBase::applyOnTheLeft(), MatrixBase::applyOnTheRight()
33*bf2c3715SXin Li   */
34*bf2c3715SXin Li template<typename Scalar> class JacobiRotation
35*bf2c3715SXin Li {
36*bf2c3715SXin Li   public:
37*bf2c3715SXin Li     typedef typename NumTraits<Scalar>::Real RealScalar;
38*bf2c3715SXin Li 
39*bf2c3715SXin Li     /** Default constructor without any initialization. */
40*bf2c3715SXin Li     EIGEN_DEVICE_FUNC
JacobiRotation()41*bf2c3715SXin Li     JacobiRotation() {}
42*bf2c3715SXin Li 
43*bf2c3715SXin Li     /** Construct a planar rotation from a cosine-sine pair (\a c, \c s). */
44*bf2c3715SXin Li     EIGEN_DEVICE_FUNC
JacobiRotation(const Scalar & c,const Scalar & s)45*bf2c3715SXin Li     JacobiRotation(const Scalar& c, const Scalar& s) : m_c(c), m_s(s) {}
46*bf2c3715SXin Li 
c()47*bf2c3715SXin Li     EIGEN_DEVICE_FUNC Scalar& c() { return m_c; }
c()48*bf2c3715SXin Li     EIGEN_DEVICE_FUNC Scalar c() const { return m_c; }
s()49*bf2c3715SXin Li     EIGEN_DEVICE_FUNC Scalar& s() { return m_s; }
s()50*bf2c3715SXin Li     EIGEN_DEVICE_FUNC Scalar s() const { return m_s; }
51*bf2c3715SXin Li 
52*bf2c3715SXin Li     /** Concatenates two planar rotation */
53*bf2c3715SXin Li     EIGEN_DEVICE_FUNC
54*bf2c3715SXin Li     JacobiRotation operator*(const JacobiRotation& other)
55*bf2c3715SXin Li     {
56*bf2c3715SXin Li       using numext::conj;
57*bf2c3715SXin Li       return JacobiRotation(m_c * other.m_c - conj(m_s) * other.m_s,
58*bf2c3715SXin Li                             conj(m_c * conj(other.m_s) + conj(m_s) * conj(other.m_c)));
59*bf2c3715SXin Li     }
60*bf2c3715SXin Li 
61*bf2c3715SXin Li     /** Returns the transposed transformation */
62*bf2c3715SXin Li     EIGEN_DEVICE_FUNC
transpose()63*bf2c3715SXin Li     JacobiRotation transpose() const { using numext::conj; return JacobiRotation(m_c, -conj(m_s)); }
64*bf2c3715SXin Li 
65*bf2c3715SXin Li     /** Returns the adjoint transformation */
66*bf2c3715SXin Li     EIGEN_DEVICE_FUNC
adjoint()67*bf2c3715SXin Li     JacobiRotation adjoint() const { using numext::conj; return JacobiRotation(conj(m_c), -m_s); }
68*bf2c3715SXin Li 
69*bf2c3715SXin Li     template<typename Derived>
70*bf2c3715SXin Li     EIGEN_DEVICE_FUNC
71*bf2c3715SXin Li     bool makeJacobi(const MatrixBase<Derived>&, Index p, Index q);
72*bf2c3715SXin Li     EIGEN_DEVICE_FUNC
73*bf2c3715SXin Li     bool makeJacobi(const RealScalar& x, const Scalar& y, const RealScalar& z);
74*bf2c3715SXin Li 
75*bf2c3715SXin Li     EIGEN_DEVICE_FUNC
76*bf2c3715SXin Li     void makeGivens(const Scalar& p, const Scalar& q, Scalar* r=0);
77*bf2c3715SXin Li 
78*bf2c3715SXin Li   protected:
79*bf2c3715SXin Li     EIGEN_DEVICE_FUNC
80*bf2c3715SXin Li     void makeGivens(const Scalar& p, const Scalar& q, Scalar* r, internal::true_type);
81*bf2c3715SXin Li     EIGEN_DEVICE_FUNC
82*bf2c3715SXin Li     void makeGivens(const Scalar& p, const Scalar& q, Scalar* r, internal::false_type);
83*bf2c3715SXin Li 
84*bf2c3715SXin Li     Scalar m_c, m_s;
85*bf2c3715SXin Li };
86*bf2c3715SXin Li 
87*bf2c3715SXin Li /** 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
88*bf2c3715SXin Li   * \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$
89*bf2c3715SXin Li   *
90*bf2c3715SXin Li   * \sa MatrixBase::makeJacobi(const MatrixBase<Derived>&, Index, Index), MatrixBase::applyOnTheLeft(), MatrixBase::applyOnTheRight()
91*bf2c3715SXin Li   */
92*bf2c3715SXin Li template<typename Scalar>
93*bf2c3715SXin Li EIGEN_DEVICE_FUNC
makeJacobi(const RealScalar & x,const Scalar & y,const RealScalar & z)94*bf2c3715SXin Li bool JacobiRotation<Scalar>::makeJacobi(const RealScalar& x, const Scalar& y, const RealScalar& z)
95*bf2c3715SXin Li {
96*bf2c3715SXin Li   using std::sqrt;
97*bf2c3715SXin Li   using std::abs;
98*bf2c3715SXin Li 
99*bf2c3715SXin Li   RealScalar deno = RealScalar(2)*abs(y);
100*bf2c3715SXin Li   if(deno < (std::numeric_limits<RealScalar>::min)())
101*bf2c3715SXin Li   {
102*bf2c3715SXin Li     m_c = Scalar(1);
103*bf2c3715SXin Li     m_s = Scalar(0);
104*bf2c3715SXin Li     return false;
105*bf2c3715SXin Li   }
106*bf2c3715SXin Li   else
107*bf2c3715SXin Li   {
108*bf2c3715SXin Li     RealScalar tau = (x-z)/deno;
109*bf2c3715SXin Li     RealScalar w = sqrt(numext::abs2(tau) + RealScalar(1));
110*bf2c3715SXin Li     RealScalar t;
111*bf2c3715SXin Li     if(tau>RealScalar(0))
112*bf2c3715SXin Li     {
113*bf2c3715SXin Li       t = RealScalar(1) / (tau + w);
114*bf2c3715SXin Li     }
115*bf2c3715SXin Li     else
116*bf2c3715SXin Li     {
117*bf2c3715SXin Li       t = RealScalar(1) / (tau - w);
118*bf2c3715SXin Li     }
119*bf2c3715SXin Li     RealScalar sign_t = t > RealScalar(0) ? RealScalar(1) : RealScalar(-1);
120*bf2c3715SXin Li     RealScalar n = RealScalar(1) / sqrt(numext::abs2(t)+RealScalar(1));
121*bf2c3715SXin Li     m_s = - sign_t * (numext::conj(y) / abs(y)) * abs(t) * n;
122*bf2c3715SXin Li     m_c = n;
123*bf2c3715SXin Li     return true;
124*bf2c3715SXin Li   }
125*bf2c3715SXin Li }
126*bf2c3715SXin Li 
127*bf2c3715SXin Li /** 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
128*bf2c3715SXin Li   * \f$ B = \left ( \begin{array}{cc} \text{this}_{pp} & \text{this}_{pq} \\ (\text{this}_{pq})^* & \text{this}_{qq} \end{array} \right )\f$ yields
129*bf2c3715SXin Li   * a diagonal matrix \f$ A = J^* B J \f$
130*bf2c3715SXin Li   *
131*bf2c3715SXin Li   * Example: \include Jacobi_makeJacobi.cpp
132*bf2c3715SXin Li   * Output: \verbinclude Jacobi_makeJacobi.out
133*bf2c3715SXin Li   *
134*bf2c3715SXin Li   * \sa JacobiRotation::makeJacobi(RealScalar, Scalar, RealScalar), MatrixBase::applyOnTheLeft(), MatrixBase::applyOnTheRight()
135*bf2c3715SXin Li   */
136*bf2c3715SXin Li template<typename Scalar>
137*bf2c3715SXin Li template<typename Derived>
138*bf2c3715SXin Li EIGEN_DEVICE_FUNC
makeJacobi(const MatrixBase<Derived> & m,Index p,Index q)139*bf2c3715SXin Li inline bool JacobiRotation<Scalar>::makeJacobi(const MatrixBase<Derived>& m, Index p, Index q)
140*bf2c3715SXin Li {
141*bf2c3715SXin Li   return makeJacobi(numext::real(m.coeff(p,p)), m.coeff(p,q), numext::real(m.coeff(q,q)));
142*bf2c3715SXin Li }
143*bf2c3715SXin Li 
144*bf2c3715SXin Li /** Makes \c *this as a Givens rotation \c G such that applying \f$ G^* \f$ to the left of the vector
145*bf2c3715SXin Li   * \f$ V = \left ( \begin{array}{c} p \\ q \end{array} \right )\f$ yields:
146*bf2c3715SXin Li   * \f$ G^* V = \left ( \begin{array}{c} r \\ 0 \end{array} \right )\f$.
147*bf2c3715SXin Li   *
148*bf2c3715SXin Li   * The value of \a r is returned if \a r is not null (the default is null).
149*bf2c3715SXin Li   * Also note that G is built such that the cosine is always real.
150*bf2c3715SXin Li   *
151*bf2c3715SXin Li   * Example: \include Jacobi_makeGivens.cpp
152*bf2c3715SXin Li   * Output: \verbinclude Jacobi_makeGivens.out
153*bf2c3715SXin Li   *
154*bf2c3715SXin Li   * This function implements the continuous Givens rotation generation algorithm
155*bf2c3715SXin Li   * found in Anderson (2000), Discontinuous Plane Rotations and the Symmetric Eigenvalue Problem.
156*bf2c3715SXin Li   * LAPACK Working Note 150, University of Tennessee, UT-CS-00-454, December 4, 2000.
157*bf2c3715SXin Li   *
158*bf2c3715SXin Li   * \sa MatrixBase::applyOnTheLeft(), MatrixBase::applyOnTheRight()
159*bf2c3715SXin Li   */
160*bf2c3715SXin Li template<typename Scalar>
161*bf2c3715SXin Li EIGEN_DEVICE_FUNC
makeGivens(const Scalar & p,const Scalar & q,Scalar * r)162*bf2c3715SXin Li void JacobiRotation<Scalar>::makeGivens(const Scalar& p, const Scalar& q, Scalar* r)
163*bf2c3715SXin Li {
164*bf2c3715SXin Li   makeGivens(p, q, r, typename internal::conditional<NumTraits<Scalar>::IsComplex, internal::true_type, internal::false_type>::type());
165*bf2c3715SXin Li }
166*bf2c3715SXin Li 
167*bf2c3715SXin Li 
168*bf2c3715SXin Li // specialization for complexes
169*bf2c3715SXin Li template<typename Scalar>
170*bf2c3715SXin Li EIGEN_DEVICE_FUNC
makeGivens(const Scalar & p,const Scalar & q,Scalar * r,internal::true_type)171*bf2c3715SXin Li void JacobiRotation<Scalar>::makeGivens(const Scalar& p, const Scalar& q, Scalar* r, internal::true_type)
172*bf2c3715SXin Li {
173*bf2c3715SXin Li   using std::sqrt;
174*bf2c3715SXin Li   using std::abs;
175*bf2c3715SXin Li   using numext::conj;
176*bf2c3715SXin Li 
177*bf2c3715SXin Li   if(q==Scalar(0))
178*bf2c3715SXin Li   {
179*bf2c3715SXin Li     m_c = numext::real(p)<0 ? Scalar(-1) : Scalar(1);
180*bf2c3715SXin Li     m_s = 0;
181*bf2c3715SXin Li     if(r) *r = m_c * p;
182*bf2c3715SXin Li   }
183*bf2c3715SXin Li   else if(p==Scalar(0))
184*bf2c3715SXin Li   {
185*bf2c3715SXin Li     m_c = 0;
186*bf2c3715SXin Li     m_s = -q/abs(q);
187*bf2c3715SXin Li     if(r) *r = abs(q);
188*bf2c3715SXin Li   }
189*bf2c3715SXin Li   else
190*bf2c3715SXin Li   {
191*bf2c3715SXin Li     RealScalar p1 = numext::norm1(p);
192*bf2c3715SXin Li     RealScalar q1 = numext::norm1(q);
193*bf2c3715SXin Li     if(p1>=q1)
194*bf2c3715SXin Li     {
195*bf2c3715SXin Li       Scalar ps = p / p1;
196*bf2c3715SXin Li       RealScalar p2 = numext::abs2(ps);
197*bf2c3715SXin Li       Scalar qs = q / p1;
198*bf2c3715SXin Li       RealScalar q2 = numext::abs2(qs);
199*bf2c3715SXin Li 
200*bf2c3715SXin Li       RealScalar u = sqrt(RealScalar(1) + q2/p2);
201*bf2c3715SXin Li       if(numext::real(p)<RealScalar(0))
202*bf2c3715SXin Li         u = -u;
203*bf2c3715SXin Li 
204*bf2c3715SXin Li       m_c = Scalar(1)/u;
205*bf2c3715SXin Li       m_s = -qs*conj(ps)*(m_c/p2);
206*bf2c3715SXin Li       if(r) *r = p * u;
207*bf2c3715SXin Li     }
208*bf2c3715SXin Li     else
209*bf2c3715SXin Li     {
210*bf2c3715SXin Li       Scalar ps = p / q1;
211*bf2c3715SXin Li       RealScalar p2 = numext::abs2(ps);
212*bf2c3715SXin Li       Scalar qs = q / q1;
213*bf2c3715SXin Li       RealScalar q2 = numext::abs2(qs);
214*bf2c3715SXin Li 
215*bf2c3715SXin Li       RealScalar u = q1 * sqrt(p2 + q2);
216*bf2c3715SXin Li       if(numext::real(p)<RealScalar(0))
217*bf2c3715SXin Li         u = -u;
218*bf2c3715SXin Li 
219*bf2c3715SXin Li       p1 = abs(p);
220*bf2c3715SXin Li       ps = p/p1;
221*bf2c3715SXin Li       m_c = p1/u;
222*bf2c3715SXin Li       m_s = -conj(ps) * (q/u);
223*bf2c3715SXin Li       if(r) *r = ps * u;
224*bf2c3715SXin Li     }
225*bf2c3715SXin Li   }
226*bf2c3715SXin Li }
227*bf2c3715SXin Li 
228*bf2c3715SXin Li // specialization for reals
229*bf2c3715SXin Li template<typename Scalar>
230*bf2c3715SXin Li EIGEN_DEVICE_FUNC
makeGivens(const Scalar & p,const Scalar & q,Scalar * r,internal::false_type)231*bf2c3715SXin Li void JacobiRotation<Scalar>::makeGivens(const Scalar& p, const Scalar& q, Scalar* r, internal::false_type)
232*bf2c3715SXin Li {
233*bf2c3715SXin Li   using std::sqrt;
234*bf2c3715SXin Li   using std::abs;
235*bf2c3715SXin Li   if(q==Scalar(0))
236*bf2c3715SXin Li   {
237*bf2c3715SXin Li     m_c = p<Scalar(0) ? Scalar(-1) : Scalar(1);
238*bf2c3715SXin Li     m_s = Scalar(0);
239*bf2c3715SXin Li     if(r) *r = abs(p);
240*bf2c3715SXin Li   }
241*bf2c3715SXin Li   else if(p==Scalar(0))
242*bf2c3715SXin Li   {
243*bf2c3715SXin Li     m_c = Scalar(0);
244*bf2c3715SXin Li     m_s = q<Scalar(0) ? Scalar(1) : Scalar(-1);
245*bf2c3715SXin Li     if(r) *r = abs(q);
246*bf2c3715SXin Li   }
247*bf2c3715SXin Li   else if(abs(p) > abs(q))
248*bf2c3715SXin Li   {
249*bf2c3715SXin Li     Scalar t = q/p;
250*bf2c3715SXin Li     Scalar u = sqrt(Scalar(1) + numext::abs2(t));
251*bf2c3715SXin Li     if(p<Scalar(0))
252*bf2c3715SXin Li       u = -u;
253*bf2c3715SXin Li     m_c = Scalar(1)/u;
254*bf2c3715SXin Li     m_s = -t * m_c;
255*bf2c3715SXin Li     if(r) *r = p * u;
256*bf2c3715SXin Li   }
257*bf2c3715SXin Li   else
258*bf2c3715SXin Li   {
259*bf2c3715SXin Li     Scalar t = p/q;
260*bf2c3715SXin Li     Scalar u = sqrt(Scalar(1) + numext::abs2(t));
261*bf2c3715SXin Li     if(q<Scalar(0))
262*bf2c3715SXin Li       u = -u;
263*bf2c3715SXin Li     m_s = -Scalar(1)/u;
264*bf2c3715SXin Li     m_c = -t * m_s;
265*bf2c3715SXin Li     if(r) *r = q * u;
266*bf2c3715SXin Li   }
267*bf2c3715SXin Li 
268*bf2c3715SXin Li }
269*bf2c3715SXin Li 
270*bf2c3715SXin Li /****************************************************************************************
271*bf2c3715SXin Li *   Implementation of MatrixBase methods
272*bf2c3715SXin Li ****************************************************************************************/
273*bf2c3715SXin Li 
274*bf2c3715SXin Li namespace internal {
275*bf2c3715SXin Li /** \jacobi_module
276*bf2c3715SXin Li   * Applies the clock wise 2D rotation \a j to the set of 2D vectors of coordinates \a x and \a y:
277*bf2c3715SXin Li   * \f$ \left ( \begin{array}{cc} x \\ y \end{array} \right )  =  J \left ( \begin{array}{cc} x \\ y \end{array} \right ) \f$
278*bf2c3715SXin Li   *
279*bf2c3715SXin Li   * \sa MatrixBase::applyOnTheLeft(), MatrixBase::applyOnTheRight()
280*bf2c3715SXin Li   */
281*bf2c3715SXin Li template<typename VectorX, typename VectorY, typename OtherScalar>
282*bf2c3715SXin Li EIGEN_DEVICE_FUNC
283*bf2c3715SXin Li void apply_rotation_in_the_plane(DenseBase<VectorX>& xpr_x, DenseBase<VectorY>& xpr_y, const JacobiRotation<OtherScalar>& j);
284*bf2c3715SXin Li }
285*bf2c3715SXin Li 
286*bf2c3715SXin Li /** \jacobi_module
287*bf2c3715SXin Li   * Applies the rotation in the plane \a j to the rows \a p and \a q of \c *this, i.e., it computes B = J * B,
288*bf2c3715SXin Li   * with \f$ B = \left ( \begin{array}{cc} \text{*this.row}(p) \\ \text{*this.row}(q) \end{array} \right ) \f$.
289*bf2c3715SXin Li   *
290*bf2c3715SXin Li   * \sa class JacobiRotation, MatrixBase::applyOnTheRight(), internal::apply_rotation_in_the_plane()
291*bf2c3715SXin Li   */
292*bf2c3715SXin Li template<typename Derived>
293*bf2c3715SXin Li template<typename OtherScalar>
294*bf2c3715SXin Li EIGEN_DEVICE_FUNC
applyOnTheLeft(Index p,Index q,const JacobiRotation<OtherScalar> & j)295*bf2c3715SXin Li inline void MatrixBase<Derived>::applyOnTheLeft(Index p, Index q, const JacobiRotation<OtherScalar>& j)
296*bf2c3715SXin Li {
297*bf2c3715SXin Li   RowXpr x(this->row(p));
298*bf2c3715SXin Li   RowXpr y(this->row(q));
299*bf2c3715SXin Li   internal::apply_rotation_in_the_plane(x, y, j);
300*bf2c3715SXin Li }
301*bf2c3715SXin Li 
302*bf2c3715SXin Li /** \ingroup Jacobi_Module
303*bf2c3715SXin Li   * Applies the rotation in the plane \a j to the columns \a p and \a q of \c *this, i.e., it computes B = B * J
304*bf2c3715SXin Li   * with \f$ B = \left ( \begin{array}{cc} \text{*this.col}(p) & \text{*this.col}(q) \end{array} \right ) \f$.
305*bf2c3715SXin Li   *
306*bf2c3715SXin Li   * \sa class JacobiRotation, MatrixBase::applyOnTheLeft(), internal::apply_rotation_in_the_plane()
307*bf2c3715SXin Li   */
308*bf2c3715SXin Li template<typename Derived>
309*bf2c3715SXin Li template<typename OtherScalar>
310*bf2c3715SXin Li EIGEN_DEVICE_FUNC
applyOnTheRight(Index p,Index q,const JacobiRotation<OtherScalar> & j)311*bf2c3715SXin Li inline void MatrixBase<Derived>::applyOnTheRight(Index p, Index q, const JacobiRotation<OtherScalar>& j)
312*bf2c3715SXin Li {
313*bf2c3715SXin Li   ColXpr x(this->col(p));
314*bf2c3715SXin Li   ColXpr y(this->col(q));
315*bf2c3715SXin Li   internal::apply_rotation_in_the_plane(x, y, j.transpose());
316*bf2c3715SXin Li }
317*bf2c3715SXin Li 
318*bf2c3715SXin Li namespace internal {
319*bf2c3715SXin Li 
320*bf2c3715SXin Li template<typename Scalar, typename OtherScalar,
321*bf2c3715SXin Li          int SizeAtCompileTime, int MinAlignment, bool Vectorizable>
322*bf2c3715SXin Li struct apply_rotation_in_the_plane_selector
323*bf2c3715SXin Li {
324*bf2c3715SXin Li   static EIGEN_DEVICE_FUNC
runapply_rotation_in_the_plane_selector325*bf2c3715SXin Li   inline void run(Scalar *x, Index incrx, Scalar *y, Index incry, Index size, OtherScalar c, OtherScalar s)
326*bf2c3715SXin Li   {
327*bf2c3715SXin Li     for(Index i=0; i<size; ++i)
328*bf2c3715SXin Li     {
329*bf2c3715SXin Li       Scalar xi = *x;
330*bf2c3715SXin Li       Scalar yi = *y;
331*bf2c3715SXin Li       *x =  c * xi + numext::conj(s) * yi;
332*bf2c3715SXin Li       *y = -s * xi + numext::conj(c) * yi;
333*bf2c3715SXin Li       x += incrx;
334*bf2c3715SXin Li       y += incry;
335*bf2c3715SXin Li     }
336*bf2c3715SXin Li   }
337*bf2c3715SXin Li };
338*bf2c3715SXin Li 
339*bf2c3715SXin Li template<typename Scalar, typename OtherScalar,
340*bf2c3715SXin Li          int SizeAtCompileTime, int MinAlignment>
341*bf2c3715SXin Li struct apply_rotation_in_the_plane_selector<Scalar,OtherScalar,SizeAtCompileTime,MinAlignment,true /* vectorizable */>
342*bf2c3715SXin Li {
343*bf2c3715SXin Li   static inline void run(Scalar *x, Index incrx, Scalar *y, Index incry, Index size, OtherScalar c, OtherScalar s)
344*bf2c3715SXin Li   {
345*bf2c3715SXin Li     enum {
346*bf2c3715SXin Li       PacketSize = packet_traits<Scalar>::size,
347*bf2c3715SXin Li       OtherPacketSize = packet_traits<OtherScalar>::size
348*bf2c3715SXin Li     };
349*bf2c3715SXin Li     typedef typename packet_traits<Scalar>::type Packet;
350*bf2c3715SXin Li     typedef typename packet_traits<OtherScalar>::type OtherPacket;
351*bf2c3715SXin Li 
352*bf2c3715SXin Li     /*** dynamic-size vectorized paths ***/
353*bf2c3715SXin Li     if(SizeAtCompileTime == Dynamic && ((incrx==1 && incry==1) || PacketSize == 1))
354*bf2c3715SXin Li     {
355*bf2c3715SXin Li       // both vectors are sequentially stored in memory => vectorization
356*bf2c3715SXin Li       enum { Peeling = 2 };
357*bf2c3715SXin Li 
358*bf2c3715SXin Li       Index alignedStart = internal::first_default_aligned(y, size);
359*bf2c3715SXin Li       Index alignedEnd = alignedStart + ((size-alignedStart)/PacketSize)*PacketSize;
360*bf2c3715SXin Li 
361*bf2c3715SXin Li       const OtherPacket pc = pset1<OtherPacket>(c);
362*bf2c3715SXin Li       const OtherPacket ps = pset1<OtherPacket>(s);
363*bf2c3715SXin Li       conj_helper<OtherPacket,Packet,NumTraits<OtherScalar>::IsComplex,false> pcj;
364*bf2c3715SXin Li       conj_helper<OtherPacket,Packet,false,false> pm;
365*bf2c3715SXin Li 
366*bf2c3715SXin Li       for(Index i=0; i<alignedStart; ++i)
367*bf2c3715SXin Li       {
368*bf2c3715SXin Li         Scalar xi = x[i];
369*bf2c3715SXin Li         Scalar yi = y[i];
370*bf2c3715SXin Li         x[i] =  c * xi + numext::conj(s) * yi;
371*bf2c3715SXin Li         y[i] = -s * xi + numext::conj(c) * yi;
372*bf2c3715SXin Li       }
373*bf2c3715SXin Li 
374*bf2c3715SXin Li       Scalar* EIGEN_RESTRICT px = x + alignedStart;
375*bf2c3715SXin Li       Scalar* EIGEN_RESTRICT py = y + alignedStart;
376*bf2c3715SXin Li 
377*bf2c3715SXin Li       if(internal::first_default_aligned(x, size)==alignedStart)
378*bf2c3715SXin Li       {
379*bf2c3715SXin Li         for(Index i=alignedStart; i<alignedEnd; i+=PacketSize)
380*bf2c3715SXin Li         {
381*bf2c3715SXin Li           Packet xi = pload<Packet>(px);
382*bf2c3715SXin Li           Packet yi = pload<Packet>(py);
383*bf2c3715SXin Li           pstore(px, padd(pm.pmul(pc,xi),pcj.pmul(ps,yi)));
384*bf2c3715SXin Li           pstore(py, psub(pcj.pmul(pc,yi),pm.pmul(ps,xi)));
385*bf2c3715SXin Li           px += PacketSize;
386*bf2c3715SXin Li           py += PacketSize;
387*bf2c3715SXin Li         }
388*bf2c3715SXin Li       }
389*bf2c3715SXin Li       else
390*bf2c3715SXin Li       {
391*bf2c3715SXin Li         Index peelingEnd = alignedStart + ((size-alignedStart)/(Peeling*PacketSize))*(Peeling*PacketSize);
392*bf2c3715SXin Li         for(Index i=alignedStart; i<peelingEnd; i+=Peeling*PacketSize)
393*bf2c3715SXin Li         {
394*bf2c3715SXin Li           Packet xi   = ploadu<Packet>(px);
395*bf2c3715SXin Li           Packet xi1  = ploadu<Packet>(px+PacketSize);
396*bf2c3715SXin Li           Packet yi   = pload <Packet>(py);
397*bf2c3715SXin Li           Packet yi1  = pload <Packet>(py+PacketSize);
398*bf2c3715SXin Li           pstoreu(px, padd(pm.pmul(pc,xi),pcj.pmul(ps,yi)));
399*bf2c3715SXin Li           pstoreu(px+PacketSize, padd(pm.pmul(pc,xi1),pcj.pmul(ps,yi1)));
400*bf2c3715SXin Li           pstore (py, psub(pcj.pmul(pc,yi),pm.pmul(ps,xi)));
401*bf2c3715SXin Li           pstore (py+PacketSize, psub(pcj.pmul(pc,yi1),pm.pmul(ps,xi1)));
402*bf2c3715SXin Li           px += Peeling*PacketSize;
403*bf2c3715SXin Li           py += Peeling*PacketSize;
404*bf2c3715SXin Li         }
405*bf2c3715SXin Li         if(alignedEnd!=peelingEnd)
406*bf2c3715SXin Li         {
407*bf2c3715SXin Li           Packet xi = ploadu<Packet>(x+peelingEnd);
408*bf2c3715SXin Li           Packet yi = pload <Packet>(y+peelingEnd);
409*bf2c3715SXin Li           pstoreu(x+peelingEnd, padd(pm.pmul(pc,xi),pcj.pmul(ps,yi)));
410*bf2c3715SXin Li           pstore (y+peelingEnd, psub(pcj.pmul(pc,yi),pm.pmul(ps,xi)));
411*bf2c3715SXin Li         }
412*bf2c3715SXin Li       }
413*bf2c3715SXin Li 
414*bf2c3715SXin Li       for(Index i=alignedEnd; i<size; ++i)
415*bf2c3715SXin Li       {
416*bf2c3715SXin Li         Scalar xi = x[i];
417*bf2c3715SXin Li         Scalar yi = y[i];
418*bf2c3715SXin Li         x[i] =  c * xi + numext::conj(s) * yi;
419*bf2c3715SXin Li         y[i] = -s * xi + numext::conj(c) * yi;
420*bf2c3715SXin Li       }
421*bf2c3715SXin Li     }
422*bf2c3715SXin Li 
423*bf2c3715SXin Li     /*** fixed-size vectorized path ***/
424*bf2c3715SXin Li     else if(SizeAtCompileTime != Dynamic && MinAlignment>0) // FIXME should be compared to the required alignment
425*bf2c3715SXin Li     {
426*bf2c3715SXin Li       const OtherPacket pc = pset1<OtherPacket>(c);
427*bf2c3715SXin Li       const OtherPacket ps = pset1<OtherPacket>(s);
428*bf2c3715SXin Li       conj_helper<OtherPacket,Packet,NumTraits<OtherPacket>::IsComplex,false> pcj;
429*bf2c3715SXin Li       conj_helper<OtherPacket,Packet,false,false> pm;
430*bf2c3715SXin Li       Scalar* EIGEN_RESTRICT px = x;
431*bf2c3715SXin Li       Scalar* EIGEN_RESTRICT py = y;
432*bf2c3715SXin Li       for(Index i=0; i<size; i+=PacketSize)
433*bf2c3715SXin Li       {
434*bf2c3715SXin Li         Packet xi = pload<Packet>(px);
435*bf2c3715SXin Li         Packet yi = pload<Packet>(py);
436*bf2c3715SXin Li         pstore(px, padd(pm.pmul(pc,xi),pcj.pmul(ps,yi)));
437*bf2c3715SXin Li         pstore(py, psub(pcj.pmul(pc,yi),pm.pmul(ps,xi)));
438*bf2c3715SXin Li         px += PacketSize;
439*bf2c3715SXin Li         py += PacketSize;
440*bf2c3715SXin Li       }
441*bf2c3715SXin Li     }
442*bf2c3715SXin Li 
443*bf2c3715SXin Li     /*** non-vectorized path ***/
444*bf2c3715SXin Li     else
445*bf2c3715SXin Li     {
446*bf2c3715SXin Li       apply_rotation_in_the_plane_selector<Scalar,OtherScalar,SizeAtCompileTime,MinAlignment,false>::run(x,incrx,y,incry,size,c,s);
447*bf2c3715SXin Li     }
448*bf2c3715SXin Li   }
449*bf2c3715SXin Li };
450*bf2c3715SXin Li 
451*bf2c3715SXin Li template<typename VectorX, typename VectorY, typename OtherScalar>
452*bf2c3715SXin Li EIGEN_DEVICE_FUNC
453*bf2c3715SXin Li void /*EIGEN_DONT_INLINE*/ apply_rotation_in_the_plane(DenseBase<VectorX>& xpr_x, DenseBase<VectorY>& xpr_y, const JacobiRotation<OtherScalar>& j)
454*bf2c3715SXin Li {
455*bf2c3715SXin Li   typedef typename VectorX::Scalar Scalar;
456*bf2c3715SXin Li   const bool Vectorizable =    (int(VectorX::Flags) & int(VectorY::Flags) & PacketAccessBit)
457*bf2c3715SXin Li                             && (int(packet_traits<Scalar>::size) == int(packet_traits<OtherScalar>::size));
458*bf2c3715SXin Li 
459*bf2c3715SXin Li   eigen_assert(xpr_x.size() == xpr_y.size());
460*bf2c3715SXin Li   Index size = xpr_x.size();
461*bf2c3715SXin Li   Index incrx = xpr_x.derived().innerStride();
462*bf2c3715SXin Li   Index incry = xpr_y.derived().innerStride();
463*bf2c3715SXin Li 
464*bf2c3715SXin Li   Scalar* EIGEN_RESTRICT x = &xpr_x.derived().coeffRef(0);
465*bf2c3715SXin Li   Scalar* EIGEN_RESTRICT y = &xpr_y.derived().coeffRef(0);
466*bf2c3715SXin Li 
467*bf2c3715SXin Li   OtherScalar c = j.c();
468*bf2c3715SXin Li   OtherScalar s = j.s();
469*bf2c3715SXin Li   if (c==OtherScalar(1) && s==OtherScalar(0))
470*bf2c3715SXin Li     return;
471*bf2c3715SXin Li 
472*bf2c3715SXin Li   apply_rotation_in_the_plane_selector<
473*bf2c3715SXin Li     Scalar,OtherScalar,
474*bf2c3715SXin Li     VectorX::SizeAtCompileTime,
475*bf2c3715SXin Li     EIGEN_PLAIN_ENUM_MIN(evaluator<VectorX>::Alignment, evaluator<VectorY>::Alignment),
476*bf2c3715SXin Li     Vectorizable>::run(x,incrx,y,incry,size,c,s);
477*bf2c3715SXin Li }
478*bf2c3715SXin Li 
479*bf2c3715SXin Li } // end namespace internal
480*bf2c3715SXin Li 
481*bf2c3715SXin Li } // end namespace Eigen
482*bf2c3715SXin Li 
483*bf2c3715SXin Li #endif // EIGEN_JACOBI_H
484