HOPS
HOPS class reference
MHO_LinearAlgebraUtilities.hh
Go to the documentation of this file.
1 #ifndef MHO_LinearAlgebraUtilities_HH__
2 #define MHO_LinearAlgebraUtilities_HH__
3 
4 #include <cmath>
5 #include <complex>
6 #include <cstddef>
7 #include <functional>
8 #include <limits>
9 #include <sstream>
10 #include <string>
11 #include <vector>
12 
13 #include "MHO_Message.hh"
14 
15 #define MHO_LINALG_PRINT_ERROR
16 
17 #define MHO_CHECK_ARRAY_OVERRUN
18 
19 namespace hops
20 {
21 
23 // Error Handling
25 
26 //error codes
27 enum class MHO_linalg_error
28 {
29  Success = 0,
30  DomainError, //1
31  Overflow, //2
32  Underflow, //3
34  DivideByZero, //5
35  FailedToConverge, //6
36  ArrayOverrun, //7
37  Unknown
38 };
39 
40 //make these globals thread local
42 thread_local std::string last_error_msg;
43 
44 //provide and optional callback method (defaults to null)
45 using MHO_linalg_error_handler = std::function< void(MHO_linalg_error, const std::string&) >;
46 thread_local MHO_linalg_error_handler error_handler = nullptr;
47 
48 inline void report_error(MHO_linalg_error code, const std::string& msg)
49 {
50  last_error = code;
52  if(error_handler)
53  {
54  error_handler(code, msg);
55  }
56 #ifdef MHO_LINALG_PRINT_ERROR
57  if(code != MHO_linalg_error::Success)
58  {
59  msg_warn("math", msg << eom);
60  }
61 #endif
62 }
63 
64 //query functions
66 {
67  return last_error;
68 }
69 
70 inline const std::string& get_last_error_message() noexcept
71 {
72  return last_error_msg;
73 }
74 
76 {
77  error_handler = std::move(handler);
78 }
79 
81 //vector class
83 
84 template< typename XValueType = double > class MHO_linalg_vector
85 {
86  public:
87  MHO_linalg_vector(): fSize(0), fData(){};
88 
89  MHO_linalg_vector(unsigned int sz): fSize(sz)
90  {
91 
92  fData.resize(fSize);
93  zero();
94  };
95 
96  MHO_linalg_vector(MHO_linalg_vector&& other) noexcept: fSize(other.fSize), fData(std::move(other.fData)) {}
97 
98  MHO_linalg_vector(const MHO_linalg_vector& copy) noexcept: fSize(copy.fSize), fData(copy.fData) {}
99 
100  //no virtual destructor, since we do not plan on inheritance
101  //virtual ~MHO_linalg_vector() {};
102 
103  unsigned int size() const { return fSize; };
104 
105  void resize(unsigned int sz)
106  {
107  if(sz == fSize)
108  {
109  return;
110  }
111  fSize = sz;
112  fData.resize(fSize);
113  }
114 
115  void zero() { std::fill(fData.begin(), fData.end(), 0.0); }
116 
117  // access (no safety checks)
118  XValueType& operator()(unsigned int i)
119  {
120 #ifndef MHO_CHECK_ARRAY_OVERRUN
121  return fData[i];
122 #else
123  if(i < fSize)
124  {
125  return fData[i];
126  }
127  else
128  {
129  std::stringstream ss;
130  ss << "MHO_linalg_vector::operator() error, out of range: " << i << " !< " << fSize;
132  return fDummy;
133  }
134 #endif
135  }
136 
137  const XValueType& operator()(unsigned int i) const
138  {
139 #ifndef MHO_CHECK_ARRAY_OVERRUN
140  return fData[i];
141 #else
142  if(i < fSize)
143  {
144  return fData[i];
145  }
146  else
147  {
148  std::stringstream ss;
149  ss << "MHO_linalg_vector::operator() error, out of range: " << i << " !< " << fSize;
151  return fDummy;
152  }
153 #endif
154  }
155 
156  // assignment
157  inline MHO_linalg_vector& operator=(const MHO_linalg_vector& other) noexcept
158  {
159  if(this != &other)
160  {
161  this->fData = other.fData;
162  }
163  return *this;
164  }
165 
166  //move assignment
168  {
169  if(this != &other)
170  {
171  fSize = other.fSize;
172  fData = std::move(other.fData);
173  }
174  return *this;
175  }
176 
178  {
179  if(this->fSize == other.size())
180  {
181  for(unsigned int i = 0; i < fSize; ++i)
182  {
183  this->fData[i] += other(i);
184  }
185  }
186  else
187  {
189  "MHO_linalg_vector::operator+= error, vectors have difference sizes.");
190  }
191  return *this;
192  }
193 
195  {
196  if(this->fSize == other.size())
197  {
198  for(unsigned int i = 0; i < fSize; ++i)
199  {
200  this->fData[i] -= other(i);
201  }
202  }
203  else
204  {
206  "MHO_linalg_vector::operator-= error, vectors have difference sizes.");
207  }
208  return *this;
209  }
210 
212  {
213  MHO_linalg_vector tmp = *this;
214  tmp += other;
215  return tmp;
216  }
217 
219  {
220  MHO_linalg_vector tmp = *this;
221  tmp -= other;
222  return tmp;
223  }
224 
225  //scale by a scalar constant
226  inline void scale(const XValueType& scale_factor)
227  {
228  for(unsigned int i = 0; i < fSize; ++i)
229  {
230  fData[i] *= scale_factor;
231  }
232  }
233 
234  inline XValueType inner_product(const MHO_linalg_vector& b) const
235  {
236  XValueType val = 0;
237  if(fSize == b.size())
238  {
239  for(unsigned int i = 0; i < fSize; i++)
240  {
241  val += fData[i] * b(i);
242  }
243  }
244  else
245  {
246  std::stringstream ss;
247  ss << "MHO_linalg_inner_product: error, vectors have different sizes: " << fSize << " != " << b.size() << "."
248  << "\n";
250  }
251  return val;
252  }
253 
254  inline XValueType norm() const
255  {
256  XValueType val = 0.0;
257  for(unsigned int i = 0; i < fSize; i++)
258  {
259  val += fData[i] * fData[i];
260  }
261  return std::sqrt(val);
262  }
263 
264  inline void normalize()
265  {
266  XValueType norm = this->norm();
267  if(norm != 0)
268  {
269  this->scale(1.0 / norm);
270  }
271  else
272  {
273  report_error(MHO_linalg_error::DivideByZero, "MHO_linalg_vector::normalize: error, vector has zero norm.");
274  }
275  }
276 
278  {
279  MHO_linalg_vector c(3);
280  if(b.size() == 3)
281  {
282  c(0) = fData[1] * b(2) - fData[2] * b(1);
283  c(1) = fData[2] * b(0) - fData[0] * b(2);
284  c(2) = fData[0] * b(1) - fData[1] * b(0);
285  }
286  else
287  {
289  "MHO_linalg_vector_cross_product: error, requires vectors of size 3");
290  }
291  return c;
292  }
293 
294  private:
295  unsigned int fSize;
296  std::vector< XValueType > fData;
297  XValueType fDummy;
298 };
299 
301 //matrix class
303 
304 template< typename XValueType = double > class MHO_linalg_matrix
305 {
306  public:
307  MHO_linalg_matrix(): fNRows(0), fNCols(0), fTotalSize(0), fData() {}
308 
309  MHO_linalg_matrix(unsigned int nrows, unsigned int ncols)
310  : fNRows(nrows), fNCols(ncols), fTotalSize(nrows * ncols), fData(nrows * ncols, 0.0)
311  {}
312 
313  //copy cons.
315  : fNRows(copy.fNRows), fNCols(copy.fNCols), fTotalSize(copy.fTotalSize), fData(copy.fData)
316  {}
317 
318  //move constructor
320  : fNRows(other.fNRows), fNCols(other.fNCols), fTotalSize(other.fTotalSize), fData(std::move(other.fData))
321  {
322  //reset the moved-from object
323  other.fNRows = 0;
324  other.fNCols = 0;
325  other.fTotalSize = 0;
326  }
327 
328  //no inheritance or virtual functions
329  //virtual ~MHO_linalg_matrix(){};
330 
331  void resize(unsigned int nrows, unsigned int ncols)
332  {
333  if(fTotalSize != nrows * ncols)
334  {
335  fData.resize(nrows * ncols);
336  }
337  fNRows = nrows;
338  fNCols = ncols;
339  fTotalSize = fNRows * fNCols;
340  }
341 
342  unsigned int n_rows() const { return fNRows; };
343 
344  unsigned int n_cols() const { return fNCols; };
345 
346  void zero()
347  {
348  for(unsigned int i = 0; i < fNRows * fNCols; i++)
349  {
350  fData[i] = 0.0;
351  }
352  }
353 
355  {
356  this->zero();
357  unsigned int min;
358  if(fNRows < fNCols)
359  {
360  min = fNRows;
361  }
362  else
363  {
364  min = fNCols;
365  }
366  for(unsigned int i = 0; i < min; i++)
367  {
368  (*this)(i, i) = 1.0;
369  }
370  }
371 
372  // access (no safety checks)
373  XValueType& operator()(unsigned int i, unsigned int j)
374  {
375 #ifndef MHO_CHECK_ARRAY_OVERRUN
376  return fData[i * fNCols + j];
377 #else
378  if(i < fNRows && j < fNCols)
379  {
380  return fData[i * fNCols + j];
381  }
382  else
383  {
384  std::stringstream ss;
385  ss << "MHO_linalg_matrix::operator() error, out of range, row: " << i << " !< " << fNRows << " or col: " << j
386  << " !< " << fNCols;
388  return fDummy;
389  }
390 #endif
391  }
392 
393  const XValueType& operator()(unsigned int i, unsigned int j) const
394  {
395 #ifndef MHO_CHECK_ARRAY_OVERRUN
396  return fData[i * fNCols + j];
397 #else
398  if(i < fNRows && j < fNCols)
399  {
400  return fData[i * fNCols + j];
401  }
402  else
403  {
404  std::stringstream ss;
405  ss << "MHO_linalg_matrix::operator() error, out of range, row: " << i << " !< " << fNRows << " or col: " << j
406  << " !< " << fNCols;
408  return fDummy;
409  }
410 #endif
411  }
412 
413  // assignment
415  {
416  if(this == &other)
417  {
418  return *this;
419  }
420  this->resize(other.fNRows, other.fNCols);
421  this->fData = other.fData;
422  return *this;
423  }
424 
425  //move assignment
427  {
428  if(this != &other)
429  {
430  this->fNRows = other.fNRows;
431  this->fNCols = other.fNCols;
432  this->fTotalSize = other.fTotalSize;
433  this->fData = std::move(other.fData);
434  }
435  //reset the moved-from object
436  other.fNRows = 0;
437  other.fNCols = 0;
438  other.fTotalSize = 0;
439  return *this;
440  }
441 
442  // math
444  {
445  if(this->fNRows == b.fNRows && this->fNCols == b.fNCols)
446  {
447  //same memory layout, so only a single 1D loop is needed
448  for(unsigned int i = 0; i < this->fTotalSize; ++i)
449  {
450  this->fData[i] += b.fData[i];
451  }
452  }
453  else
454  {
456  "MHO_linalg_matrix::operator+: error, matrices have difference sizes.");
457  }
458  return *this;
459  }
460 
462  {
463  if(this->fNRows == b.fNRows && this->fNCols == b.fNCols)
464  {
465  //same memory layout, so only a single 1D loop is needed
466  for(unsigned int i = 0; i < this->fTotalSize; ++i)
467  {
468  this->fData[i] -= b.fData[i];
469  }
470  }
471  else
472  {
474  "MHO_linalg_matrix::operator-: error, matrices have difference sizes.");
475  }
476  return *this;
477  }
478 
480  {
481  MHO_linalg_matrix tmp = *this;
482  tmp += other;
483  return tmp;
484  }
485 
487  {
488  MHO_linalg_matrix tmp = *this;
489  tmp -= other;
490  return tmp;
491  }
492 
493  //scale by a scalar constant
494  void scale(const XValueType& scale_factor)
495  {
496  for(unsigned int i = 0; i < this->fTotalSize; ++i)
497  {
498  this->fData[i] *= scale_factor;
499  }
500  }
501 
502  //Frobenius norm of matrix
503  XValueType frobenius_norm()
504  {
505  XValueType sum = 0;
506  for(unsigned int i = 0; i < fTotalSize; ++i)
507  {
508  sum += fData[i] * fData[i]; // TODO FIXME FOR COMPLEX DATA
509  }
510  return std::sqrt(sum);
511  }
512 
513  private:
514  unsigned int fNRows;
515  unsigned int fNCols;
516  unsigned int fTotalSize;
517  std::vector< XValueType > fData;
518  XValueType fDummy;
519 };
520 
522 //matrix-vector operations
524 
525 template< typename XValueType = double >
528 {
529  // check sizes
530  if((in.size() == m.n_cols()) && (out.size() == m.n_rows()))
531  {
532  XValueType elem;
533  for(unsigned int i = 0; i < m.n_rows(); i++)
534  {
535  elem = 0.0;
536  for(unsigned int j = 0; j < m.n_cols(); j++)
537  {
538  elem += m(i, j) * in(j);
539  }
540  out(i) = elem;
541  }
542  }
543  else
544  {
545  std::stringstream ss;
546  ss << "MHO_linalg_matrix_vector_product: error, matrix/vector sizes are mismatched."
547  << "\n";
548  ss << "matrix m is " << m.n_rows() << " by " << m.n_cols() << "."
549  << "\n";
550  ss << "input vector has size " << in.size() << "."
551  << "\n";
552  ss << "output vector has size " << out.size() << "."
553  << "\n";
555  }
556 }
557 
558 template< typename XValueType = double >
561 {
562  // check sizes
563  if((in.size() == m.n_rows()) && (out.size() == m.n_cols()))
564  {
565 
566  XValueType elem;
567  for(unsigned int i = 0; i < m.n_cols(); i++)
568  {
569  elem = 0.0;
570 
571  for(unsigned int j = 0; j < m.n_rows(); j++)
572  {
573  elem += m(j, i) * in(j);
574  }
575  out(i) = elem;
576  }
577  }
578  else
579  {
580  std::stringstream ss;
581  ss << "MHO_linalg_matrix_transpose_vector_product: error, matrix/vector sizes are mismatched."
582  << "\n";
583  ss << "transpose of matrix m is " << m.n_cols() << " by " << m.n_rows() << "."
584  << "\n";
585  ss << "input vector has size " << in.size() << "."
586  << "\n";
587  ss << "output vector has size " << out.size() << "."
588  << "\n";
590  }
591 }
592 
593 template< typename XValueType = double >
596 {
597  //resize if necessary
598  if((a.size() == p.n_rows()) && (b.size() == p.n_cols()))
599  {
600  p.resize(a.size(), b.size());
601  }
602 
603  for(unsigned int i = 0; i < p.n_rows(); i++)
604  {
605  for(unsigned int j = 0; j < p.n_cols(); j++)
606  {
607  p(i, j) = a(i) * b(j);
608  }
609  }
610 }
611 
613 //matrix-matrix operations
615 
616 //C = A x B
617 template< typename XValueType = double >
620 {
621  // check that sizes are valid
622  unsigned int a_row = A.n_rows();
623  unsigned int a_col = A.n_cols();
624 
625  unsigned int b_row = B.n_rows();
626  unsigned int b_col = B.n_cols();
627 
628  unsigned int c_row = C.n_rows();
629  unsigned int c_col = C.n_cols();
630 
631  if((a_col == b_row) && (c_row == a_row) && (c_col == b_col))
632  {
633  // perform super slow naive direct O(N^3) matrix multiplication
634  for(unsigned int i = 0; i < c_row; i++)
635  {
636  for(unsigned int j = 0; j < c_col; j++)
637  {
638  XValueType elem = 0.0;
639 
640  for(unsigned int offset = 0; offset < b_row; offset++)
641  {
642  elem += (A(i, offset)) * (B(offset, j));
643  }
644  C(i, j) = elem;
645  }
646  }
647  }
648  else
649  {
650  std::stringstream ss;
651  ss << "MHO_linalg_matrix_multiply: error, matrices have different sizes."
652  << "\n";
653  ss << "matrix a is " << A.n_rows() << " by " << A.n_cols() << "."
654  << "\n";
655  ss << "matrix b is " << B.n_rows() << " by " << B.n_cols() << "."
656  << "\n";
657  ss << "matrix c is " << C.n_rows() << " by " << C.n_cols() << "."
658  << "\n";
660  }
661 }
662 
663 //matrix multiply which constructs return matrix
664 template< typename XValueType = double >
667 {
669  C.resize(A.n_rows(), B.n_cols());
671  return C;
672 }
673 
674 template< typename XValueType = double >
675 void MHO_linalg_matrix_multiply_with_transpose(bool transposeA, bool transposeB, const MHO_linalg_matrix< XValueType >& A,
677 {
678  // check that sizes are valid
679  unsigned int a_row = A.n_rows();
680  unsigned int a_col = A.n_cols();
681 
682  if(transposeA)
683  {
684  unsigned int swap = a_col;
685  a_col = a_row;
686  a_row = swap;
687  }
688 
689  unsigned int b_row = B.n_rows();
690  unsigned int b_col = B.n_cols();
691 
692  if(transposeB)
693  {
694  unsigned int swap = b_col;
695  b_col = b_row;
696  b_row = swap;
697  }
698 
699  unsigned int c_row = C.n_rows();
700  unsigned int c_col = C.n_cols();
701 
702  unsigned int ai, aj, bi, bj;
703 
704  if((a_col == b_row) && (c_row == a_row) && (c_col == b_col))
705  {
706  // perform super slow naive direct O(N^3) matrix multiplication
707  for(unsigned int i = 0; i < c_row; i++)
708  {
709  for(unsigned int j = 0; j < c_col; j++)
710  {
711  XValueType elem = 0.0;
712 
713  for(unsigned int offset = 0; offset < b_row; offset++)
714  {
715  if(transposeA)
716  {
717  ai = offset;
718  aj = i;
719  }
720  else
721  {
722  ai = i;
723  aj = offset;
724  }
725 
726  if(transposeB)
727  {
728  bi = j;
729  bj = offset;
730  }
731  else
732  {
733  bi = offset;
734  bj = j;
735  }
736 
737  elem += (A(ai, aj)) * (B(bi, bj));
738  }
739 
740  C(i, j) = elem;
741  }
742  }
743  }
744  else
745  {
746  std::stringstream ss;
747  ss << "MHO_linalg_matrix_multiply_with_transpose: error, matrices have different sizes."
748  << "\n";
749  ss << "matrix a is " << A.n_rows() << " by " << A.n_cols() << "."
750  << "\n";
751  ss << "matrix b is " << B.n_rows() << " by " << B.n_cols() << "."
752  << "\n";
753  ss << "matrix c is " << C.n_rows() << " by " << C.n_cols() << "."
754  << "\n";
756  }
757 }
758 
759 //matrix multiply with transpose which constructs return matrix
760 template< typename XValueType = double >
764 {
766  unsigned int c_row = A.n_rows();
767  unsigned int c_col = B.n_cols();
768  if(transposeA)
769  {
770  c_row = A.n_cols();
771  }
772  if(transposeB)
773  {
774  c_col = B.n_rows();
775  }
776  C.resize(c_row, c_col);
777  MHO_linalg_matrix_multiply_with_transpose(transposeA, transposeB, A, B, C);
778  return C;
779 }
780 
781 template< typename XValueType = double >
784 {
785  // this function uses the slower but more accurate one-sided jacobi svd
786  // as defined in the paper:
787  // Jacobi's method is more accurate than QR by J. Demmel and K. Veselic
788  // SIAM. J. Matrix Anal. & Appl., 13(4), 1204-1245.
789  // www.netlib.org/lapack/lawnspdf/lawn15.pdf
790  // assume that A is n x m with n >= m (tall or square); fat matrices (m>n) are not supported
791  // then U is an n x m
792  // V is m x m
793  // S is length m
794 
795  unsigned int n = A.n_rows();
796  unsigned int m = A.n_cols();
797 
798  if(n < m)
799  {
800  std::stringstream ss;
801  ss << "MHO_linalg_matrix_svd: error, only tall (n_row >= m_cols) or square matrices supported."
802  << "\n";
803  ss << "matrix A is " << n << " by " << m << "."
804  << "\n";
806  }
807 
808  if(U.n_rows() != n || U.n_cols() != m)
809  {
810  std::stringstream ss;
811  ss << "MHO_linalg_matrix_svd: error, matrices A and U have different sizes, will resize U."
812  << "\n";
813  ss << "matrix A is " << n << " by " << m << "."
814  << "\n";
815  ss << "matrix U was " << U.n_rows() << " by " << U.n_cols() << "."
816  << "\n";
818  U.resize(n, m);
819  }
820 
821  if(V.n_rows() != m || V.n_cols() != m)
822  {
823  std::stringstream ss;
824  ss << "MHO_linalg_matrix_svd: error, matrix V has wrong size, will resize."
825  << "\n";
826  ss << "matrix V is " << V.n_rows() << " by " << V.n_cols() << "."
827  << "\n";
828  ss << "matrix V should be " << m << " by " << m << "."
829  << "\n";
831  V.resize(m, m);
832  }
833 
834  if(S.size() != m)
835  {
836  std::stringstream ss;
837  ss << "MHO_linalg_matrix_svd: error, vector S has wrong size, will resize"
838  << "\n";
839  ss << "vector S is length " << S.size() << "\n";
840  ss << "vector S should be length " << m << "."
841  << "\n";
843  S.resize(m);
844  }
845 
846  // copy A into U
847  U = A;
848  // set V to the identity
849  V.set_as_identity();
850  // put some limits on the number of iterations, this is completely arbitrary
851  int n_iter = 0;
852  int n_max_iter = 10 * m;
853  // scratch space
854  XValueType a, b, c, g1, g2, cs, sn, t, psi, sign;
855  // make a very rough empirical estimate of the appropriate tolerance
856  XValueType tol = 0;
857  for(unsigned int i = 0; i < n; i++)
858  {
859  for(unsigned int j = 0; j < m; j++)
860  {
861  g1 = U(i, j);
862  tol += g1 * g1;
863  }
864  }
865  tol = tol * n * m * std::numeric_limits< XValueType >::epsilon() * std::numeric_limits< XValueType >::epsilon();
866 
867  // convergence count
868  int count = 0;
869  do
870  {
871  count = 0;
872  // for all column pairs i < j < m
873  for(unsigned int i = 0; i < m - 1; i++)
874  {
875  for(unsigned int j = i + 1; j < m; j++)
876  {
877  // add to the convergence count
878  count++;
879  // compute the a,b,c submatrix
880  a = 0;
881  b = 0;
882  c = 0;
883  for(unsigned int k = 0; k < n; k++)
884  {
885  g1 = U(k, i);
886  g2 = U(k, j);
887  a += g1 * g1;
888  b += g2 * g2;
889  c += g1 * g2;
890  }
891  if((c * c) / (a * b) > tol)
892  {
893  // compute the sine/cosine of the Given's rotation
894  psi = (b - a) / (2.0 * c);
895  sign = 1.0;
896  if(psi < 0)
897  {
898  sign = -1.0;
899  }
900  t = (sign) / (std::fabs(psi) + std::sqrt(1.0 + psi * psi));
901  cs = 1.0 / std::sqrt(1.0 + t * t);
902  sn = cs * t;
903  // apply the rotation to U and V
904  for(unsigned int k = 0; k < n; k++)
905  {
906  // apply to U
907  g1 = U(k, i);
908  g2 = U(k, j);
909  U(k, i) = cs * g1 - sn * g2;
910  U(k, j) = sn * g1 + cs * g2;
911  }
912  for(unsigned int k = 0; k < m; k++)
913  {
914  // apply to V
915  g1 = V(k, i);
916  g2 = V(k, j);
917  V(k, i) = cs * g1 - sn * g2;
918  V(k, j) = sn * g1 + cs * g2;
919  }
920  }
921  else
922  {
923  // subtract from convergence count
924  count--;
925  }
926  }
927  }
928  n_iter++;
929  if(n_iter >= n_max_iter)
930  {
931  std::stringstream ss;
932  ss << "MHO_linalg_matrix_svd: error, SVD failed to converge within " << n_max_iter << " iterations, "
933  << "\n";
935  break;
936  }
937  }
938  while(count > 0);
939 
940  // now we compute the singular values, they are the norms of the columns of U
941  // we also compute the norm of all the singular values
942  XValueType norm_s = 0.0;
943  for(unsigned int i = 0; i < m; i++)
944  {
945  a = 0;
946  for(unsigned int j = 0; j < n; j++)
947  {
948  g1 = U(j, i);
949  a += g1 * g1;
950  }
951  norm_s += a;
952  a = std::sqrt(a);
953  S(i) = a;
954  }
955  norm_s = std::sqrt(norm_s);
956  tol = std::numeric_limits< XValueType >::epsilon() * norm_s;
957  // eliminate all those singular values which are below the tolerance
958  for(unsigned int i = 0; i < m; i++)
959  {
960  if(S(i) < tol)
961  {
962  S(i) = 0.0;
963  }
964  }
965  // now we fix U by post multiplying with the inverse of diag(S)
966  for(unsigned int i = 0; i < n; i++) // rows
967  {
968  for(unsigned int j = 0; j < m; j++) // cols
969  {
970  g1 = U(i, j);
971  g2 = S(j);
972  if(g2 == 0.0)
973  {
974  U(i, j) = 0.0; // set to zero
975  }
976  else
977  {
978  U(i, j) = g1 / g2;
979  }
980  }
981  }
982 }
983 
984 template< typename XValueType = double >
986 {
987 
988  if((in.n_rows() != out.n_cols()) || (in.n_cols() != out.n_rows()))
989  {
990  report_error(MHO_linalg_error::MismatchedDimension, "MHO_linalg_matrix_transpose: error, dimension mismatch.");
991  }
992 
993  unsigned int nrows = in.n_rows();
994  unsigned int ncols = in.n_cols();
995  XValueType temp;
996 
997  for(unsigned int row = 0; row < nrows; row++)
998  {
999  for(unsigned int col = 0; col < ncols; col++)
1000  {
1001  temp = in(row, col);
1002  out(col, row) = temp;
1003  }
1004  }
1005 }
1006 
1007 template< typename XValueType = double >
1011 {
1012  //the solution is given by:
1013  //x = [V*diag(S)^{-1}*U^{T}]b
1014  //workspace
1016  //first we apply U^T to b
1017  x.zero();
1018  work.zero();
1020  x = work;
1021 
1022  //now we apply the inverse of diag(S) to x
1023  //with the exception that if a singular value is zero, then we apply zero
1024  //we assume anything less than EPSILON*norm(S) to be essentially zero (singular values should all be positive)
1025  double s, elem;
1026  double norm_s = S.norm();
1027  for(unsigned int i = 0; i < S.size(); i++)
1028  {
1029  s = S(i);
1030  if(s > std::numeric_limits< XValueType >::epsilon() * norm_s)
1031  {
1032  //multiply 1/s against the i'th element of x
1033  elem = (1.0 / s) * x(i); //MHO_linalg_vector_get(x,i);
1034  x(i) = elem;
1035  }
1036  else
1037  {
1038  x(i) = 0; //truncate small s
1039  }
1040  }
1041 
1042  //finally we apply the matrix V to the vector x
1044  x = work;
1045 }
1046 
1047 template< typename XValueType = double > void MHO_linalg_matrix_print(const MHO_linalg_matrix< XValueType >& m)
1048 {
1049  for(unsigned int i = 0; i < m.n_rows(); i++) // rows
1050  {
1051  for(unsigned int j = 0; j < (m.n_cols() - 1); j++) // col
1052  {
1053  std::cout << m(i, j) << ", ";
1054  }
1055  std::cout << m(i, m.n_cols() - 1);
1056  std::cout << std::endl;
1057  }
1058 }
1059 
1060 template< typename XValueType = double > void MHO_linalg_vector_print(const MHO_linalg_vector< XValueType >& m)
1061 {
1062  for(unsigned int j = 0; j < m.size() - 1; j++)
1063  {
1064  std::cout << m(j) << ", ";
1065  }
1066  std::cout << m(m.size() - 1);
1067  std::cout << std::endl;
1068 }
1069 
1070 //build diagonal matrix from a vector
1072 {
1073  unsigned int n = s.size();
1075  D.zero();
1076  for(unsigned int i = 0; i < n; ++i)
1077  {
1078  D(i, i) = s(i);
1079  }
1080  return D;
1081 }
1082 
1083 //construct the transpose of a matrix
1084 template< typename XValueType >
1086 {
1088  for(unsigned int i = 0; i < A.n_rows(); ++i)
1089  {
1090  for(unsigned int j = 0; j < A.n_cols(); ++j)
1091  {
1092  AT(j, i) = A(i, j);
1093  }
1094  }
1095  return AT;
1096 }
1097 
1098 } // namespace hops
1099 
1100 #endif
#define msg_warn(xKEY, xCONTENT)
Definition: MHO_Message.hh:248
#define V
Definition: adump.h:36
#define U
Definition: adump.h:35
Definition: MHO_LinearAlgebraUtilities.hh:305
MHO_linalg_matrix & operator=(const MHO_linalg_matrix &other)
Definition: MHO_LinearAlgebraUtilities.hh:414
unsigned int n_cols() const
Definition: MHO_LinearAlgebraUtilities.hh:344
XValueType & operator()(unsigned int i, unsigned int j)
Definition: MHO_LinearAlgebraUtilities.hh:373
void zero()
Definition: MHO_LinearAlgebraUtilities.hh:346
MHO_linalg_matrix()
Definition: MHO_LinearAlgebraUtilities.hh:307
void resize(unsigned int nrows, unsigned int ncols)
Definition: MHO_LinearAlgebraUtilities.hh:331
const XValueType & operator()(unsigned int i, unsigned int j) const
Definition: MHO_LinearAlgebraUtilities.hh:393
MHO_linalg_matrix & operator+=(const MHO_linalg_matrix &b)
Definition: MHO_LinearAlgebraUtilities.hh:443
MHO_linalg_matrix & operator=(MHO_linalg_matrix &&other) noexcept
Definition: MHO_LinearAlgebraUtilities.hh:426
MHO_linalg_matrix operator-(const MHO_linalg_matrix &other)
Definition: MHO_LinearAlgebraUtilities.hh:486
void set_as_identity()
Definition: MHO_LinearAlgebraUtilities.hh:354
XValueType frobenius_norm()
Definition: MHO_LinearAlgebraUtilities.hh:503
unsigned int n_rows() const
Definition: MHO_LinearAlgebraUtilities.hh:342
MHO_linalg_matrix(MHO_linalg_matrix &&other)
Definition: MHO_LinearAlgebraUtilities.hh:319
MHO_linalg_matrix(unsigned int nrows, unsigned int ncols)
Definition: MHO_LinearAlgebraUtilities.hh:309
MHO_linalg_matrix(const MHO_linalg_matrix &copy)
Definition: MHO_LinearAlgebraUtilities.hh:314
MHO_linalg_matrix operator+(const MHO_linalg_matrix &other)
Definition: MHO_LinearAlgebraUtilities.hh:479
void scale(const XValueType &scale_factor)
Definition: MHO_LinearAlgebraUtilities.hh:494
MHO_linalg_matrix & operator-=(const MHO_linalg_matrix &b)
Definition: MHO_LinearAlgebraUtilities.hh:461
Definition: MHO_LinearAlgebraUtilities.hh:85
MHO_linalg_vector(unsigned int sz)
Definition: MHO_LinearAlgebraUtilities.hh:89
MHO_linalg_vector(MHO_linalg_vector &&other) noexcept
Definition: MHO_LinearAlgebraUtilities.hh:96
MHO_linalg_vector()
Definition: MHO_LinearAlgebraUtilities.hh:87
MHO_linalg_vector operator-(const MHO_linalg_vector &other)
Definition: MHO_LinearAlgebraUtilities.hh:218
XValueType norm() const
Definition: MHO_LinearAlgebraUtilities.hh:254
XValueType inner_product(const MHO_linalg_vector &b) const
Definition: MHO_LinearAlgebraUtilities.hh:234
MHO_linalg_vector & operator=(const MHO_linalg_vector &other) noexcept
Definition: MHO_LinearAlgebraUtilities.hh:157
MHO_linalg_vector cross_product(const MHO_linalg_vector &b)
Definition: MHO_LinearAlgebraUtilities.hh:277
void zero()
Definition: MHO_LinearAlgebraUtilities.hh:115
unsigned int size() const
Definition: MHO_LinearAlgebraUtilities.hh:103
MHO_linalg_vector operator+(const MHO_linalg_vector &other)
Definition: MHO_LinearAlgebraUtilities.hh:211
XValueType & operator()(unsigned int i)
Definition: MHO_LinearAlgebraUtilities.hh:118
MHO_linalg_vector & operator+=(const MHO_linalg_vector &other)
Definition: MHO_LinearAlgebraUtilities.hh:177
const XValueType & operator()(unsigned int i) const
Definition: MHO_LinearAlgebraUtilities.hh:137
void normalize()
Definition: MHO_LinearAlgebraUtilities.hh:264
MHO_linalg_vector & operator=(MHO_linalg_vector &&other) noexcept
Definition: MHO_LinearAlgebraUtilities.hh:167
void resize(unsigned int sz)
Definition: MHO_LinearAlgebraUtilities.hh:105
void scale(const XValueType &scale_factor)
Definition: MHO_LinearAlgebraUtilities.hh:226
MHO_linalg_vector & operator-=(const MHO_linalg_vector &other)
Definition: MHO_LinearAlgebraUtilities.hh:194
MHO_linalg_vector(const MHO_linalg_vector &copy) noexcept
Definition: MHO_LinearAlgebraUtilities.hh:98
#define min(a, b)
Definition: max555.c:9
void msg(const char *string, int level,...)
Definition: msg.c:25
t
Definition: picking_aedit.py:14
Definition: MHO_AdhocFlagging.hh:18
void report_error(MHO_linalg_error code, const std::string &msg)
Definition: MHO_LinearAlgebraUtilities.hh:48
MHO_linalg_error get_last_error() noexcept
Definition: MHO_LinearAlgebraUtilities.hh:65
void set_error_handler(MHO_linalg_error_handler handler)
Definition: MHO_LinearAlgebraUtilities.hh:75
void MHO_linalg_matrix_svd(const MHO_linalg_matrix< XValueType > &A, MHO_linalg_matrix< XValueType > &U, MHO_linalg_vector< XValueType > &S, MHO_linalg_matrix< XValueType > &V)
Definition: MHO_LinearAlgebraUtilities.hh:782
void MHO_linalg_matrix_multiply_with_transpose(bool transposeA, bool transposeB, const MHO_linalg_matrix< XValueType > &A, const MHO_linalg_matrix< XValueType > &B, MHO_linalg_matrix< XValueType > &C)
Definition: MHO_LinearAlgebraUtilities.hh:675
void MHO_linalg_matrix_transpose(const MHO_linalg_matrix< XValueType > &in, MHO_linalg_matrix< XValueType > &out)
Definition: MHO_LinearAlgebraUtilities.hh:985
void MHO_linalg_matrix_print(const MHO_linalg_matrix< XValueType > &m)
Definition: MHO_LinearAlgebraUtilities.hh:1047
thread_local MHO_linalg_error_handler error_handler
Definition: MHO_LinearAlgebraUtilities.hh:46
MHO_linalg_matrix< XValueType > MHO_linalg_diag_matrix(const MHO_linalg_vector< XValueType > &s)
Definition: MHO_LinearAlgebraUtilities.hh:1071
void MHO_linalg_vector_outer_product(const MHO_linalg_vector< XValueType > &a, const MHO_linalg_vector< XValueType > &b, MHO_linalg_matrix< XValueType > &p)
Definition: MHO_LinearAlgebraUtilities.hh:594
MHO_linalg_matrix< XValueType > MHO_linalg_transpose_matrix(const MHO_linalg_matrix< XValueType > &A)
Definition: MHO_LinearAlgebraUtilities.hh:1085
void MHO_linalg_vector_print(const MHO_linalg_vector< XValueType > &m)
Definition: MHO_LinearAlgebraUtilities.hh:1060
void MHO_linalg_matrix_vector_product(const MHO_linalg_matrix< XValueType > &m, const MHO_linalg_vector< XValueType > &in, MHO_linalg_vector< XValueType > &out)
Definition: MHO_LinearAlgebraUtilities.hh:526
std::function< void(MHO_linalg_error, const std::string &) > MHO_linalg_error_handler
Definition: MHO_LinearAlgebraUtilities.hh:45
void MHO_linalg_matrix_multiply(const MHO_linalg_matrix< XValueType > &A, const MHO_linalg_matrix< XValueType > &B, MHO_linalg_matrix< XValueType > &C)
Definition: MHO_LinearAlgebraUtilities.hh:618
thread_local MHO_linalg_error last_error
Definition: MHO_LinearAlgebraUtilities.hh:41
thread_local std::string last_error_msg
Definition: MHO_LinearAlgebraUtilities.hh:42
const std::string & get_last_error_message() noexcept
Definition: MHO_LinearAlgebraUtilities.hh:70
void MHO_linalg_matrix_svd_solve(const MHO_linalg_matrix< XValueType > &U, const MHO_linalg_vector< XValueType > &S, const MHO_linalg_matrix< XValueType > &V, const MHO_linalg_vector< XValueType > &b, MHO_linalg_vector< XValueType > &x)
Definition: MHO_LinearAlgebraUtilities.hh:1008
void MHO_linalg_matrix_transpose_vector_product(const MHO_linalg_matrix< XValueType > &m, const MHO_linalg_vector< XValueType > &in, MHO_linalg_vector< XValueType > &out)
Definition: MHO_LinearAlgebraUtilities.hh:559
MHO_linalg_error
Definition: MHO_LinearAlgebraUtilities.hh:28