Jpp  18.2.1-ARCA-DF-PATCH
the software that should make you happy
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
JSVD3D.hh
Go to the documentation of this file.
1 #ifndef __JMATH_JSVD3D__
2 #define __JMATH_JSVD3D__
3 
4 #include <algorithm>
5 #include <cmath>
6 #include <array>
7 
8 #include "JMath/JConstants.hh"
9 #include "JMath/JMatrix3D.hh"
10 #include "JMath/JMatrix3S.hh"
11 
12 
13 namespace JMATH {}
14 namespace JPP { using namespace JMATH; }
15 
16 namespace JMATH {
17 
18  /**
19  * Singular value decomposition.
20  *
21  * See:
22  * "Computing the Singular Value Decomposition of 3x3 matrices
23  * with minimal branching and elementary floating point operations",\n
24  * A.\ McAdams, A.\ Selle, R.\ Tamstorf, J.\ Teran and E.\ Sifakis,\n
25  * University of Wisconsin - Madison technical report TR1690, May 2011
26  */
27  class JSVD3D {
28  public:
29  /**
30  * Default constructor.
31  */
33  {}
34 
35 
36  /**
37  * Constructor.
38  *
39  * \param A matrix
40  */
41  JSVD3D(const JMatrix3D& A)
42  {
43  decompose(A);
44  }
45 
46 
47  /**
48  * Decompose given matrix.
49  *
50  * \param A matrix
51  */
52  void decompose(const JMatrix3D& A)
53  {
54  using namespace std;
55 
56  // B = A^T * A
57 
58  B.a00 = A.a00 * A.a00 + A.a10 * A.a10 + A.a20 * A.a20;
59 
60  B.a10 = A.a01 * A.a00 + A.a11 * A.a10 + A.a21 * A.a20;
61  B.a11 = A.a01 * A.a01 + A.a11 * A.a11 + A.a21 * A.a21;
62 
63  B.a20 = A.a02 * A.a00 + A.a12 * A.a10 + A.a22 * A.a20;
64  B.a21 = A.a02 * A.a01 + A.a12 * A.a11 + A.a22 * A.a21;
65  B.a22 = A.a02 * A.a02 + A.a12 * A.a12 + A.a22 * A.a22;
66 
67  B.a01 = B.a10;
68  B.a02 = B.a20;
69  B.a12 = B.a21;
70 
71 
72  // symmetric eigen alysis
73 
74  const JQuaternion q(B);
75 
76  const double w = q[3];
77  const double x = q[0];
78  const double y = q[1];
79  const double z = q[2];
80 
81  const double xx = x*x;
82  const double yy = y*y;
83  const double zz = z*z;
84  const double xz = x*z;
85  const double xy = x*y;
86  const double yz = y*z;
87  const double wx = w*x;
88  const double wy = w*y;
89  const double wz = w*z;
90 
91  V.a00 = 1.0 - 2.0*(yy + zz); V.a01 = 2.0*(xy - wz); V.a02 = 2.0*(xz + wy);
92  V.a10 = 2.0*(xy + wz); V.a11 = 1.0 - 2.0*(xx + zz); V.a12 = 2.0*(yz - wx);
93  V.a20 = 2.0*(xz - wy); V.a21 = 2.0*(yz + wx); V.a22 = 1.0 - 2.0*(xx + yy);
94 
95 
96  B.mul(A, V);
97 
98 
99  // sort singular values.
100 
101  double rho1 = getLengthSquared(B.a00, B.a10, B.a20);
102  double rho2 = getLengthSquared(B.a01, B.a11, B.a21);
103  double rho3 = getLengthSquared(B.a02, B.a12, B.a22);
104 
105  if (rho1 < rho2) {
106  swap(B.a00,B.a01); B.a01 = -B.a01; swap(V.a00,V.a01); V.a01 = -V.a01;
107  swap(B.a10,B.a11); B.a11 = -B.a11; swap(V.a10,V.a11); V.a11 = -V.a11;
108  swap(B.a20,B.a21); B.a21 = -B.a21; swap(V.a20,V.a21); V.a21 = -V.a21;
109  swap(rho1,rho2);
110  }
111 
112  if (rho1 < rho3) {
113  swap(B.a00,B.a02); B.a02 = -B.a02; swap(V.a00,V.a02); V.a02 = -V.a02;
114  swap(B.a10,B.a12); B.a12 = -B.a12; swap(V.a10,V.a12); V.a12 = -V.a12;
115  swap(B.a20,B.a22); B.a22 = -B.a22; swap(V.a20,V.a22); V.a22 = -V.a22;
116  swap(rho1,rho3);
117  }
118 
119  if (rho2 < rho3) {
120  swap(B.a01,B.a02); B.a02 = -B.a02; swap(V.a01,V.a02); V.a02 = -V.a02;
121  swap(B.a11,B.a12); B.a12 = -B.a12; swap(V.a11,V.a12); V.a12 = -V.a12;
122  swap(B.a21,B.a22); B.a22 = -B.a22; swap(V.a21,V.a22); V.a22 = -V.a22;
123  }
124 
125 
126  // QR decomposition
127 
128  JMatrix3D& Q = U;
129  JMatrix3D& R = S;
130 
131  double a, b;
132 
133  const JGivens q1(B.a00, B.a10); // 1st Givens rotation (ch,0,0,sh)
134 
135  a = q1.geta();
136  b = q1.getb();
137 
138  // apply B = Q' * B
139 
140  R.a00 = a*B.a00 + b*B.a10; R.a01 = a*B.a01 + b*B.a11; R.a02 = a*B.a02 + b*B.a12;
141  R.a10 = -b*B.a00 + a*B.a10; R.a11 = -b*B.a01 + a*B.a11; R.a12 = -b*B.a02 + a*B.a12;
142  R.a20 = B.a20; R.a21 = B.a21; R.a22 = B.a22;
143 
144  const JGivens q2(R.a00, R.a20); // 2nd Givens rotation (ch,0,-sh,0)
145 
146  a = q2.geta();
147  b = q2.getb();
148 
149  // apply B = Q' * B;
150 
151  B.a00 = a*R.a00 + b*R.a20; B.a01 = a*R.a01 + b*R.a21; B.a02 = a*R.a02 + b*R.a22;
152  B.a10 = R.a10; B.a11 = R.a11; B.a12 = R.a12;
153  B.a20 = -b*R.a00 + a*R.a20; B.a21 = -b*R.a01 + a*R.a21; B.a22 = -b*R.a02 + a*R.a22;
154 
155  const JGivens q3(B.a11, B.a21); // 3rd Givens rotation (ch,sh,0,0)
156 
157  a = q3.geta();
158  b = q3.getb();
159 
160  // R is now set to desired value
161 
162  R.a00 = B.a00; R.a01 = B.a01; R.a02 = B.a02;
163  R.a10 = a*B.a10+b*B.a20; R.a11 = a*B.a11 + b*B.a21; R.a12 = a*B.a12 + b*B.a22;
164  R.a20 = -b*B.a10+a*B.a20; R.a21 = -b*B.a11 + a*B.a21; R.a22 = -b*B.a12 + a*B.a22;
165 
166  // Q = Q1 * Q2 * Q3
167 
168  const double sp1 = -1.0 + 2.0*q1.sh*q1.sh;
169  const double sp2 = -1.0 + 2.0*q2.sh*q2.sh;
170  const double sp3 = -1.0 + 2.0*q3.sh*q3.sh;
171 
172  Q.a00 = sp1*sp2;
173  Q.a01 = 4.0*q2.ch*q3.ch*sp1*q2.sh*q3.sh + 2.0*q1.ch*q1.sh*sp3;
174  Q.a02 = 4.0*q1.ch*q3.ch*q1.sh*q3.sh - 2.0*q2.ch*sp1*q2.sh*sp3;
175 
176  Q.a10 = -2.0*q1.ch*q1.sh*sp2;
177  Q.a11 = -8.0*q1.ch*q2.ch*q3.ch*q1.sh*q2.sh*q3.sh + sp1*sp3;
178  Q.a12 = -2.0*q3.ch*q3.sh + 4.0*q1.sh*(q3.ch*q1.sh*q3.sh + q1.ch*q2.ch*q2.sh*sp3);
179 
180  Q.a20 = 2.0*q2.ch*q2.sh;
181  Q.a21 = -2.0*q3.ch*sp2*q3.sh;
182  Q.a22 = sp2*sp3;
183  }
184 
185 
186  /**
187  * Get inverted matrix.
188  *
189  * \param precision precision
190  * \return inverted matrix
191  */
192  const JMatrix3D& invert(const double precision = 1.0e-12) const
193  {
194  double w = fabs(S.a00);
195 
196  if (fabs(S.a11) > w) { w = fabs(S.a11); }
197  if (fabs(S.a22) > w) { w = fabs(S.a22); }
198 
199  w *= precision;
200 
201  const double s00 = (fabs(S.a00) >= w ? 1.0 / S.a00 : 0.0);
202  const double s11 = (fabs(S.a11) >= w ? 1.0 / S.a11 : 0.0);
203  const double s22 = (fabs(S.a22) >= w ? 1.0 / S.a22 : 0.0);
204 
205  // B = V * S^-1
206 
207  B.a00 = V.a00*s00; B.a01 = V.a01*s11; B.a02 = V.a02*s22;
208  B.a10 = V.a10*s00; B.a11 = V.a11*s11; B.a12 = V.a12*s22;
209  B.a20 = V.a20*s00; B.a21 = V.a21*s11; B.a22 = V.a22*s22;
210 
211  U.transpose();
212 
213  // B = V * S^-1 * U^T
214 
215  B.mul(U);
216 
217  U.transpose();
218 
219  return B;
220  }
221 
222  mutable JMatrix3D U;
223  mutable JMatrix3D S;
224  mutable JMatrix3D V;
225 
226  private:
227 
228  mutable JMatrix3S B; // work space
229 
230  /**
231  * Auxiliary class for quaternion computation.
232  */
233  struct JQuaternion :
234  public std::array<double, 4>
235  {
236  /**
237  * Constructor.
238  *
239  * Finds transformation that diagonalizes the given symmetric matrix by using Jacobi eigen analysis.
240  *
241  * \param S matrix
242  */
244  {
245  // follow same indexing convention as GLM
246 
247  (*this)[3] = 1.0;
248  (*this)[0] = 0.0;
249  (*this)[1] = 0.0;
250  (*this)[2] = 0.0;
251 
252  for (int i = 0; i != 4; ++i) {
253 
254  // eliminate maximum off-diagonal element on every iteration,
255  // while cycling over all 3 possible rotations in fixed order.
256  // (p,q) = (0,1), (1,2), (0,2) still retains asymptotic convergence.
257 
258  conjugate(0, 1, 2, S); // (p,q) = (0,1)
259  conjugate(1, 2, 0, S); // (p,q) = (1,2)
260  conjugate(2, 0, 1, S); // (p,q) = (0,2)
261  }
262  }
263 
264  private:
265 
266  /**
267  * Get conjugate of symmetric matrix for given order.
268  *
269  * \param x 1st index
270  * \param y 2nd index
271  * \param z 3rd index
272  * \param S matrix
273  */
274  inline void conjugate(const int x,
275  const int y,
276  const int z,
277  JMatrix3S& S)
278  {
279  static const double GAMMA = sqrt(8.0) + 3.0;
280  static const double CSTAR = cos(PI/8.0);
281  static const double SSTAR = sin(PI/8.0);
282 
283  // approximate Givens quaternion
284 
285  double ch = 2.0*(S.a00 - S.a11);
286  double sh = S.a10;
287 
288  if (GAMMA*sh*sh < ch*ch) {
289 
290  const double w = 1.0 / sqrt(ch*ch+sh*sh);
291 
292  ch *= w;
293  sh *= w;
294 
295  } else {
296 
297  ch = CSTAR;
298  sh = SSTAR;
299  }
300 
301  const double scale = ch*ch + sh*sh;
302  const double a = (ch+sh)*(ch-sh) / scale;
303  const double b = (2.0*sh*ch) / scale;
304 
305  // make temporary copy of S
306 
307  double s00 = S.a00;
308  double s10 = S.a10; double s11 = S.a11;
309  double s20 = S.a20; double s21 = S.a21; double s22 = S.a22;
310 
311  // perform conjugation S = Q' * S * Q
312  // where Q is already implicitly solved from a and b
313 
314  S.a00 = a*( a*s00 + b*s10) + b*( a*s10 + b*s11);
315  S.a10 = a*(-b*s00 + a*s10) + b*(-b*s10 + a*s11);
316  S.a11 = -b*(-b*s00 + a*s10) + a*(-b*s10 + a*s11);
317  S.a20 = a*s20 + b*s21;
318  S.a21 = -b*s20 + a*s21;
319  S.a22 = s22;
320 
321  // update cumulative rotation
322 
323  double tmp[] = {
324  (*this)[0]*sh,
325  (*this)[1]*sh,
326  (*this)[2]*sh
327  };
328 
329  sh *= (*this)[3];
330 
331  (*this)[0] *= ch;
332  (*this)[1] *= ch;
333  (*this)[2] *= ch;
334  (*this)[3] *= ch;
335 
336  // (x,y,z) corresponds to {(0,1,2), (1,2,0), (2,0,1)}
337  // for (p,q) = {(0,1), (1,2), (0,2)}, respectively.
338 
339  (*this)[z] += sh;
340  (*this)[3] -= tmp[z]; // w
341  (*this)[x] += tmp[y];
342  (*this)[y] -= tmp[x];
343 
344  // re-arrange matrix for next iteration
345 
346  s00 = S.a11;
347  s10 = S.a21; s11 = S.a22;
348  s20 = S.a10; s21 = S.a20; s22 = S.a00;
349 
350  S.a00 = s00;
351  S.a10 = s10; S.a11 = s11;
352  S.a20 = s20; S.a21 = s21; S.a22 = s22;
353  }
354  };
355 
356 
357  /**
358  * Get length squared.
359  *
360  * \param x x
361  * \param y y
362  * \param z z
363  * \return square of length
364  */
365  static inline double getLengthSquared(const double x, const double y, const double z)
366  {
367  return x*x + y*y + z*z;
368  }
369 
370 
371  /**
372  * Givens quaternion.
373  */
374  struct JGivens {
375 
376  static constexpr double EPSILON = 1.0e-6;
377 
378  /**
379  * Constructor.
380  *
381  * \param a pivot point on diagonal
382  * \param b lower triangular entry we want to annihilate
383  */
384  JGivens(const double a,
385  const double b)
386  {
387  using namespace std;
388 
389  const double rho = sqrt(a*a + b*b);
390 
391  sh = rho > EPSILON ? b : 0.0;
392  ch = fabs(a) + max(rho,EPSILON);
393 
394  if (a < 0.0) {
395  swap(sh,ch);
396  }
397 
398  const double w = 1.0 / sqrt(ch*ch + sh*sh);
399 
400  ch *= w;
401  sh *= w;
402  }
403 
404  inline double geta() const { return 1.0 - 2.0*sh*sh; } //!< get new a value
405  inline double getb() const { return 2.0*ch*sh; } //!< get new b value
406 
407  double ch; //!< cosine rotation angle
408  double sh; //!< sine rotation angle
409  };
410  };
411 }
412 
413 #endif
Auxiliary class for quaternion computation.
Definition: JSVD3D.hh:233
data_type w[N+1][M+1]
Definition: JPolint.hh:867
Q(UTCMax_s-UTCMin_s)-livetime_s
static double getLengthSquared(const double x, const double y, const double z)
Get length squared.
Definition: JSVD3D.hh:365
JMatrix3S B
Definition: JSVD3D.hh:228
3 x 3 matrix
Givens quaternion.
Definition: JSVD3D.hh:374
JMatrix3D & mul(const double factor)
Scale matrix.
JMatrix3D & transpose()
Transpose.
double sh
sine rotation angle
Definition: JSVD3D.hh:408
JGivens(const double a, const double b)
Constructor.
Definition: JSVD3D.hh:384
then usage set_variable ACOUSTICS_WORKDIR $WORKDIR set_variable FORMULA sin([0]+2 *$PI *([1]+[2]*x)*x)" set_variable DY 1.0e-8 mkdir $WORKDIR for DETECTOR in $DETECTORS[*]
JSVD3D()
Default constructor.
Definition: JSVD3D.hh:32
static constexpr double EPSILON
Definition: JSVD3D.hh:376
JQuaternion(JMatrix3S &S)
Constructor.
Definition: JSVD3D.hh:243
JSVD3D(const JMatrix3D &A)
Constructor.
Definition: JSVD3D.hh:41
3 x 3 symmetric matrix
Definition: JMatrix3S.hh:29
Mathematical constants.
then JCalibrateToT a
Definition: JTuneHV.sh:113
double ch
cosine rotation angle
Definition: JSVD3D.hh:407
double getb() const
get new b value
Definition: JSVD3D.hh:405
void decompose(const JMatrix3D &A)
Decompose given matrix.
Definition: JSVD3D.hh:52
JMatrix3D S
Definition: JSVD3D.hh:223
JMatrix3D U
Definition: JSVD3D.hh:222
Singular value decomposition.
Definition: JSVD3D.hh:27
double geta() const
get new a value
Definition: JSVD3D.hh:404
static const double PI
Mathematical constants.
void conjugate(const int x, const int y, const int z, JMatrix3S &S)
Get conjugate of symmetric matrix for given order.
Definition: JSVD3D.hh:274
then JCookie sh JDataQuality D $DETECTOR_ID R
Definition: JDataQuality.sh:41
const JMatrix3D & invert(const double precision=1.0e-12) const
Get inverted matrix.
Definition: JSVD3D.hh:192
JMatrix3D V
Definition: JSVD3D.hh:224
source $JPP_DIR setenv csh $JPP_DIR &dev null eval JShellParser o a A
void scale(vector< double > &v, double c)
scale vector content