ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
SquareMatrix.h
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 
8 #pragma once
9 
10 // local
11 #include "CVGeom.h"
12 
13 // system
14 #include <cassert>
15 #include <cstdio>
16 #include <cstring>
17 #include <vector>
18 
19 namespace cloudViewer {
21 
24 template <typename Scalar>
26 public:
28 
30  SquareMatrixTpl() { init(0); }
31 
33 
35  SquareMatrixTpl(unsigned size) { init(size); }
36 
38 
41  if (init(mat.size())) {
42  for (unsigned r = 0; r < m_matrixSize; r++)
43  for (unsigned c = 0; c < m_matrixSize; c++)
44  setValue(r, c, static_cast<Scalar>(mat.getValue(r, c)));
45  }
46  }
47 
49 
52  if (init(mat.size())) {
53  for (unsigned r = 0; r < m_matrixSize; r++)
54  for (unsigned c = 0; c < m_matrixSize; c++)
55  setValue(r, c, static_cast<Scalar>(mat.getValue(r, c)));
56  }
57  }
58 
60 
66  SquareMatrixTpl(const float M16f[], bool rotationOnly = false) {
67  unsigned size = (rotationOnly ? 3 : 4);
68 
69  if (init(size)) {
70  for (unsigned r = 0; r < size; r++)
71  for (unsigned c = 0; c < size; c++)
72  m_values[r][c] = static_cast<Scalar>(M16f[c * 4 + r]);
73  }
74  }
75 
77 
83  SquareMatrixTpl(const double M16d[], bool rotationOnly = false) {
84  unsigned size = (rotationOnly ? 3 : 4);
85 
86  if (init(size)) {
87  for (unsigned r = 0; r < size; r++)
88  for (unsigned c = 0; c < size; c++)
89  m_values[r][c] = static_cast<Scalar>(M16d[c * 4 + r]);
90  }
91  }
92 
94  virtual ~SquareMatrixTpl() { invalidate(); }
95 
97  inline SquareMatrixTpl(const Eigen::Matrix<Scalar, 3, 3>& mat) {
98  *this = mat;
99  }
100  inline SquareMatrixTpl(const Eigen::Matrix<Scalar, 4, 4>& mat) {
101  *this = mat;
102  }
103 
105  inline SquareMatrixTpl& operator=(const Eigen::Matrix<Scalar, 3, 3>& mat) {
106  assert(m_matrixSize <= 3);
107  for (unsigned r = 0; r < m_matrixSize; r++)
108  for (unsigned c = 0; c < m_matrixSize; c++)
109  m_values[r][c] =
110  static_cast<Scalar>(mat.data[c * m_matrixSize + r]);
111  return *this;
112  }
113 
114  inline SquareMatrixTpl& operator=(const Eigen::Matrix<Scalar, 4, 4>& mat) {
115  assert(m_matrixSize <= 4);
116  for (unsigned r = 0; r < m_matrixSize; r++)
117  for (unsigned c = 0; c < m_matrixSize; c++)
118  m_values[r][c] =
119  static_cast<Scalar>(mat.data[c * m_matrixSize + r]);
120  return *this;
121  }
122 
123  inline void toArray(Scalar data[]) {
124  memset(data, 0, sizeof(Scalar) * m_matrixSize * m_matrixSize);
125 
126  for (unsigned r = 0; r < m_matrixSize; r++)
127  for (unsigned c = 0; c < m_matrixSize; c++)
128  data[r + c * m_matrixSize] =
129  static_cast<double>(m_values[r][c]);
130  }
131 
133  inline unsigned size() const { return m_matrixSize; }
134 
136 
138  inline bool isValid() const { return (m_matrixSize != 0); }
139 
141 
143  void invalidate() {
144  delete[] m_underlyingData;
145  m_underlyingData = nullptr;
146 
147  delete[] m_values;
148  m_values = nullptr;
149 
150  m_matrixSize = 0;
151  matrixSquareSize = 0;
152  }
153 
155 
157  Scalar** m_values = nullptr;
158 
160  inline Scalar* row(unsigned index) { return m_values[index]; }
161 
163  void inline setValue(unsigned row, unsigned column, Scalar value) {
164  m_values[row][column] = value;
165  }
166 
168  Scalar inline getValue(unsigned row, unsigned column) const {
169  return m_values[row][column];
170  }
171 
174  if (m_matrixSize != B.size()) {
175  invalidate();
176  init(B.size());
177  }
178 
179  for (unsigned r = 0; r < m_matrixSize; r++)
180  for (unsigned c = 0; c < m_matrixSize; c++)
181  m_values[r][c] = B.m_values[r][c];
182 
183  return *this;
184  }
185 
188  SquareMatrixTpl C = *this;
189  C += B;
190 
191  return C;
192  }
193 
196  assert(B.size() == m_matrixSize);
197 
198  for (unsigned r = 0; r < m_matrixSize; r++)
199  for (unsigned c = 0; c < m_matrixSize; c++)
200  m_values[r][c] += B.m_values[r][c];
201 
202  return *this;
203  }
204 
207  SquareMatrixTpl C = *this;
208  C -= B;
209 
210  return C;
211  }
212 
215  assert(B.size() == m_matrixSize);
216 
217  for (unsigned r = 0; r < m_matrixSize; r++)
218  for (unsigned c = 0; c < m_matrixSize; c++)
219  m_values[r][c] -= B.m_values[r][c];
220 
221  return *this;
222  }
223 
226  assert(B.size() == m_matrixSize);
227 
228  SquareMatrixTpl C(m_matrixSize);
229 
230  for (unsigned r = 0; r < m_matrixSize; r++) {
231  for (unsigned c = 0; c < m_matrixSize; c++) {
232  Scalar sum = 0;
233  for (unsigned k = 0; k < m_matrixSize; k++)
234  sum += m_values[r][k] * B.m_values[k][c];
235  C.m_values[r][c] = sum;
236  }
237  }
238 
239  return C;
240  }
241 
244  if (m_matrixSize == 3) {
246  apply(V.u, result.u);
247 
248  return result;
249  } else {
250  return V;
251  }
252  }
253 
255  inline const SquareMatrixTpl& operator*=(const SquareMatrixTpl& B) {
256  *this = (*this) * B;
257 
258  return *this;
259  }
260 
262 
266  void apply(const float vec[], float result[]) const {
267  for (unsigned r = 0; r < m_matrixSize; r++) {
268  double sum = 0;
269  for (unsigned k = 0; k < m_matrixSize; k++)
270  sum += m_values[r][k] * static_cast<double>(vec[k]);
271  result[r] = static_cast<float>(sum);
272  }
273  }
274 
276 
280  void apply(const float vec[], double result[]) const {
281  for (unsigned r = 0; r < m_matrixSize; r++) {
282  double sum = 0;
283  for (unsigned k = 0; k < m_matrixSize; k++)
284  sum += m_values[r][k] * static_cast<double>(vec[k]);
285  result[r] = sum;
286  }
287  }
288 
290 
294  void apply(const double vec[], double result[]) const {
295  for (unsigned r = 0; r < m_matrixSize; r++) {
296  double sum = 0;
297  for (unsigned k = 0; k < m_matrixSize; k++)
298  sum += m_values[r][k] * static_cast<double>(vec[k]);
299  result[r] = sum;
300  }
301  }
302 
304  void transpose() {
305  for (unsigned r = 0; r < m_matrixSize - 1; r++)
306  for (unsigned c = r + 1; c < m_matrixSize; c++)
307  std::swap(m_values[r][c], m_values[c][r]);
308  }
309 
312  SquareMatrixTpl T(*this);
313  T.transpose();
314 
315  return T;
316  }
317 
319  void clear() {
320  for (unsigned r = 0; r < m_matrixSize; ++r) {
321  memset(m_values[r], 0, sizeof(Scalar) * m_matrixSize);
322  }
323  }
324 
327  // we create the n by 2n matrix, composed of this matrix and the
328  // identity
329  Scalar** tempM = nullptr;
330  {
331  tempM = new Scalar*[m_matrixSize];
332  if (!tempM) {
333  // not enough memory
334  return SquareMatrixTpl();
335  }
336  for (unsigned i = 0; i < m_matrixSize; i++) {
337  tempM[i] = new Scalar[2 * m_matrixSize];
338  if (!tempM[i]) {
339  // not enough memory
340  for (unsigned j = 0; j < i; j++) delete[] tempM[j];
341  delete[] tempM;
342  return SquareMatrixTpl();
343  }
344  }
345  }
346 
347  // identity
348  {
349  for (unsigned i = 0; i < m_matrixSize; i++) {
350  for (unsigned j = 0; j < m_matrixSize; j++) {
351  tempM[i][j] = m_values[i][j];
352  if (i == j)
353  tempM[i][j + m_matrixSize] = 1;
354  else
355  tempM[i][j + m_matrixSize] = 0;
356  }
357  }
358  }
359 
360  // Gauss pivot
361  {
362  for (unsigned i = 0; i < m_matrixSize; i++) {
363  // we look for the pivot value (first non zero element)
364  unsigned j = i;
365 
366  while (tempM[j][i] == 0) {
367  if (++j >= m_matrixSize) {
368  // non inversible matrix!
369  for (unsigned k = 0; k < m_matrixSize; ++k)
370  delete[] tempM[k];
371  delete[] tempM;
372  return SquareMatrixTpl();
373  }
374  }
375 
376  // swap the 2 rows if they are different
377  //(we only start by the ith element (as all the others are
378  // zero!)
379  if (i != j)
380  for (unsigned k = i; k < 2 * m_matrixSize; k++)
381  std::swap(tempM[i][k], tempM[j][k]);
382 
383  // we scale the matrix to make the pivot equal to 1
384  if (tempM[i][i] != 1.0) {
385  const Scalar& tmpVal = tempM[i][i];
386  for (unsigned k = i; k < 2 * m_matrixSize; ++k)
387  tempM[i][k] /= tmpVal;
388  }
389 
390  // after the pivot value, all elements are set to zero
391  for (unsigned j = i + 1; j < m_matrixSize; j++) {
392  if (tempM[j][i] != 0) {
393  const Scalar& tmpVal = tempM[j][i];
394  for (unsigned k = i; k < 2 * m_matrixSize; k++)
395  tempM[j][k] -= tempM[i][k] * tmpVal;
396  }
397  }
398  }
399  }
400 
401  // reduction
402  {
403  for (unsigned i = m_matrixSize - 1; i > 0; i--) {
404  for (unsigned j = 0; j < i; j++) {
405  if (tempM[j][i] != 0) {
406  const Scalar& tmpVal = tempM[j][i];
407  for (unsigned k = i; k < 2 * m_matrixSize; k++)
408  tempM[j][k] -= tempM[i][k] * tmpVal;
409  }
410  }
411  }
412  }
413 
414  // result: second part or tempM
415  SquareMatrixTpl result(m_matrixSize);
416  {
417  for (unsigned i = 0; i < m_matrixSize; i++)
418  for (unsigned j = 0; j < m_matrixSize; j++)
419  result.m_values[i][j] = tempM[i][j + m_matrixSize];
420  }
421 
422  // we release temp matrix from memory
423  {
424  for (unsigned i = 0; i < m_matrixSize; i++) delete[] tempM[i];
425  delete[] tempM;
426  tempM = nullptr;
427  }
428 
429  return result;
430  }
431 
433 
435  void print(FILE* fp = nullptr) const {
436  for (unsigned r = 0; r < m_matrixSize; r++) {
437  for (unsigned c = 0; c < m_matrixSize; c++) {
438  if (fp)
439  fprintf(fp, "%6.6f ", m_values[r][c]);
440  else
441  printf("%6.6f ", m_values[r][c]);
442  }
443 
444  if (fp)
445  fprintf(fp, "\n");
446  else
447  printf("\n");
448  }
449  }
450 
452  void toIdentity() {
453  clear();
454 
455  for (unsigned r = 0; r < m_matrixSize; r++) m_values[r][r] = 1;
456  }
457 
459  void scale(Scalar coef) {
460  for (unsigned r = 0; r < m_matrixSize; r++)
461  for (unsigned c = 0; c < m_matrixSize; c++) m_values[r][c] *= coef;
462  }
463 
465  Scalar trace() const {
466  Scalar trace = 0;
467 
468  for (unsigned r = 0; r < m_matrixSize; r++) trace += m_values[r][r];
469 
470  return trace;
471  }
472 
474  double computeDet() const { return computeSubDet(m_values, m_matrixSize); }
475 
477 
480  void initFromQuaternion(const float q[]) {
481  double qd[4] = {static_cast<double>(q[0]), static_cast<double>(q[1]),
482  static_cast<double>(q[2]), static_cast<double>(q[3])};
483 
484  initFromQuaternion(qd);
485  }
486 
488 
492  void initFromQuaternion(const double q[]) {
493  if (m_matrixSize == 0)
494  if (!init(3)) return;
495  assert(m_matrixSize == 3);
496 
497  double q00 = q[0] * q[0];
498  double q11 = q[1] * q[1];
499  double q22 = q[2] * q[2];
500  double q33 = q[3] * q[3];
501  double q03 = q[0] * q[3];
502  double q13 = q[1] * q[3];
503  double q23 = q[2] * q[3];
504  double q02 = q[0] * q[2];
505  double q12 = q[1] * q[2];
506  double q01 = q[0] * q[1];
507 
508  m_values[0][0] = static_cast<Scalar>(q00 + q11 - q22 - q33);
509  m_values[1][1] = static_cast<Scalar>(q00 - q11 + q22 - q33);
510  m_values[2][2] = static_cast<Scalar>(q00 - q11 - q22 + q33);
511  m_values[0][1] = static_cast<Scalar>(2.0 * (q12 - q03));
512  m_values[1][0] = static_cast<Scalar>(2.0 * (q12 + q03));
513  m_values[0][2] = static_cast<Scalar>(2.0 * (q13 + q02));
514  m_values[2][0] = static_cast<Scalar>(2.0 * (q13 - q02));
515  m_values[1][2] = static_cast<Scalar>(2.0 * (q23 - q01));
516  m_values[2][1] = static_cast<Scalar>(2.0 * (q23 + q01));
517  }
518 
520 
525  bool toQuaternion(double q[/*4*/]) {
526  if (m_matrixSize != 3) return false;
527 
528  double dTrace = static_cast<double>(m_values[0][0]) +
529  static_cast<double>(m_values[1][1]) +
530  static_cast<double>(m_values[2][2]) + 1.0;
531 
532  double w, x, y, z; // quaternion
533  if (dTrace > 1.0e-6) {
534  double S = 2.0 * sqrt(dTrace);
535  x = (m_values[2][1] - m_values[1][2]) / S;
536  y = (m_values[0][2] - m_values[2][0]) / S;
537  z = (m_values[1][0] - m_values[0][1]) / S;
538  w = 0.25 * S;
539  } else if (m_values[0][0] > m_values[1][1] &&
540  m_values[0][0] > m_values[2][2]) {
541  double S = sqrt(1.0 + m_values[0][0] - m_values[1][1] -
542  m_values[2][2]) *
543  2.0;
544  x = 0.25 * S;
545  y = (m_values[1][0] + m_values[0][1]) / S;
546  z = (m_values[0][2] + m_values[2][0]) / S;
547  w = (m_values[2][1] - m_values[1][2]) / S;
548  } else if (m_values[1][1] > m_values[2][2]) {
549  double S = sqrt(1.0 + m_values[1][1] - m_values[0][0] -
550  m_values[2][2]) *
551  2.0;
552  x = (m_values[1][0] + m_values[0][1]) / S;
553  y = 0.25 * S;
554  z = (m_values[2][1] + m_values[1][2]) / S;
555  w = (m_values[0][2] - m_values[2][0]) / S;
556  } else {
557  double S = sqrt(1.0 + m_values[2][2] - m_values[0][0] -
558  m_values[1][1]) *
559  2.0;
560  x = (m_values[0][2] + m_values[2][0]) / S;
561  y = (m_values[2][1] + m_values[1][2]) / S;
562  z = 0.25 * S;
563  w = (m_values[1][0] - m_values[0][1]) / S;
564  }
565 
566  // normalize the quaternion if the matrix is not a clean rigid body
567  // matrix or if it has scaler information.
568  double len = sqrt(w * w + x * x + y * y + z * z);
569  if (len != 0) {
570  q[0] = w / len;
571  q[1] = x / len;
572  q[2] = y / len;
573  q[3] = z / len;
574 
575  return true;
576  }
577 
578  return false;
579  }
580 
582  Scalar deltaDeterminant(unsigned column, Scalar* Vec) const {
583  SquareMatrixTpl mat(m_matrixSize);
584 
585  for (unsigned i = 0; i < m_matrixSize; i++) {
586  if (column == i) {
587  for (unsigned j = 0; j < m_matrixSize; j++) {
588  mat.m_values[j][i] = static_cast<Scalar>(*Vec);
589  Vec++;
590  }
591  } else {
592  for (unsigned j = 0; j < m_matrixSize; j++)
593  mat.m_values[j][i] = m_values[j][i];
594  }
595  }
596 
597  return mat.computeDet();
598  }
599 
601  void toGlMatrix(float M16f[]) const {
602  assert(m_matrixSize == 3 || m_matrixSize == 4);
603  memset(M16f, 0, sizeof(float) * 16);
604 
605  for (unsigned r = 0; r < 3; r++)
606  for (unsigned c = 0; c < 3; c++)
607  M16f[r + c * 4] = static_cast<float>(m_values[r][c]);
608 
609  if (m_matrixSize == 4)
610  for (unsigned r = 0; r < 3; r++) {
611  M16f[12 + r] = static_cast<float>(m_values[3][r]);
612  M16f[3 + r * 4] = static_cast<float>(m_values[r][3]);
613  }
614 
615  M16f[15] = 1.0f;
616  }
617 
620  void toGlMatrix(double M16d[]) const {
621  assert(m_matrixSize == 3 || m_matrixSize == 4);
622  memset(M16d, 0, sizeof(double) * 16);
623 
624  for (unsigned r = 0; r < 3; r++)
625  for (unsigned c = 0; c < 3; c++)
626  M16d[r + c * 4] = static_cast<double>(m_values[r][c]);
627 
628  if (m_matrixSize == 4) {
629  for (unsigned r = 0; r < 3; r++) {
630  M16d[12 + r] = static_cast<double>(m_values[3][r]);
631  M16d[3 + r * 4] = static_cast<double>(m_values[r][3]);
632  }
633  }
634 
635  M16d[15] = 1.0;
636  }
637 
641  if (m_matrixSize < 0) return false;
642 
643  // S : copy of the current matrix
644  SquareMatrixTpl S_(*this);
645 
646  // U : identity matrix
647  SquareMatrixTpl U_(m_matrixSize);
648  U_.toIdentity();
649 
650  // V : identity matrix
651  SquareMatrixTpl V_(m_matrixSize);
652  V_.toIdentity();
653 
654  ComputeSVD(m_matrixSize, U_, S_, V_);
655 
656  // sort the eigenvalues (absolute values)
657  std::vector<unsigned> eigOrder(m_matrixSize);
658  {
659  for (unsigned i = 0; i < m_matrixSize; i++) {
660  eigOrder[i] = i;
661  }
662  for (unsigned i = 0; i < m_matrixSize - 1; i++) {
663  unsigned largest = i;
664  Scalar largestEigValue = std::abs(
665  S_.getValue(eigOrder[largest], eigOrder[largest]));
666 
667  for (unsigned j = i + 1; j < m_matrixSize; j++) {
668  Scalar eigValue =
669  std::abs(S_.getValue(eigOrder[j], eigOrder[j]));
670  if (eigValue > largestEigValue) {
671  largest = j;
672  largestEigValue = eigValue;
673  }
674  }
675  if (largest != i) {
676  std::swap(eigOrder[i], eigOrder[largest]);
677  }
678  }
679  }
680 
681  // Build the output U, S and V matrices
682  S.init(m_matrixSize);
683  S.clear();
684  U.init(m_matrixSize);
685  V.init(m_matrixSize);
686  {
687  // for each eigen value
688  for (unsigned j = 0; j < m_matrixSize; j++) {
689  unsigned index = eigOrder[j];
690 
691  Scalar eigValue = S_.getValue(index, index);
692 
693  // we flip the eigen vector so that all eigen values are
694  // positive
695  S.setValue(j, j, std::abs(eigValue));
696  Scalar sign = static_cast<Scalar>(eigValue < 0 ? -1 : 1);
697 
698  // copy the corresponding column
699  for (unsigned i = 0; i < m_matrixSize; i++) {
700  U.setValue(i, j, U_.getValue(i, index) * sign);
701  V.setValue(i, j, V_.getValue(index, i));
702  }
703  }
704  }
705 
706  return true;
707  }
708 
709 private:
711 
713  bool init(unsigned size) {
714  m_matrixSize = size;
715  matrixSquareSize = m_matrixSize * m_matrixSize;
716 
717  if (size == 0) {
718  return true;
719  }
720 
721  m_values = new Scalar* [m_matrixSize] {};
722  m_underlyingData = new Scalar[matrixSquareSize]{};
723 
724  if ((m_values == nullptr) || (m_underlyingData == nullptr)) {
725  return false;
726  }
727 
728  for (unsigned i = 0; i < m_matrixSize; i++) {
729  m_values[i] = m_underlyingData + (i * m_matrixSize);
730  }
731 
732  return true;
733  }
734 
736  double computeSubDet(Scalar** mat, unsigned matSize) const {
737  if (matSize == 2) {
738  return static_cast<double>(mat[0][0] * mat[1][1] -
739  mat[0][1] * mat[1][0]);
740  }
741 
742  Scalar** subMat = new Scalar*[matSize - 1];
743  if (subMat) {
744  double subDet = 0;
745  double sign = 1.0;
746 
747  for (unsigned row = 0; row < matSize; row++) {
748  unsigned k = 0;
749  for (unsigned i = 0; i < matSize; i++)
750  if (i != row) subMat[k++] = mat[i] + 1;
751 
752  subDet += static_cast<double>(mat[row][0]) *
753  computeSubDet(subMat, matSize - 1) * sign;
754  sign = -sign;
755  }
756 
757  delete[] subMat;
758  return subDet;
759  } else {
760  // not enough memory
761  return 0.0;
762  }
763  }
764 
765 private
766  : // methods used to perform the SVD decomposition (inspired from
767  // https://github.com/dmalhotra/pvfmm/blob/develop/include/mat_utils.txx)
768  static void GivensL(SquareMatrixTpl& S, unsigned m, Scalar a, Scalar b) {
769  Scalar r = sqrt(a * a + b * b);
770  if (r == 0) return;
771  Scalar c = a / r;
772  Scalar s = -b / r;
773 
774  for (int i = 0; i < static_cast<int>(S.size()); i++) {
775  Scalar S0 = S.getValue(m + 0, i);
776  Scalar S1 = S.getValue(m + 1, i);
777  S.setValue(m, i, S.getValue(m, i) + S0 * (c - 1) - S1 * s);
778  S.setValue(m + 1, i, S.getValue(m + 1, i) + S0 * s + S1 * (c - 1));
779  }
780  }
781 
782  static void GivensR(SquareMatrixTpl& S, unsigned m, Scalar a, Scalar b) {
783  Scalar r = sqrt(a * a + b * b);
784  if (r == 0) return;
785  Scalar c = a / r;
786  Scalar s = -b / r;
787 
788  for (int i = 0; i < static_cast<int>(S.size()); i++) {
789  Scalar S0 = S.getValue(i, m + 0);
790  Scalar S1 = S.getValue(i, m + 1);
791  S.setValue(i, m, S.getValue(i, m) + S0 * (c - 1) - S1 * s);
792  S.setValue(i, m + 1, S.getValue(i, m + 1) + S0 * s + S1 * (c - 1));
793  }
794  }
795 
796  static void ComputeSVD(unsigned matrixSize,
797  SquareMatrixTpl& U,
798  SquareMatrixTpl& S,
799  SquareMatrixTpl& V) {
800  assert(matrixSize >= 2);
801 
802  // Bi-diagonalization
803  {
804  std::vector<Scalar> house_vec(matrixSize);
805  for (unsigned i = 0; i < matrixSize; i++) {
806  // Column Householder
807  {
808  Scalar x1 = S.getValue(i, i);
809  if (x1 < 0) x1 = -x1;
810 
811  Scalar x_inv_norm = 0;
812  for (unsigned j = i; j < matrixSize; j++) {
813  x_inv_norm += S.getValue(j, i) * S.getValue(j, i);
814  }
815  if (x_inv_norm > 0) x_inv_norm = 1 / sqrt(x_inv_norm);
816 
817  Scalar alpha = sqrt(1 + x1 * x_inv_norm);
818  Scalar beta = x_inv_norm / alpha;
819  if (x_inv_norm == 0) alpha = 0; // nothing to do
820 
821  house_vec[i] = -alpha;
822  for (unsigned j = i + 1; j < matrixSize; j++) {
823  house_vec[j] = -beta * S.getValue(j, i);
824  }
825  if (S.getValue(i, i) < 0) {
826  for (unsigned j = i + 1; j < matrixSize; j++) {
827  house_vec[j] = -house_vec[j];
828  }
829  }
830  }
831 
832  for (int k = i; k < static_cast<int>(matrixSize); k++) {
833  Scalar dot_prod = 0;
834  for (unsigned j = i; j < matrixSize; j++) {
835  dot_prod += S.getValue(j, k) * house_vec[j];
836  }
837  for (unsigned j = i; j < matrixSize; j++) {
838  S.setValue(j, k,
839  S.getValue(j, k) - dot_prod * house_vec[j]);
840  }
841  }
842 
843  for (int k = 0; k < static_cast<int>(matrixSize); k++) {
844  Scalar dot_prod = 0;
845  for (unsigned j = i; j < matrixSize; j++) {
846  dot_prod += U.getValue(k, j) * house_vec[j];
847  }
848  for (unsigned j = i; j < matrixSize; j++) {
849  U.setValue(k, j,
850  U.getValue(k, j) - dot_prod * house_vec[j]);
851  }
852  }
853 
854  // Row Householder
855  if (i >= matrixSize - 1) continue;
856  {
857  Scalar x1 = S.getValue(i, i + 1);
858  if (x1 < 0) x1 = -x1;
859 
860  Scalar x_inv_norm = 0;
861  for (unsigned j = i + 1; j < matrixSize; j++) {
862  x_inv_norm += S.getValue(i, j) * S.getValue(i, j);
863  }
864  if (x_inv_norm > 0) x_inv_norm = 1 / sqrt(x_inv_norm);
865 
866  Scalar alpha = sqrt(1 + x1 * x_inv_norm);
867  Scalar beta = x_inv_norm / alpha;
868  if (x_inv_norm == 0) alpha = 0; // nothing to do
869 
870  house_vec[i + 1] = -alpha;
871  for (unsigned j = i + 2; j < matrixSize; j++) {
872  house_vec[j] = -beta * S.getValue(i, j);
873  }
874  if (S.getValue(i, i + 1) < 0) {
875  for (unsigned j = i + 2; j < matrixSize; j++) {
876  house_vec[j] = -house_vec[j];
877  }
878  }
879  }
880 
881  for (int k = i; k < static_cast<int>(matrixSize); k++) {
882  Scalar dot_prod = 0;
883  for (unsigned j = i + 1; j < matrixSize; j++) {
884  dot_prod += S.getValue(k, j) * house_vec[j];
885  }
886  for (unsigned j = i + 1; j < matrixSize; j++) {
887  S.setValue(k, j,
888  S.getValue(k, j) - dot_prod * house_vec[j]);
889  }
890  }
891 
892  for (int k = 0; k < static_cast<int>(matrixSize); k++) {
893  Scalar dot_prod = 0;
894  for (unsigned j = i + 1; j < matrixSize; j++) {
895  dot_prod += V.getValue(j, k) * house_vec[j];
896  }
897  for (unsigned j = i + 1; j < matrixSize; j++) {
898  V.setValue(j, k,
899  V.getValue(j, k) - dot_prod * house_vec[j]);
900  }
901  }
902  }
903  }
904 
905  const Scalar eps = std::numeric_limits<Scalar>::epsilon() * 64;
906 
907  // Diagonalization
908  for (unsigned k0 = 0; k0 < matrixSize - 1;) {
909  Scalar S_max = 0.0;
910  for (unsigned i = 0; i < matrixSize; i++)
911  S_max = (S_max > std::abs(S.getValue(i, i))
912  ? S_max
913  : std::abs(S.getValue(i, i)));
914 
915  for (unsigned i = 0; i < matrixSize - 1; i++)
916  S_max = (S_max > std::abs(S.getValue(i, i + 1))
917  ? S_max
918  : std::abs(S.getValue(i, i + 1)));
919 
920  while (k0 < matrixSize - 1 &&
921  std::abs(S.getValue(k0, k0 + 1)) <= eps * S_max)
922  k0++;
923 
924  if (k0 == matrixSize - 1) continue;
925 
926  unsigned n = k0 + 2;
927 
928  while (n < matrixSize &&
929  std::abs(S.getValue(n - 1, n)) > eps * S_max)
930  n++;
931 
932  // Compute mu
933  Scalar alpha = 0;
934  Scalar beta = 0;
935  if (n - k0 == 2 && std::abs(S.getValue(k0, k0)) < eps * S_max &&
936  std::abs(S.getValue(k0 + 1, k0 + 1)) < eps * S_max) {
937  alpha = 0;
938  beta = 1;
939  } else {
940  Scalar C[2][2];
941  C[0][0] = S.getValue(n - 2, n - 2) * S.getValue(n - 2, n - 2);
942  if (n - k0 > 2)
943  C[0][0] +=
944  S.getValue(n - 3, n - 2) * S.getValue(n - 3, n - 2);
945  C[0][1] = S.getValue(n - 2, n - 2) * S.getValue(n - 2, n - 1);
946  C[1][0] = S.getValue(n - 2, n - 2) * S.getValue(n - 2, n - 1);
947  C[1][1] = S.getValue(n - 1, n - 1) * S.getValue(n - 1, n - 1) +
948  S.getValue(n - 2, n - 1) * S.getValue(n - 2, n - 1);
949 
950  Scalar b = -(C[0][0] + C[1][1]) / 2;
951  Scalar c = C[0][0] * C[1][1] - C[0][1] * C[1][0];
952  Scalar d = 0;
953  if (b * b - c > 0) {
954  d = sqrt(b * b - c);
955  } else {
956  b = (C[0][0] - C[1][1]) / 2;
957  c = -C[0][1] * C[1][0];
958  if (b * b - c > 0) d = sqrt(b * b - c);
959  }
960 
961  Scalar lambda1 = -b + d;
962  Scalar lambda2 = -b - d;
963 
964  Scalar d1 = lambda1 - C[1][1];
965  d1 = (d1 < 0 ? -d1 : d1);
966  Scalar d2 = lambda2 - C[1][1];
967  d2 = (d2 < 0 ? -d2 : d2);
968  Scalar mu = (d1 < d2 ? lambda1 : lambda2);
969 
970  alpha = S.getValue(k0, k0) * S.getValue(k0, k0) - mu;
971  beta = S.getValue(k0, k0) * S.getValue(k0, k0 + 1);
972  }
973 
974  for (unsigned k = k0; k < n - 1; k++) {
975  GivensR(S, k, alpha, beta);
976  GivensL(V, k, alpha, beta);
977 
978  alpha = S.getValue(k, k);
979  beta = S.getValue(k + 1, k);
980  GivensL(S, k, alpha, beta);
981  GivensR(U, k, alpha, beta);
982 
983  alpha = S.getValue(k, k + 1);
984  beta = S.getValue(k, k + 2);
985  }
986 
987  // Make S bi-diagonal again
988  {
989  for (unsigned i0 = k0; i0 < n - 1; i0++) {
990  for (unsigned i1 = 0; i1 < matrixSize; i1++) {
991  if (i0 > i1 || i0 + 1 < i1) S.setValue(i0, i1, 0);
992  }
993  }
994  for (unsigned i0 = 0; i0 < matrixSize; i0++) {
995  for (unsigned i1 = k0; i1 < n - 1; i1++) {
996  if (i0 > i1 || i0 + 1 < i1) S.setValue(i0, i1, 0);
997  }
998  }
999  for (unsigned i = 0; i < matrixSize - 1; i++) {
1000  if (std::abs(S.getValue(i, i + 1)) <= eps * S_max) {
1001  S.setValue(i, i + 1, 0);
1002  }
1003  }
1004  }
1005  }
1006  }
1007 
1008 private: // members
1010  unsigned m_matrixSize;
1011 
1013  unsigned matrixSquareSize;
1014 
1016  Scalar* m_underlyingData = nullptr;
1017 };
1018 
1021 
1024 
1027 
1028 } // namespace cloudViewer
core::Tensor result
Definition: VtkUtils.cpp:76
Type u[3]
Definition: CVGeom.h:139
3D Vector (templated version)
Definition: CVGeom.h:223
const SquareMatrixTpl & operator+=(const SquareMatrixTpl &B)
In-place addition.
Definition: SquareMatrix.h:195
SquareMatrixTpl inv() const
Returns inverse (Gauss)
Definition: SquareMatrix.h:326
void toIdentity()
Sets matrix to identity.
Definition: SquareMatrix.h:452
void apply(const float vec[], double result[]) const
Multiplication by a float vector, outputs a double vector.
Definition: SquareMatrix.h:280
bool svd(SquareMatrixTpl &S, SquareMatrixTpl &U, SquareMatrixTpl &V) const
Definition: SquareMatrix.h:640
SquareMatrixTpl operator*(const SquareMatrixTpl &B) const
Multiplication (M = A*B)
Definition: SquareMatrix.h:225
SquareMatrixTpl(const SquareMatrixTpl< float > &mat)
Constructor from another float matrix.
Definition: SquareMatrix.h:51
Scalar ** m_values
The matrix rows.
Definition: SquareMatrix.h:157
Scalar trace() const
Returns trace.
Definition: SquareMatrix.h:465
SquareMatrixTpl(unsigned size)
Constructor with a given size.
Definition: SquareMatrix.h:35
void clear()
Sets all elements to 0.
Definition: SquareMatrix.h:319
SquareMatrixTpl(const float M16f[], bool rotationOnly=false)
"From OpenGl" constructor (float version)
Definition: SquareMatrix.h:66
SquareMatrixTpl & operator=(const Eigen::Matrix< Scalar, 3, 3 > &mat)
Assignment Function.
Definition: SquareMatrix.h:105
bool isValid() const
Returns matrix validity.
Definition: SquareMatrix.h:138
const SquareMatrixTpl & operator*=(const SquareMatrixTpl &B)
In-place multiplication.
Definition: SquareMatrix.h:255
SquareMatrixTpl(const double M16d[], bool rotationOnly=false)
"From OpenGl" constructor (double version)
Definition: SquareMatrix.h:83
SquareMatrixTpl & operator=(const SquareMatrixTpl &B)
Matrix copy operator.
Definition: SquareMatrix.h:173
void invalidate()
Invalidates matrix.
Definition: SquareMatrix.h:143
double computeDet() const
Returns determinant.
Definition: SquareMatrix.h:474
SquareMatrixTpl(const SquareMatrixTpl< double > &mat)
Constructor from another double matrix.
Definition: SquareMatrix.h:40
Vector3Tpl< Scalar > operator*(const Vector3Tpl< Scalar > &V) const
Multiplication by a vector.
Definition: SquareMatrix.h:243
SquareMatrixTpl transposed() const
Returns the transposed version of this matrix.
Definition: SquareMatrix.h:311
void initFromQuaternion(const float q[])
Creates a rotation matrix from a quaternion (float version)
Definition: SquareMatrix.h:480
SquareMatrixTpl(const Eigen::Matrix< Scalar, 4, 4 > &mat)
Definition: SquareMatrix.h:100
void apply(const double vec[], double result[]) const
Multiplication by a double vector.
Definition: SquareMatrix.h:294
unsigned size() const
Returns matrix size.
Definition: SquareMatrix.h:133
void print(FILE *fp=nullptr) const
Prints out matrix to console or file.
Definition: SquareMatrix.h:435
SquareMatrixTpl & operator=(const Eigen::Matrix< Scalar, 4, 4 > &mat)
Definition: SquareMatrix.h:114
SquareMatrixTpl operator-(const SquareMatrixTpl &B) const
Subtraction.
Definition: SquareMatrix.h:206
SquareMatrixTpl()
Default constructor.
Definition: SquareMatrix.h:30
void transpose()
In-place transpose.
Definition: SquareMatrix.h:304
void setValue(unsigned row, unsigned column, Scalar value)
Sets a particular matrix value.
Definition: SquareMatrix.h:163
SquareMatrixTpl operator+(const SquareMatrixTpl &B) const
Addition.
Definition: SquareMatrix.h:187
bool toQuaternion(double q[])
Converts rotation matrix to quaternion.
Definition: SquareMatrix.h:525
virtual ~SquareMatrixTpl()
Default destructor.
Definition: SquareMatrix.h:94
void scale(Scalar coef)
Scales matrix (all elements are multiplied by the same coef.)
Definition: SquareMatrix.h:459
void toGlMatrix(float M16f[]) const
Converts a 3*3 or 4*4 matrix to an OpenGL-style float matrix (float[16])
Definition: SquareMatrix.h:601
void apply(const float vec[], float result[]) const
Multiplication by a float vector, outputs a float vector.
Definition: SquareMatrix.h:266
SquareMatrixTpl(const Eigen::Matrix< Scalar, 3, 3 > &mat)
Copy Function.
Definition: SquareMatrix.h:97
const SquareMatrixTpl & operator-=(const SquareMatrixTpl &B)
In-place subtraction.
Definition: SquareMatrix.h:214
Scalar deltaDeterminant(unsigned column, Scalar *Vec) const
Returns Delta-determinant (see Kramer formula)
Definition: SquareMatrix.h:582
Scalar * row(unsigned index)
Returns pointer to matrix row.
Definition: SquareMatrix.h:160
void toGlMatrix(double M16d[]) const
Definition: SquareMatrix.h:620
void initFromQuaternion(const double q[])
Creates a rotation matrix from a quaternion (double version)
Definition: SquareMatrix.h:492
void toArray(Scalar data[])
Definition: SquareMatrix.h:123
Scalar getValue(unsigned row, unsigned column) const
Returns a particular matrix value.
Definition: SquareMatrix.h:168
__host__ __device__ int2 abs(int2 v)
Definition: cutil_math.h:1267
Generic file read and write utility for python interface.
void swap(cloudViewer::core::SmallVectorImpl< T > &LHS, cloudViewer::core::SmallVectorImpl< T > &RHS)
Implement std::swap in terms of SmallVector swap.
Definition: SmallVector.h:1370