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