Warning, file /include/eigen3/Eigen/src/Jacobi/Jacobi.h was not indexed
or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #ifndef EIGEN_JACOBI_H
0012 #define EIGEN_JACOBI_H
0013
0014 namespace Eigen {
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034 template<typename Scalar> class JacobiRotation
0035 {
0036 public:
0037 typedef typename NumTraits<Scalar>::Real RealScalar;
0038
0039
0040 EIGEN_DEVICE_FUNC
0041 JacobiRotation() {}
0042
0043
0044 EIGEN_DEVICE_FUNC
0045 JacobiRotation(const Scalar& c, const Scalar& s) : m_c(c), m_s(s) {}
0046
0047 EIGEN_DEVICE_FUNC Scalar& c() { return m_c; }
0048 EIGEN_DEVICE_FUNC Scalar c() const { return m_c; }
0049 EIGEN_DEVICE_FUNC Scalar& s() { return m_s; }
0050 EIGEN_DEVICE_FUNC Scalar s() const { return m_s; }
0051
0052
0053 EIGEN_DEVICE_FUNC
0054 JacobiRotation operator*(const JacobiRotation& other)
0055 {
0056 using numext::conj;
0057 return JacobiRotation(m_c * other.m_c - conj(m_s) * other.m_s,
0058 conj(m_c * conj(other.m_s) + conj(m_s) * conj(other.m_c)));
0059 }
0060
0061
0062 EIGEN_DEVICE_FUNC
0063 JacobiRotation transpose() const { using numext::conj; return JacobiRotation(m_c, -conj(m_s)); }
0064
0065
0066 EIGEN_DEVICE_FUNC
0067 JacobiRotation adjoint() const { using numext::conj; return JacobiRotation(conj(m_c), -m_s); }
0068
0069 template<typename Derived>
0070 EIGEN_DEVICE_FUNC
0071 bool makeJacobi(const MatrixBase<Derived>&, Index p, Index q);
0072 EIGEN_DEVICE_FUNC
0073 bool makeJacobi(const RealScalar& x, const Scalar& y, const RealScalar& z);
0074
0075 EIGEN_DEVICE_FUNC
0076 void makeGivens(const Scalar& p, const Scalar& q, Scalar* r=0);
0077
0078 protected:
0079 EIGEN_DEVICE_FUNC
0080 void makeGivens(const Scalar& p, const Scalar& q, Scalar* r, internal::true_type);
0081 EIGEN_DEVICE_FUNC
0082 void makeGivens(const Scalar& p, const Scalar& q, Scalar* r, internal::false_type);
0083
0084 Scalar m_c, m_s;
0085 };
0086
0087
0088
0089
0090
0091
0092 template<typename Scalar>
0093 EIGEN_DEVICE_FUNC
0094 bool JacobiRotation<Scalar>::makeJacobi(const RealScalar& x, const Scalar& y, const RealScalar& z)
0095 {
0096 using std::sqrt;
0097 using std::abs;
0098
0099 RealScalar deno = RealScalar(2)*abs(y);
0100 if(deno < (std::numeric_limits<RealScalar>::min)())
0101 {
0102 m_c = Scalar(1);
0103 m_s = Scalar(0);
0104 return false;
0105 }
0106 else
0107 {
0108 RealScalar tau = (x-z)/deno;
0109 RealScalar w = sqrt(numext::abs2(tau) + RealScalar(1));
0110 RealScalar t;
0111 if(tau>RealScalar(0))
0112 {
0113 t = RealScalar(1) / (tau + w);
0114 }
0115 else
0116 {
0117 t = RealScalar(1) / (tau - w);
0118 }
0119 RealScalar sign_t = t > RealScalar(0) ? RealScalar(1) : RealScalar(-1);
0120 RealScalar n = RealScalar(1) / sqrt(numext::abs2(t)+RealScalar(1));
0121 m_s = - sign_t * (numext::conj(y) / abs(y)) * abs(t) * n;
0122 m_c = n;
0123 return true;
0124 }
0125 }
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136 template<typename Scalar>
0137 template<typename Derived>
0138 EIGEN_DEVICE_FUNC
0139 inline bool JacobiRotation<Scalar>::makeJacobi(const MatrixBase<Derived>& m, Index p, Index q)
0140 {
0141 return makeJacobi(numext::real(m.coeff(p,p)), m.coeff(p,q), numext::real(m.coeff(q,q)));
0142 }
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160 template<typename Scalar>
0161 EIGEN_DEVICE_FUNC
0162 void JacobiRotation<Scalar>::makeGivens(const Scalar& p, const Scalar& q, Scalar* r)
0163 {
0164 makeGivens(p, q, r, typename internal::conditional<NumTraits<Scalar>::IsComplex, internal::true_type, internal::false_type>::type());
0165 }
0166
0167
0168
0169 template<typename Scalar>
0170 EIGEN_DEVICE_FUNC
0171 void JacobiRotation<Scalar>::makeGivens(const Scalar& p, const Scalar& q, Scalar* r, internal::true_type)
0172 {
0173 using std::sqrt;
0174 using std::abs;
0175 using numext::conj;
0176
0177 if(q==Scalar(0))
0178 {
0179 m_c = numext::real(p)<0 ? Scalar(-1) : Scalar(1);
0180 m_s = 0;
0181 if(r) *r = m_c * p;
0182 }
0183 else if(p==Scalar(0))
0184 {
0185 m_c = 0;
0186 m_s = -q/abs(q);
0187 if(r) *r = abs(q);
0188 }
0189 else
0190 {
0191 RealScalar p1 = numext::norm1(p);
0192 RealScalar q1 = numext::norm1(q);
0193 if(p1>=q1)
0194 {
0195 Scalar ps = p / p1;
0196 RealScalar p2 = numext::abs2(ps);
0197 Scalar qs = q / p1;
0198 RealScalar q2 = numext::abs2(qs);
0199
0200 RealScalar u = sqrt(RealScalar(1) + q2/p2);
0201 if(numext::real(p)<RealScalar(0))
0202 u = -u;
0203
0204 m_c = Scalar(1)/u;
0205 m_s = -qs*conj(ps)*(m_c/p2);
0206 if(r) *r = p * u;
0207 }
0208 else
0209 {
0210 Scalar ps = p / q1;
0211 RealScalar p2 = numext::abs2(ps);
0212 Scalar qs = q / q1;
0213 RealScalar q2 = numext::abs2(qs);
0214
0215 RealScalar u = q1 * sqrt(p2 + q2);
0216 if(numext::real(p)<RealScalar(0))
0217 u = -u;
0218
0219 p1 = abs(p);
0220 ps = p/p1;
0221 m_c = p1/u;
0222 m_s = -conj(ps) * (q/u);
0223 if(r) *r = ps * u;
0224 }
0225 }
0226 }
0227
0228
0229 template<typename Scalar>
0230 EIGEN_DEVICE_FUNC
0231 void JacobiRotation<Scalar>::makeGivens(const Scalar& p, const Scalar& q, Scalar* r, internal::false_type)
0232 {
0233 using std::sqrt;
0234 using std::abs;
0235 if(q==Scalar(0))
0236 {
0237 m_c = p<Scalar(0) ? Scalar(-1) : Scalar(1);
0238 m_s = Scalar(0);
0239 if(r) *r = abs(p);
0240 }
0241 else if(p==Scalar(0))
0242 {
0243 m_c = Scalar(0);
0244 m_s = q<Scalar(0) ? Scalar(1) : Scalar(-1);
0245 if(r) *r = abs(q);
0246 }
0247 else if(abs(p) > abs(q))
0248 {
0249 Scalar t = q/p;
0250 Scalar u = sqrt(Scalar(1) + numext::abs2(t));
0251 if(p<Scalar(0))
0252 u = -u;
0253 m_c = Scalar(1)/u;
0254 m_s = -t * m_c;
0255 if(r) *r = p * u;
0256 }
0257 else
0258 {
0259 Scalar t = p/q;
0260 Scalar u = sqrt(Scalar(1) + numext::abs2(t));
0261 if(q<Scalar(0))
0262 u = -u;
0263 m_s = -Scalar(1)/u;
0264 m_c = -t * m_s;
0265 if(r) *r = q * u;
0266 }
0267
0268 }
0269
0270
0271
0272
0273
0274 namespace internal {
0275
0276
0277
0278
0279
0280
0281 template<typename VectorX, typename VectorY, typename OtherScalar>
0282 EIGEN_DEVICE_FUNC
0283 void apply_rotation_in_the_plane(DenseBase<VectorX>& xpr_x, DenseBase<VectorY>& xpr_y, const JacobiRotation<OtherScalar>& j);
0284 }
0285
0286
0287
0288
0289
0290
0291
0292 template<typename Derived>
0293 template<typename OtherScalar>
0294 EIGEN_DEVICE_FUNC
0295 inline void MatrixBase<Derived>::applyOnTheLeft(Index p, Index q, const JacobiRotation<OtherScalar>& j)
0296 {
0297 RowXpr x(this->row(p));
0298 RowXpr y(this->row(q));
0299 internal::apply_rotation_in_the_plane(x, y, j);
0300 }
0301
0302
0303
0304
0305
0306
0307
0308 template<typename Derived>
0309 template<typename OtherScalar>
0310 EIGEN_DEVICE_FUNC
0311 inline void MatrixBase<Derived>::applyOnTheRight(Index p, Index q, const JacobiRotation<OtherScalar>& j)
0312 {
0313 ColXpr x(this->col(p));
0314 ColXpr y(this->col(q));
0315 internal::apply_rotation_in_the_plane(x, y, j.transpose());
0316 }
0317
0318 namespace internal {
0319
0320 template<typename Scalar, typename OtherScalar,
0321 int SizeAtCompileTime, int MinAlignment, bool Vectorizable>
0322 struct apply_rotation_in_the_plane_selector
0323 {
0324 static EIGEN_DEVICE_FUNC
0325 inline void run(Scalar *x, Index incrx, Scalar *y, Index incry, Index size, OtherScalar c, OtherScalar s)
0326 {
0327 for(Index i=0; i<size; ++i)
0328 {
0329 Scalar xi = *x;
0330 Scalar yi = *y;
0331 *x = c * xi + numext::conj(s) * yi;
0332 *y = -s * xi + numext::conj(c) * yi;
0333 x += incrx;
0334 y += incry;
0335 }
0336 }
0337 };
0338
0339 template<typename Scalar, typename OtherScalar,
0340 int SizeAtCompileTime, int MinAlignment>
0341 struct apply_rotation_in_the_plane_selector<Scalar,OtherScalar,SizeAtCompileTime,MinAlignment,true >
0342 {
0343 static inline void run(Scalar *x, Index incrx, Scalar *y, Index incry, Index size, OtherScalar c, OtherScalar s)
0344 {
0345 enum {
0346 PacketSize = packet_traits<Scalar>::size,
0347 OtherPacketSize = packet_traits<OtherScalar>::size
0348 };
0349 typedef typename packet_traits<Scalar>::type Packet;
0350 typedef typename packet_traits<OtherScalar>::type OtherPacket;
0351
0352
0353 if(SizeAtCompileTime == Dynamic && ((incrx==1 && incry==1) || PacketSize == 1))
0354 {
0355
0356 enum { Peeling = 2 };
0357
0358 Index alignedStart = internal::first_default_aligned(y, size);
0359 Index alignedEnd = alignedStart + ((size-alignedStart)/PacketSize)*PacketSize;
0360
0361 const OtherPacket pc = pset1<OtherPacket>(c);
0362 const OtherPacket ps = pset1<OtherPacket>(s);
0363 conj_helper<OtherPacket,Packet,NumTraits<OtherScalar>::IsComplex,false> pcj;
0364 conj_helper<OtherPacket,Packet,false,false> pm;
0365
0366 for(Index i=0; i<alignedStart; ++i)
0367 {
0368 Scalar xi = x[i];
0369 Scalar yi = y[i];
0370 x[i] = c * xi + numext::conj(s) * yi;
0371 y[i] = -s * xi + numext::conj(c) * yi;
0372 }
0373
0374 Scalar* EIGEN_RESTRICT px = x + alignedStart;
0375 Scalar* EIGEN_RESTRICT py = y + alignedStart;
0376
0377 if(internal::first_default_aligned(x, size)==alignedStart)
0378 {
0379 for(Index i=alignedStart; i<alignedEnd; i+=PacketSize)
0380 {
0381 Packet xi = pload<Packet>(px);
0382 Packet yi = pload<Packet>(py);
0383 pstore(px, padd(pm.pmul(pc,xi),pcj.pmul(ps,yi)));
0384 pstore(py, psub(pcj.pmul(pc,yi),pm.pmul(ps,xi)));
0385 px += PacketSize;
0386 py += PacketSize;
0387 }
0388 }
0389 else
0390 {
0391 Index peelingEnd = alignedStart + ((size-alignedStart)/(Peeling*PacketSize))*(Peeling*PacketSize);
0392 for(Index i=alignedStart; i<peelingEnd; i+=Peeling*PacketSize)
0393 {
0394 Packet xi = ploadu<Packet>(px);
0395 Packet xi1 = ploadu<Packet>(px+PacketSize);
0396 Packet yi = pload <Packet>(py);
0397 Packet yi1 = pload <Packet>(py+PacketSize);
0398 pstoreu(px, padd(pm.pmul(pc,xi),pcj.pmul(ps,yi)));
0399 pstoreu(px+PacketSize, padd(pm.pmul(pc,xi1),pcj.pmul(ps,yi1)));
0400 pstore (py, psub(pcj.pmul(pc,yi),pm.pmul(ps,xi)));
0401 pstore (py+PacketSize, psub(pcj.pmul(pc,yi1),pm.pmul(ps,xi1)));
0402 px += Peeling*PacketSize;
0403 py += Peeling*PacketSize;
0404 }
0405 if(alignedEnd!=peelingEnd)
0406 {
0407 Packet xi = ploadu<Packet>(x+peelingEnd);
0408 Packet yi = pload <Packet>(y+peelingEnd);
0409 pstoreu(x+peelingEnd, padd(pm.pmul(pc,xi),pcj.pmul(ps,yi)));
0410 pstore (y+peelingEnd, psub(pcj.pmul(pc,yi),pm.pmul(ps,xi)));
0411 }
0412 }
0413
0414 for(Index i=alignedEnd; i<size; ++i)
0415 {
0416 Scalar xi = x[i];
0417 Scalar yi = y[i];
0418 x[i] = c * xi + numext::conj(s) * yi;
0419 y[i] = -s * xi + numext::conj(c) * yi;
0420 }
0421 }
0422
0423
0424 else if(SizeAtCompileTime != Dynamic && MinAlignment>0)
0425 {
0426 const OtherPacket pc = pset1<OtherPacket>(c);
0427 const OtherPacket ps = pset1<OtherPacket>(s);
0428 conj_helper<OtherPacket,Packet,NumTraits<OtherPacket>::IsComplex,false> pcj;
0429 conj_helper<OtherPacket,Packet,false,false> pm;
0430 Scalar* EIGEN_RESTRICT px = x;
0431 Scalar* EIGEN_RESTRICT py = y;
0432 for(Index i=0; i<size; i+=PacketSize)
0433 {
0434 Packet xi = pload<Packet>(px);
0435 Packet yi = pload<Packet>(py);
0436 pstore(px, padd(pm.pmul(pc,xi),pcj.pmul(ps,yi)));
0437 pstore(py, psub(pcj.pmul(pc,yi),pm.pmul(ps,xi)));
0438 px += PacketSize;
0439 py += PacketSize;
0440 }
0441 }
0442
0443
0444 else
0445 {
0446 apply_rotation_in_the_plane_selector<Scalar,OtherScalar,SizeAtCompileTime,MinAlignment,false>::run(x,incrx,y,incry,size,c,s);
0447 }
0448 }
0449 };
0450
0451 template<typename VectorX, typename VectorY, typename OtherScalar>
0452 EIGEN_DEVICE_FUNC
0453 void apply_rotation_in_the_plane(DenseBase<VectorX>& xpr_x, DenseBase<VectorY>& xpr_y, const JacobiRotation<OtherScalar>& j)
0454 {
0455 typedef typename VectorX::Scalar Scalar;
0456 const bool Vectorizable = (int(VectorX::Flags) & int(VectorY::Flags) & PacketAccessBit)
0457 && (int(packet_traits<Scalar>::size) == int(packet_traits<OtherScalar>::size));
0458
0459 eigen_assert(xpr_x.size() == xpr_y.size());
0460 Index size = xpr_x.size();
0461 Index incrx = xpr_x.derived().innerStride();
0462 Index incry = xpr_y.derived().innerStride();
0463
0464 Scalar* EIGEN_RESTRICT x = &xpr_x.derived().coeffRef(0);
0465 Scalar* EIGEN_RESTRICT y = &xpr_y.derived().coeffRef(0);
0466
0467 OtherScalar c = j.c();
0468 OtherScalar s = j.s();
0469 if (c==OtherScalar(1) && s==OtherScalar(0))
0470 return;
0471
0472 apply_rotation_in_the_plane_selector<
0473 Scalar,OtherScalar,
0474 VectorX::SizeAtCompileTime,
0475 EIGEN_PLAIN_ENUM_MIN(evaluator<VectorX>::Alignment, evaluator<VectorY>::Alignment),
0476 Vectorizable>::run(x,incrx,y,incry,size,c,s);
0477 }
0478
0479 }
0480
0481 }
0482
0483 #endif