Jacobi.h
Go to the documentation of this file.
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:
40 
44 
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 
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 
66 
69  JacobiRotation adjoint() const { using numext::conj; return JacobiRotation(conj(m_c), -m_s); }
70 
71  template<typename Derived>
73  bool makeJacobi(const MatrixBase<Derived>&, Index p, Index q);
75  bool makeJacobi(const RealScalar& x, const Scalar& y, const RealScalar& z);
76 
78  void makeGivens(const Scalar& p, const Scalar& q, Scalar* r=0);
79 
80  protected:
82  void makeGivens(const Scalar& p, const Scalar& q, Scalar* r, internal::true_type);
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>
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);
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);
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>
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>
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>
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>
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;
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 
276 namespace internal {
283 template<typename VectorX, typename VectorY, typename OtherScalar>
286 }
287 
294 template<typename Derived>
295 template<typename OtherScalar>
298 {
299  RowXpr x(this->row(p));
300  RowXpr y(this->row(q));
302 }
303 
310 template<typename Derived>
311 template<typename OtherScalar>
314 {
315  ColXpr x(this->col(p));
316  ColXpr y(this->col(q));
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  typedef typename packet_traits<Scalar>::type Packet;
348  typedef typename packet_traits<OtherScalar>::type OtherPacket;
349 
350  constexpr int RequiredAlignment =
351  (std::max)(unpacket_traits<Packet>::alignment, unpacket_traits<OtherPacket>::alignment);
352  constexpr Index PacketSize = packet_traits<Scalar>::size;
353 
354 
355  if(size >= 2 * PacketSize && SizeAtCompileTime == Dynamic && ((incrx == 1 && incry == 1) || PacketSize == 1))
356  {
357  // both vectors are sequentially stored in memory => vectorization
358  constexpr Index 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 
426  else if(SizeAtCompileTime != Dynamic && MinAlignment >= RequiredAlignment)
427  {
428  const OtherPacket pc = pset1<OtherPacket>(c);
429  const OtherPacket ps = pset1<OtherPacket>(s);
430  conj_helper<OtherPacket,Packet,NumTraits<OtherScalar>::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 
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>
456 {
457  typedef typename VectorX::Scalar Scalar;
458  constexpr bool Vectorizable = (int(evaluator<VectorX>::Flags) & int(evaluator<VectorY>::Flags) & PacketAccessBit) &&
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();
472  return;
473 
474  constexpr int Alignment = (std::min)(int(evaluator<VectorX>::Alignment), int(evaluator<VectorY>::Alignment));
475  apply_rotation_in_the_plane_selector<Scalar, OtherScalar, VectorX::SizeAtCompileTime, Alignment, Vectorizable>::run(
476  x, incrx, y, incry, size, c, s);
477 }
478 
479 } // end namespace internal
480 
481 } // end namespace Eigen
482 
483 #endif // EIGEN_JACOBI_H
Matrix3f m
const AbsReturnType abs() const
const SqrtReturnType sqrt() const
int n
RowXpr row(Index i)
This is the const version of row(). *‍/.
ColXpr col(Index i)
This is the const version of col().
RealReturnType real() const
Array33i c
G makeGivens(v.x(), v.y())
J makeJacobi(m, 0, 1)
#define EIGEN_RESTRICT
Definition: Macros.h:1055
#define EIGEN_DEVICE_FUNC
Definition: Macros.h:883
#define eigen_assert(x)
Definition: Macros.h:902
Vector3f p1
RowVector3d w
float * p
Base class for all dense matrices, vectors, and arrays.
Definition: DenseBase.h:42
internal::traits< Derived >::Scalar Scalar
Definition: DenseBase.h:61
EIGEN_CONSTEXPR Index size() const EIGEN_NOEXCEPT
Definition: EigenBase.h:69
Rotation given by a cosine-sine pair.
Definition: Jacobi.h:37
Scalar c() const
Definition: Jacobi.h:50
Scalar & s()
Definition: Jacobi.h:51
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
NumTraits< Scalar >::Real RealScalar
Definition: Jacobi.h:39
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
Scalar s() const
Definition: Jacobi.h:52
Scalar & c()
Definition: Jacobi.h:49
Base class for all dense matrices, vectors, and expressions.
Definition: MatrixBase.h:52
void applyOnTheLeft(const EigenBase< OtherDerived > &other)
Definition: MatrixBase.h:544
void applyOnTheRight(const EigenBase< OtherDerived > &other)
Definition: MatrixBase.h:532
constexpr const Scalar & coeff(Index rowId, Index colId) const
const unsigned int PacketAccessBit
Definition: Constants.h:96
bfloat16() max(const bfloat16 &a, const bfloat16 &b)
Definition: BFloat16.h:690
bfloat16() min(const bfloat16 &a, const bfloat16 &b)
Definition: BFloat16.h:684
Packet padd(const Packet &a, const Packet &b)
void pstore(Scalar *to, const Packet &from)
const Scalar & y
void apply_rotation_in_the_plane(DenseBase< VectorX > &xpr_x, DenseBase< VectorY > &xpr_y, const JacobiRotation< OtherScalar > &j)
Definition: Jacobi.h:455
void pstoreu(Scalar *to, const Packet &from)
Packet psub(const Packet &a, const Packet &b)
static Index first_default_aligned(const DenseBase< Derived > &m)
bool is_exactly_one(const X &x)
Definition: Meta.h:482
bool abs2(bool x)
bool is_exactly_zero(const X &x)
Definition: Meta.h:475
: InteropHeaders
Definition: Core:139
EIGEN_DEFAULT_DENSE_INDEX_TYPE Index
The Index type as used for the API.
Definition: Meta.h:82
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
std::ptrdiff_t j