16#include "./InternalHeaderCheck.h"
38template <
typename Scalar>
41 using RealScalar =
typename NumTraits<Scalar>::Real;
47 EIGEN_DEVICE_FUNC
JacobiRotation(
const Scalar& c,
const Scalar& s) : m_c(c), m_s(s) {}
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; }
58 conj(m_c * conj(other.m_s) + conj(m_s) * conj(other.m_c)));
73 template <
typename Derived>
75 EIGEN_DEVICE_FUNC
bool makeJacobi(
const RealScalar& x,
const Scalar& y,
const RealScalar& z);
77 EIGEN_DEVICE_FUNC
void makeGivens(
const Scalar& p,
const Scalar& q, Scalar* r = 0);
80 EIGEN_DEVICE_FUNC
void makeGivens(
const Scalar& p,
const Scalar& q, Scalar* r, std::true_type);
81 EIGEN_DEVICE_FUNC
void makeGivens(
const Scalar& p,
const Scalar& q, Scalar* r, std::false_type);
82 EIGEN_DEVICE_FUNC EIGEN_DONT_INLINE
void makeGivensScaled(
const Scalar& p,
const Scalar& q, Scalar* r);
94template <
typename Scalar>
99 const RealScalar abs_y = abs(y);
100 const RealScalar deno = RealScalar(2) * abs_y;
101 if (deno < (std::numeric_limits<RealScalar>::min)()) {
106 const RealScalar delta = x - z;
107 const RealScalar abs_delta = abs(delta);
113 const bool large_delta = abs_delta > deno;
114 const RealScalar ratio = (large_delta ? deno : abs_delta) / (large_delta ? abs_delta : deno);
115 const RealScalar numerator = large_delta ? ratio : RealScalar(1);
116 const RealScalar denominator = sqrt(RealScalar(1) + numext::abs2(ratio)) + (large_delta ? RealScalar(1) : ratio);
117 const RealScalar n = RealScalar(1) / sqrt(numext::abs2(numerator) + numext::abs2(denominator));
118 const RealScalar sine = numerator * n;
119 const RealScalar sign_t = delta > RealScalar(0) ? RealScalar(1) : RealScalar(-1);
120 EIGEN_IF_CONSTEXPR (NumTraits<Scalar>::IsComplex) {
121 m_s = -sign_t * (numext::conj(y) / abs_y) * sine;
124 const RealScalar signed_sine = -sign_t * sine;
125 m_s = numext::real(y) < RealScalar(0) ? -signed_sine : signed_sine;
127 m_c = denominator * n;
142template <
typename Scalar>
143template <
typename Derived>
145 return makeJacobi(numext::real(m.coeff(p, p)), m.coeff(p, q), numext::real(m.coeff(q, q)));
164template <
typename Scalar>
166 makeGivens(p, q, r, internal::bool_constant<NumTraits<Scalar>::IsComplex>());
170template <
typename Scalar>
176 if (q == Scalar(0)) {
177 m_c = numext::real(p) < 0 ? Scalar(-1) : Scalar(1);
180 }
else if (p == Scalar(0)) {
185 RealScalar p1 = numext::norm1(p);
186 RealScalar q1 = numext::norm1(q);
189 RealScalar p2 = numext::abs2(ps);
191 RealScalar q2 = numext::abs2(qs);
193 RealScalar u = sqrt(RealScalar(1) + q2 / p2);
194 if (numext::real(p) < RealScalar(0)) u = -u;
197 m_s = -qs * conj(ps) * (m_c / p2);
201 RealScalar p2 = numext::abs2(ps);
203 RealScalar q2 = numext::abs2(qs);
205 RealScalar u = q1 * sqrt(p2 + q2);
206 if (numext::real(p) < RealScalar(0)) u = -u;
211 m_s = -conj(ps) * (q / u);
218template <
typename Scalar>
223 if (numext::is_exactly_zero_no_flush(q)) {
226 if (abs(p) < (std::numeric_limits<Scalar>::min)() && !numext::is_exactly_zero_no_flush(p)) {
227 makeGivensScaled(p, q, r);
230 m_c = p < Scalar(0) ? Scalar(-1) : Scalar(1);
235 if (numext::is_exactly_zero_no_flush(p)) {
236 if (abs(q) < (std::numeric_limits<Scalar>::min)()) {
237 makeGivensScaled(p, q, r);
241 m_s = q < Scalar(0) ? Scalar(1) : Scalar(-1);
253 const Scalar safmin = (std::numeric_limits<Scalar>::min)();
254 const Scalar safmax = Scalar(1) / safmin;
255 const Scalar rtmin = sqrt(safmin);
256 const Scalar rtmax = sqrt(safmax / Scalar(2));
257 const Scalar abs_p = abs(p);
258 const Scalar abs_q = abs(q);
259 const Scalar mx = numext::maxi(abs_p, abs_q);
260 const Scalar mn = numext::mini(abs_p, abs_q);
262 if (EIGEN_PREDICT_TRUE(mx < rtmax && mn > rtmin)) {
266 Scalar u = sqrt(Scalar(1) + numext::abs2(t));
267 if (p < Scalar(0)) u = -u;
273 Scalar u = sqrt(Scalar(1) + numext::abs2(t));
274 if (q < Scalar(0)) u = -u;
275 m_s = -Scalar(1) / u;
280 makeGivensScaled(p, q, r);
284template <
typename Scalar>
285EIGEN_DEVICE_FUNC EIGEN_DONT_INLINE
void JacobiRotation<Scalar>::makeGivensScaled(
const Scalar& p,
const Scalar& q,
287 using Scaling = internal::safe_scaling<Scalar>;
290 const Scalar maximum = Scaling::recover_flushed_max_coeff(scaled, scaled.cwiseAbs().maxCoeff());
291 const auto factors = Scaling::scale_to(scaled, scaled, maximum);
292 const Scalar ps = scaled.x(), qs = scaled.y();
294 if (numext::abs(ps) > numext::abs(qs)) {
295 const Scalar t = qs / ps;
296 Scalar u = numext::sqrt<Scalar>(Scalar(1) + numext::abs2(t));
297 if (ps < Scalar(0)) u = -u;
300 if (r) norm = ps * u;
302 const Scalar t = ps / qs;
303 Scalar u = numext::sqrt<Scalar>(Scalar(1) + numext::abs2(t));
304 if (qs < Scalar(0)) u = -u;
305 m_s = -Scalar(1) / u;
307 if (r) norm = qs * u;
313 Scaling::unscale_in_place(result, maximum, factors);
330template <
typename VectorX,
typename VectorY,
typename OtherScalar>
331EIGEN_DEVICE_FUNC
void apply_rotation_in_the_plane(DenseBase<VectorX>& xpr_x, DenseBase<VectorY>& xpr_y,
332 const JacobiRotation<OtherScalar>& j);
341template <
typename Derived>
342template <
typename OtherScalar>
345 RowXpr x(this->
row(p));
346 RowXpr y(this->
row(q));
347 internal::apply_rotation_in_the_plane(x, y, j);
356template <
typename Derived>
357template <
typename OtherScalar>
360 ColXpr x(this->
col(p));
361 ColXpr y(this->
col(q));
362 internal::apply_rotation_in_the_plane(x, y, j.
transpose());
367template <
typename Scalar,
typename OtherScalar,
int SizeAtCompileTime,
int MinAlignment,
bool Vectorizable>
368struct apply_rotation_in_the_plane_selector {
369 static EIGEN_DEVICE_FUNC
inline void run(Scalar* x, Index incrx, Scalar* y, Index incry, Index size, OtherScalar c,
371 for (Index i = 0; i < size; ++i) {
374 *x = c * xi + numext::conj(s) * yi;
375 *y = -s * xi + numext::conj(c) * yi;
382template <
typename Scalar,
typename OtherScalar,
int SizeAtCompileTime,
int MinAlignment>
383struct apply_rotation_in_the_plane_selector<Scalar, OtherScalar, SizeAtCompileTime, MinAlignment,
385 EIGEN_DEVICE_FUNC
static void run(Scalar* x, Index incrx, Scalar* y, Index incry, Index size, OtherScalar c,
387 using Packet =
typename packet_traits<Scalar>::type;
388 using OtherPacket =
typename packet_traits<OtherScalar>::type;
390 constexpr int RequiredAlignment =
391 (std::max<int>)(unpacket_traits<Packet>::alignment, unpacket_traits<OtherPacket>::alignment);
392 constexpr Index PacketSize = packet_traits<Scalar>::size;
394 EIGEN_IF_CONSTEXPR (SizeAtCompileTime == Dynamic) {
396 if (size >= 2 * PacketSize && ((incrx == 1 && incry == 1) || PacketSize == 1)) {
398 constexpr Index Peeling = 2;
400 Index alignedStart = internal::first_default_aligned(y, size);
401 Index alignedEnd = alignedStart + ((size - alignedStart) / PacketSize) * PacketSize;
403 const OtherPacket pc = pset1<OtherPacket>(c);
404 const OtherPacket ps = pset1<OtherPacket>(s);
405 conj_helper<OtherPacket, Packet, NumTraits<OtherScalar>::IsComplex,
false> pcj;
406 conj_helper<OtherPacket, Packet, false, false> pm;
408 for (Index i = 0; i < alignedStart; ++i) {
411 x[i] = c * xi + numext::conj(s) * yi;
412 y[i] = -s * xi + numext::conj(c) * yi;
415 Scalar* EIGEN_RESTRICT px = x + alignedStart;
416 Scalar* EIGEN_RESTRICT py = y + alignedStart;
418 if (internal::first_default_aligned(x, size) == alignedStart) {
419 for (Index i = alignedStart; i < alignedEnd; i += PacketSize) {
420 Packet xi = pload<Packet>(px);
421 Packet yi = pload<Packet>(py);
422 pstore(px, pm.pmadd(pc, xi, pcj.pmul(ps, yi)));
423 pstore(py, pcj.pmsub(pc, yi, pm.pmul(ps, xi)));
428 Index peelingEnd = alignedStart + ((size - alignedStart) / (Peeling * PacketSize)) * (Peeling * PacketSize);
429 for (Index i = alignedStart; i < peelingEnd; i += Peeling * PacketSize) {
430 Packet xi = ploadu<Packet>(px);
431 Packet xi1 = ploadu<Packet>(px + PacketSize);
432 Packet yi = pload<Packet>(py);
433 Packet yi1 = pload<Packet>(py + PacketSize);
434 pstoreu(px, pm.pmadd(pc, xi, pcj.pmul(ps, yi)));
435 pstoreu(px + PacketSize, pm.pmadd(pc, xi1, pcj.pmul(ps, yi1)));
436 pstore(py, pcj.pmsub(pc, yi, pm.pmul(ps, xi)));
437 pstore(py + PacketSize, pcj.pmsub(pc, yi1, pm.pmul(ps, xi1)));
438 px += Peeling * PacketSize;
439 py += Peeling * PacketSize;
441 if (alignedEnd != peelingEnd) {
442 Packet xi = ploadu<Packet>(x + peelingEnd);
443 Packet yi = pload<Packet>(y + peelingEnd);
444 pstoreu(x + peelingEnd, pm.pmadd(pc, xi, pcj.pmul(ps, yi)));
445 pstore(y + peelingEnd, pcj.pmsub(pc, yi, pm.pmul(ps, xi)));
449 for (Index i = alignedEnd; i < size; ++i) {
452 x[i] = c * xi + numext::conj(s) * yi;
453 y[i] = -s * xi + numext::conj(c) * yi;
459 EIGEN_IF_CONSTEXPR (SizeAtCompileTime != Dynamic && MinAlignment >= RequiredAlignment) {
461 const OtherPacket pc = pset1<OtherPacket>(c);
462 const OtherPacket ps = pset1<OtherPacket>(s);
463 conj_helper<OtherPacket, Packet, NumTraits<OtherScalar>::IsComplex,
false> pcj;
464 conj_helper<OtherPacket, Packet, false, false> pm;
465 Scalar* EIGEN_RESTRICT px = x;
466 Scalar* EIGEN_RESTRICT py = y;
467 for (Index i = 0; i < size; i += PacketSize) {
468 Packet xi = pload<Packet>(px);
469 Packet yi = pload<Packet>(py);
470 pstore(px, pm.pmadd(pc, xi, pcj.pmul(ps, yi)));
471 pstore(py, pcj.pmsub(pc, yi, pm.pmul(ps, xi)));
479 apply_rotation_in_the_plane_selector<Scalar, OtherScalar, SizeAtCompileTime, MinAlignment, false>::run(
480 x, incrx, y, incry, size, c, s);
484template <
typename VectorX,
typename VectorY,
typename OtherScalar>
485EIGEN_DEVICE_FUNC
void inline apply_rotation_in_the_plane(DenseBase<VectorX>& xpr_x, DenseBase<VectorY>& xpr_y,
486 const JacobiRotation<OtherScalar>& j) {
487 using Scalar =
typename VectorX::Scalar;
488 constexpr bool Vectorizable = (int(evaluator<VectorX>::Flags) & int(evaluator<VectorY>::Flags) &
PacketAccessBit) &&
489 (
int(packet_traits<Scalar>::size) ==
int(packet_traits<OtherScalar>::size));
491 eigen_assert(xpr_x.size() == xpr_y.size());
492 Index size = xpr_x.size();
493 Index incrx = xpr_x.derived().innerStride();
494 Index incry = xpr_y.derived().innerStride();
496 Scalar* EIGEN_RESTRICT x = &xpr_x.derived().coeffRef(0);
497 Scalar* EIGEN_RESTRICT y = &xpr_y.derived().coeffRef(0);
499 OtherScalar c = j.c();
500 OtherScalar s = j.s();
501 if (numext::is_exactly_one(c) && numext::is_exactly_zero(s))
return;
503 constexpr int Alignment = (std::min)(
int(evaluator<VectorX>::Alignment),
int(evaluator<VectorY>::Alignment));
504 apply_rotation_in_the_plane_selector<Scalar, OtherScalar, VectorX::SizeAtCompileTime, Alignment, Vectorizable>::run(
505 x, incrx, y, incry, size, c, s);
508template <
typename MatrixType,
typename RealScalar,
typename Index>
509EIGEN_DONT_INLINE
void real_2x2_jacobi_svd(
const MatrixType& matrix, Index p, Index q,
510 JacobiRotation<RealScalar>* j_left, JacobiRotation<RealScalar>* j_right) {
512 const RealScalar m00 = numext::real(matrix.coeff(p, p));
513 const RealScalar m01 = numext::real(matrix.coeff(p, q));
514 const RealScalar m10 = numext::real(matrix.coeff(q, p));
515 const RealScalar m11 = numext::real(matrix.coeff(q, q));
518 const RealScalar t = m00 + m11;
519 const RealScalar d = m10 - m01;
522 if (numext::abs(d) < (std::numeric_limits<RealScalar>::min)()) {
528 RealScalar u = t / d;
529 s1 = RealScalar(1) / numext::sqrt<RealScalar>(RealScalar(1) + numext::abs2(u));
535 const RealScalar a00 = c1 * m00 + s1 * m10;
536 const RealScalar a01 = c1 * m01 + s1 * m11;
537 const RealScalar a11 = -s1 * m01 + c1 * m11;
540 j_right->makeJacobi(a00, a01, a11);
543 const RealScalar jr_c = j_right->c();
544 const RealScalar jr_s = j_right->s();
545 j_left->c() = c1 * jr_c + s1 * jr_s;
546 j_left->s() = s1 * jr_c - c1 * jr_s;
constexpr ColXpr col(Index i)
Definition DenseBase.h:1081
constexpr RowXpr row(Index i)
Definition DenseBase.h:1094
typename internal::traits< Derived >::Scalar Scalar
Definition DenseBase.h:63
Rotation given by a cosine-sine pair.
Definition Jacobi.h:39
JacobiRotation()
Definition Jacobi.h:44
JacobiRotation(const Scalar &c, const Scalar &s)
Definition Jacobi.h:47
bool makeJacobi(const MatrixBase< Derived > &, Index p, Index q)
Definition Jacobi.h:144
JacobiRotation adjoint() const
Definition Jacobi.h:68
JacobiRotation transpose() const
Definition Jacobi.h:62
JacobiRotation operator*(const JacobiRotation &other)
Definition Jacobi.h:55
void makeGivens(const Scalar &p, const Scalar &q, Scalar *r=0)
Definition Jacobi.h:165
Base class for all dense matrices, vectors, and expressions.
Definition MatrixBase.h:53
void applyOnTheLeft(const EigenBase< OtherDerived > &other)
Definition MatrixBase.h:553
void applyOnTheRight(const EigenBase< OtherDerived > &other)
Definition MatrixBase.h:542
The matrix class, also used for vectors and row-vectors.
Definition Matrix.h:188
constexpr unsigned int PacketAccessBit
Definition Constants.h:98