Eigen  3.4.90 (git rev 67eeba6e720c5745abc77ae6c92ce0a44aa7b7ae)
Jacobi.h
1 // This file is part of Eigen, a lightweight C++ template library
2 // for linear algebra.
3 //
4 // Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@gmail.com>
5 // Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
6 //
7 // This Source Code Form is subject to the terms of the Mozilla
8 // Public License v. 2.0. If a copy of the MPL was not distributed
9 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 
11 #ifndef EIGEN_JACOBI_H
12 #define EIGEN_JACOBI_H
13 
14 #include "./InternalHeaderCheck.h"
15 
16 namespace Eigen {
17 
36 template<typename Scalar> class JacobiRotation
37 {
38  public:
39  typedef typename NumTraits<Scalar>::Real RealScalar;
40 
42  EIGEN_DEVICE_FUNC
44 
46  EIGEN_DEVICE_FUNC
47  JacobiRotation(const Scalar& c, const Scalar& s) : m_c(c), m_s(s) {}
48 
49  EIGEN_DEVICE_FUNC Scalar& c() { return m_c; }
50  EIGEN_DEVICE_FUNC Scalar c() const { return m_c; }
51  EIGEN_DEVICE_FUNC Scalar& s() { return m_s; }
52  EIGEN_DEVICE_FUNC Scalar s() const { return m_s; }
53 
55  EIGEN_DEVICE_FUNC
57  {
58  using numext::conj;
59  return JacobiRotation(m_c * other.m_c - conj(m_s) * other.m_s,
60  conj(m_c * conj(other.m_s) + conj(m_s) * conj(other.m_c)));
61  }
62 
64  EIGEN_DEVICE_FUNC
65  JacobiRotation transpose() const { using numext::conj; return JacobiRotation(m_c, -conj(m_s)); }
66 
68  EIGEN_DEVICE_FUNC
69  JacobiRotation adjoint() const { using numext::conj; return JacobiRotation(conj(m_c), -m_s); }
70 
71  template<typename Derived>
72  EIGEN_DEVICE_FUNC
73  bool makeJacobi(const MatrixBase<Derived>&, Index p, Index q);
74  EIGEN_DEVICE_FUNC
75  bool makeJacobi(const RealScalar& x, const Scalar& y, const RealScalar& z);
76 
77  EIGEN_DEVICE_FUNC
78  void makeGivens(const Scalar& p, const Scalar& q, Scalar* r=0);
79 
80  protected:
81  EIGEN_DEVICE_FUNC
82  void makeGivens(const Scalar& p, const Scalar& q, Scalar* r, internal::true_type);
83  EIGEN_DEVICE_FUNC
84  void makeGivens(const Scalar& p, const Scalar& q, Scalar* r, internal::false_type);
85 
86  Scalar m_c, m_s;
87 };
88 
94 template<typename Scalar>
95 EIGEN_DEVICE_FUNC
96 bool JacobiRotation<Scalar>::makeJacobi(const RealScalar& x, const Scalar& y, const RealScalar& z)
97 {
98  using std::sqrt;
99  using std::abs;
100 
101  RealScalar deno = RealScalar(2)*abs(y);
102  if(deno < (std::numeric_limits<RealScalar>::min)())
103  {
104  m_c = Scalar(1);
105  m_s = Scalar(0);
106  return false;
107  }
108  else
109  {
110  RealScalar tau = (x-z)/deno;
111  RealScalar w = sqrt(numext::abs2(tau) + RealScalar(1));
112  RealScalar t;
113  if(tau>RealScalar(0))
114  {
115  t = RealScalar(1) / (tau + w);
116  }
117  else
118  {
119  t = RealScalar(1) / (tau - w);
120  }
121  RealScalar sign_t = t > RealScalar(0) ? RealScalar(1) : RealScalar(-1);
122  RealScalar n = RealScalar(1) / sqrt(numext::abs2(t)+RealScalar(1));
123  m_s = - sign_t * (numext::conj(y) / abs(y)) * abs(t) * n;
124  m_c = n;
125  return true;
126  }
127 }
128 
138 template<typename Scalar>
139 template<typename Derived>
140 EIGEN_DEVICE_FUNC
142 {
143  return makeJacobi(numext::real(m.coeff(p,p)), m.coeff(p,q), numext::real(m.coeff(q,q)));
144 }
145 
162 template<typename Scalar>
163 EIGEN_DEVICE_FUNC
164 void JacobiRotation<Scalar>::makeGivens(const Scalar& p, const Scalar& q, Scalar* r)
165 {
166  makeGivens(p, q, r, std::conditional_t<NumTraits<Scalar>::IsComplex, internal::true_type, internal::false_type>());
167 }
168 
169 
170 // specialization for complexes
171 template<typename Scalar>
172 EIGEN_DEVICE_FUNC
173 void JacobiRotation<Scalar>::makeGivens(const Scalar& p, const Scalar& q, Scalar* r, internal::true_type)
174 {
175  using std::sqrt;
176  using std::abs;
177  using numext::conj;
178 
179  if(q==Scalar(0))
180  {
181  m_c = numext::real(p)<0 ? Scalar(-1) : Scalar(1);
182  m_s = 0;
183  if(r) *r = m_c * p;
184  }
185  else if(p==Scalar(0))
186  {
187  m_c = 0;
188  m_s = -q/abs(q);
189  if(r) *r = abs(q);
190  }
191  else
192  {
193  RealScalar p1 = numext::norm1(p);
194  RealScalar q1 = numext::norm1(q);
195  if(p1>=q1)
196  {
197  Scalar ps = p / p1;
198  RealScalar p2 = numext::abs2(ps);
199  Scalar qs = q / p1;
200  RealScalar q2 = numext::abs2(qs);
201 
202  RealScalar u = sqrt(RealScalar(1) + q2/p2);
203  if(numext::real(p)<RealScalar(0))
204  u = -u;
205 
206  m_c = Scalar(1)/u;
207  m_s = -qs*conj(ps)*(m_c/p2);
208  if(r) *r = p * u;
209  }
210  else
211  {
212  Scalar ps = p / q1;
213  RealScalar p2 = numext::abs2(ps);
214  Scalar qs = q / q1;
215  RealScalar q2 = numext::abs2(qs);
216 
217  RealScalar u = q1 * sqrt(p2 + q2);
218  if(numext::real(p)<RealScalar(0))
219  u = -u;
220 
221  p1 = abs(p);
222  ps = p/p1;
223  m_c = p1/u;
224  m_s = -conj(ps) * (q/u);
225  if(r) *r = ps * u;
226  }
227  }
228 }
229 
230 // specialization for reals
231 template<typename Scalar>
232 EIGEN_DEVICE_FUNC
233 void JacobiRotation<Scalar>::makeGivens(const Scalar& p, const Scalar& q, Scalar* r, internal::false_type)
234 {
235  using std::sqrt;
236  using std::abs;
237  if(numext::is_exactly_zero(q))
238  {
239  m_c = p<Scalar(0) ? Scalar(-1) : Scalar(1);
240  m_s = Scalar(0);
241  if(r) *r = abs(p);
242  }
243  else if(numext::is_exactly_zero(p))
244  {
245  m_c = Scalar(0);
246  m_s = q<Scalar(0) ? Scalar(1) : Scalar(-1);
247  if(r) *r = abs(q);
248  }
249  else if(abs(p) > abs(q))
250  {
251  Scalar t = q/p;
252  Scalar u = sqrt(Scalar(1) + numext::abs2(t));
253  if(p<Scalar(0))
254  u = -u;
255  m_c = Scalar(1)/u;
256  m_s = -t * m_c;
257  if(r) *r = p * u;
258  }
259  else
260  {
261  Scalar t = p/q;
262  Scalar u = sqrt(Scalar(1) + numext::abs2(t));
263  if(q<Scalar(0))
264  u = -u;
265  m_s = -Scalar(1)/u;
266  m_c = -t * m_s;
267  if(r) *r = q * u;
268  }
269 
270 }
271 
272 /****************************************************************************************
273 * Implementation of MatrixBase methods
274 ****************************************************************************************/
275 
276 namespace internal {
283 template<typename VectorX, typename VectorY, typename OtherScalar>
284 EIGEN_DEVICE_FUNC
285 void apply_rotation_in_the_plane(DenseBase<VectorX>& xpr_x, DenseBase<VectorY>& xpr_y, const JacobiRotation<OtherScalar>& j);
286 }
287 
294 template<typename Derived>
295 template<typename OtherScalar>
296 EIGEN_DEVICE_FUNC
298 {
299  RowXpr x(this->row(p));
300  RowXpr y(this->row(q));
301  internal::apply_rotation_in_the_plane(x, y, j);
302 }
303 
310 template<typename Derived>
311 template<typename OtherScalar>
312 EIGEN_DEVICE_FUNC
314 {
315  ColXpr x(this->col(p));
316  ColXpr y(this->col(q));
317  internal::apply_rotation_in_the_plane(x, y, j.transpose());
318 }
319 
320 namespace internal {
321 
322 template<typename Scalar, typename OtherScalar,
323  int SizeAtCompileTime, int MinAlignment, bool Vectorizable>
324 struct apply_rotation_in_the_plane_selector
325 {
326  static EIGEN_DEVICE_FUNC
327  inline void run(Scalar *x, Index incrx, Scalar *y, Index incry, Index size, OtherScalar c, OtherScalar s)
328  {
329  for(Index i=0; i<size; ++i)
330  {
331  Scalar xi = *x;
332  Scalar yi = *y;
333  *x = c * xi + numext::conj(s) * yi;
334  *y = -s * xi + numext::conj(c) * yi;
335  x += incrx;
336  y += incry;
337  }
338  }
339 };
340 
341 template<typename Scalar, typename OtherScalar,
342  int SizeAtCompileTime, int MinAlignment>
343 struct apply_rotation_in_the_plane_selector<Scalar,OtherScalar,SizeAtCompileTime,MinAlignment,true /* vectorizable */>
344 {
345  static inline void run(Scalar *x, Index incrx, Scalar *y, Index incry, Index size, OtherScalar c, OtherScalar s)
346  {
347  enum {
348  PacketSize = packet_traits<Scalar>::size,
349  OtherPacketSize = packet_traits<OtherScalar>::size
350  };
351  typedef typename packet_traits<Scalar>::type Packet;
352  typedef typename packet_traits<OtherScalar>::type OtherPacket;
353 
354  /*** dynamic-size vectorized paths ***/
355  if(SizeAtCompileTime == Dynamic && ((incrx==1 && incry==1) || PacketSize == 1))
356  {
357  // both vectors are sequentially stored in memory => vectorization
358  enum { Peeling = 2 };
359 
360  Index alignedStart = internal::first_default_aligned(y, size);
361  Index alignedEnd = alignedStart + ((size-alignedStart)/PacketSize)*PacketSize;
362 
363  const OtherPacket pc = pset1<OtherPacket>(c);
364  const OtherPacket ps = pset1<OtherPacket>(s);
365  conj_helper<OtherPacket,Packet,NumTraits<OtherScalar>::IsComplex,false> pcj;
366  conj_helper<OtherPacket,Packet,false,false> pm;
367 
368  for(Index i=0; i<alignedStart; ++i)
369  {
370  Scalar xi = x[i];
371  Scalar yi = y[i];
372  x[i] = c * xi + numext::conj(s) * yi;
373  y[i] = -s * xi + numext::conj(c) * yi;
374  }
375 
376  Scalar* EIGEN_RESTRICT px = x + alignedStart;
377  Scalar* EIGEN_RESTRICT py = y + alignedStart;
378 
379  if(internal::first_default_aligned(x, size)==alignedStart)
380  {
381  for(Index i=alignedStart; i<alignedEnd; i+=PacketSize)
382  {
383  Packet xi = pload<Packet>(px);
384  Packet yi = pload<Packet>(py);
385  pstore(px, padd(pm.pmul(pc,xi),pcj.pmul(ps,yi)));
386  pstore(py, psub(pcj.pmul(pc,yi),pm.pmul(ps,xi)));
387  px += PacketSize;
388  py += PacketSize;
389  }
390  }
391  else
392  {
393  Index peelingEnd = alignedStart + ((size-alignedStart)/(Peeling*PacketSize))*(Peeling*PacketSize);
394  for(Index i=alignedStart; i<peelingEnd; i+=Peeling*PacketSize)
395  {
396  Packet xi = ploadu<Packet>(px);
397  Packet xi1 = ploadu<Packet>(px+PacketSize);
398  Packet yi = pload <Packet>(py);
399  Packet yi1 = pload <Packet>(py+PacketSize);
400  pstoreu(px, padd(pm.pmul(pc,xi),pcj.pmul(ps,yi)));
401  pstoreu(px+PacketSize, padd(pm.pmul(pc,xi1),pcj.pmul(ps,yi1)));
402  pstore (py, psub(pcj.pmul(pc,yi),pm.pmul(ps,xi)));
403  pstore (py+PacketSize, psub(pcj.pmul(pc,yi1),pm.pmul(ps,xi1)));
404  px += Peeling*PacketSize;
405  py += Peeling*PacketSize;
406  }
407  if(alignedEnd!=peelingEnd)
408  {
409  Packet xi = ploadu<Packet>(x+peelingEnd);
410  Packet yi = pload <Packet>(y+peelingEnd);
411  pstoreu(x+peelingEnd, padd(pm.pmul(pc,xi),pcj.pmul(ps,yi)));
412  pstore (y+peelingEnd, psub(pcj.pmul(pc,yi),pm.pmul(ps,xi)));
413  }
414  }
415 
416  for(Index i=alignedEnd; i<size; ++i)
417  {
418  Scalar xi = x[i];
419  Scalar yi = y[i];
420  x[i] = c * xi + numext::conj(s) * yi;
421  y[i] = -s * xi + numext::conj(c) * yi;
422  }
423  }
424 
425  /*** fixed-size vectorized path ***/
426  else if(SizeAtCompileTime != Dynamic && MinAlignment>0) // FIXME should be compared to the required alignment
427  {
428  const OtherPacket pc = pset1<OtherPacket>(c);
429  const OtherPacket ps = pset1<OtherPacket>(s);
430  conj_helper<OtherPacket,Packet,NumTraits<OtherPacket>::IsComplex,false> pcj;
431  conj_helper<OtherPacket,Packet,false,false> pm;
432  Scalar* EIGEN_RESTRICT px = x;
433  Scalar* EIGEN_RESTRICT py = y;
434  for(Index i=0; i<size; i+=PacketSize)
435  {
436  Packet xi = pload<Packet>(px);
437  Packet yi = pload<Packet>(py);
438  pstore(px, padd(pm.pmul(pc,xi),pcj.pmul(ps,yi)));
439  pstore(py, psub(pcj.pmul(pc,yi),pm.pmul(ps,xi)));
440  px += PacketSize;
441  py += PacketSize;
442  }
443  }
444 
445  /*** non-vectorized path ***/
446  else
447  {
448  apply_rotation_in_the_plane_selector<Scalar,OtherScalar,SizeAtCompileTime,MinAlignment,false>::run(x,incrx,y,incry,size,c,s);
449  }
450  }
451 };
452 
453 template<typename VectorX, typename VectorY, typename OtherScalar>
454 EIGEN_DEVICE_FUNC
455 void /*EIGEN_DONT_INLINE*/ apply_rotation_in_the_plane(DenseBase<VectorX>& xpr_x, DenseBase<VectorY>& xpr_y, const JacobiRotation<OtherScalar>& j)
456 {
457  typedef typename VectorX::Scalar Scalar;
458  const bool Vectorizable = (int(VectorX::Flags) & int(VectorY::Flags) & PacketAccessBit)
459  && (int(packet_traits<Scalar>::size) == int(packet_traits<OtherScalar>::size));
460 
461  eigen_assert(xpr_x.size() == xpr_y.size());
462  Index size = xpr_x.size();
463  Index incrx = xpr_x.derived().innerStride();
464  Index incry = xpr_y.derived().innerStride();
465 
466  Scalar* EIGEN_RESTRICT x = &xpr_x.derived().coeffRef(0);
467  Scalar* EIGEN_RESTRICT y = &xpr_y.derived().coeffRef(0);
468 
469  OtherScalar c = j.c();
470  OtherScalar s = j.s();
471  if (numext::is_exactly_one(c) && numext::is_exactly_zero(s))
472  return;
473 
474  apply_rotation_in_the_plane_selector<
475  Scalar,OtherScalar,
477  plain_enum_min(evaluator<VectorX>::Alignment, evaluator<VectorY>::Alignment),
478  Vectorizable>::run(x,incrx,y,incry,size,c,s);
479 }
480 
481 } // end namespace internal
482 
483 } // end namespace Eigen
484 
485 #endif // EIGEN_JACOBI_H
@ SizeAtCompileTime
Definition: DenseBase.h:108
@ Flags
Definition: DenseBase.h:159
CoeffReturnType coeff(Index row, Index col) const
Definition: DenseCoeffsBase.h:99
Rotation given by a cosine-sine pair.
Definition: Jacobi.h:37
JacobiRotation()
Definition: Jacobi.h:43
JacobiRotation(const Scalar &c, const Scalar &s)
Definition: Jacobi.h:47
bool makeJacobi(const MatrixBase< Derived > &, Index p, Index q)
Definition: Jacobi.h:141
JacobiRotation adjoint() const
Definition: Jacobi.h:69
JacobiRotation transpose() const
Definition: Jacobi.h:65
JacobiRotation operator*(const JacobiRotation &other)
Definition: Jacobi.h:56
void makeGivens(const Scalar &p, const Scalar &q, Scalar *r=0)
Definition: Jacobi.h:164
Base class for all dense matrices, vectors, and expressions.
Definition: MatrixBase.h:52
void applyOnTheLeft(const EigenBase< OtherDerived > &other)
Definition: MatrixBase.h:545
void applyOnTheRight(const EigenBase< OtherDerived > &other)
Definition: MatrixBase.h:533
const unsigned int PacketAccessBit
Definition: Constants.h:96
Namespace containing all symbols from the Eigen library.
Definition: Core:139
EIGEN_DEFAULT_DENSE_INDEX_TYPE Index
The Index type as used for the API.
Definition: Meta.h:59
const Eigen::CwiseUnaryOp< Eigen::internal::scalar_conjugate_op< typename Derived::Scalar >, const Derived > conj(const Eigen::ArrayBase< Derived > &x)
const int Dynamic
Definition: Constants.h:24
const Eigen::CwiseUnaryOp< Eigen::internal::scalar_abs_op< typename Derived::Scalar >, const Derived > abs(const Eigen::ArrayBase< Derived > &x)
const Eigen::CwiseUnaryOp< Eigen::internal::scalar_sqrt_op< typename Derived::Scalar >, const Derived > sqrt(const Eigen::ArrayBase< Derived > &x)
Eigen::Index Index
The interface type of indices.
Definition: EigenBase.h:41
Holds information about the various numeric (i.e. scalar) types allowed by Eigen.
Definition: NumTraits.h:231