KratosMultiphysics
KRATOS Multiphysics (Kratos) is a framework for building parallel, multi-disciplinary simulation software, aiming at modularity, extensibility, and high performance. Kratos is written in C++, and counts with an extensive Python interface.
svd_utils.h
Go to the documentation of this file.
1 // | / |
2 // ' / __| _` | __| _ \ __|
3 // . \ | ( | | ( |\__ `
4 // _|\_\_| \__,_|\__|\___/ ____/
5 // Multi-Physics
6 //
7 // License: BSD License
8 // Kratos default license: kratos/license.txt
9 //
10 // Main authors: Vicente Mataix Ferrandiz
11 //
12 
13 #if !defined(KRATOS_SVD_UTILS )
14 #define KRATOS_SVD_UTILS
15 
16 /* System includes */
17 
18 
19 /* External includes */
20 
21 /* Project includes */
22 #include "utilities/math_utils.h"
23 #include "spaces/ublas_space.h"
24 
25 namespace Kratos
26 {
29 
33 
37 
41 
45 
53 template<class TDataType>
54 class SVDUtils
55 {
56 public:
57 
60 
62  typedef Matrix MatrixType;
63 
65  typedef Vector VectorType;
66 
68  typedef std::size_t SizeType;
69 
71  typedef std::size_t IndexType;
72 
75 
77  constexpr static TDataType ZeroTolerance = std::numeric_limits<double>::epsilon();
78 
82 
86 
90 
103  static inline std::size_t SingularValueDecomposition(
104  const MatrixType& InputMatrix,
105  MatrixType& UMatrix,
106  MatrixType& SMatrix,
107  MatrixType& VMatrix,
108  Parameters ThisParameters)
109  {
110  // Validating defaults
111  Parameters default_parameters = Parameters(R"(
112  {
113  "type_svd" : "Jacobi",
114  "tolerance" : 0.0,
115  "max_iter" : 200
116  })");
117  default_parameters["tolerance"].SetDouble(std::numeric_limits<double>::epsilon());
118  ThisParameters.RecursivelyValidateAndAssignDefaults(default_parameters);
119 
120  const std::string& r_type_svd = ThisParameters["type_svd"].GetString();
121  const double tolerance = ThisParameters["tolerance"].GetDouble();
122  const double max_iter = ThisParameters["max_iter"].GetInt();
123  return SingularValueDecomposition(InputMatrix, UMatrix, SMatrix, VMatrix, r_type_svd, tolerance, max_iter);
124  }
125 
140  static inline std::size_t SingularValueDecomposition(
141  const MatrixType& InputMatrix,
142  MatrixType& UMatrix,
143  MatrixType& SMatrix,
144  MatrixType& VMatrix,
145  const std::string& TypeSVD = "Jacobi",
146  const TDataType Tolerance = std::numeric_limits<double>::epsilon(),
147  const IndexType MaxIter = 200)
148  {
149  if (TypeSVD == "Jacobi") {
150  return JacobiSingularValueDecomposition(InputMatrix, UMatrix, SMatrix, VMatrix, Tolerance, MaxIter);
151  } else {
152  KRATOS_ERROR << "SVD Type not implemented" << std::endl;
153  }
154  }
155 
170  static inline std::size_t JacobiSingularValueDecomposition(
171  const MatrixType& InputMatrix,
172  MatrixType& UMatrix,
173  MatrixType& SMatrix,
174  MatrixType& VMatrix,
175  const TDataType Tolerance = std::numeric_limits<double>::epsilon(),
176  const IndexType MaxIter = 200)
177  {
178  const SizeType m = InputMatrix.size1();
179  const SizeType n = InputMatrix.size2();
180  KRATOS_ERROR_IF(m != n) << "Current Jacobi implementation only works with square matrices. Use \'LinearSolversApplication\' decompositions instead." << std::endl;
181 
182  if(SMatrix.size1() != m || SMatrix.size2() != n) {
183  SMatrix.resize(m, n, false);
184  }
185  noalias(SMatrix) = InputMatrix;
186 
187  if(UMatrix.size1() != m || UMatrix.size2() != m) {
188  UMatrix.resize(m, m, false);
189  }
190  noalias(UMatrix) = IdentityMatrix(m);
191 
192  if(VMatrix.size1() != n || VMatrix.size2() != n) {
193  VMatrix.resize(n, n, false);
194  }
195  noalias(VMatrix) = IdentityMatrix(n);
196 
197  const TDataType relative_tolerance = Tolerance * LocalSpaceType::TwoNorm(InputMatrix);
198 
199  IndexType iter = 0;
200 
201  // We create the auxuliar matrices (for aliased operations)
202  MatrixType auxiliar_matrix_mn(m, n);
203  MatrixType auxiliar_matrix_m(m, m);
204  MatrixType auxiliar_matrix_n(n, n);
205 
206  // We compute Jacobi
207  while (LocalSpaceType::JacobiNorm(SMatrix) > relative_tolerance) {
208  for (IndexType i = 0; i < n; i++) {
209  for (IndexType j = i+1; j < n; j++) {
210  MatrixType j1(m, m);
211  MatrixType j2(n, n);
212 
213  Jacobi(j1, j2, SMatrix, m, n, i, j);
214 
215  const MatrixType aux_matrix = prod(SMatrix, j2);
216  noalias(SMatrix) = prod(j1, aux_matrix);
217  noalias(auxiliar_matrix_m) = prod(UMatrix, trans(j1));
218  noalias(UMatrix) = auxiliar_matrix_m;
219  noalias(auxiliar_matrix_n) = prod(trans(j2), VMatrix);
220  noalias(VMatrix) = auxiliar_matrix_n;
221  }
222 
223  for (IndexType j = n; j < m; j++) {
224  MatrixType j1(m, m);
225 
226  Jacobi(j1, SMatrix, m, i, j);
227 
228  noalias(auxiliar_matrix_mn) = prod(j1, SMatrix);
229  noalias(SMatrix) = auxiliar_matrix_mn;
230  noalias(auxiliar_matrix_m) = prod(UMatrix, trans(j1));
231  noalias(UMatrix) = auxiliar_matrix_m;
232  }
233  }
234 
235  ++iter;
236  if (iter > MaxIter) {
237  KRATOS_WARNING("JacobiSingularValueDecomposition") << "Maximum number of iterations " << MaxIter << " reached." << std::endl;
238  break;
239  }
240  }
241 
242  return iter;
243  }
244 
254  static inline void SingularValueDecomposition2x2(
255  const MatrixType& InputMatrix,
256  MatrixType& UMatrix,
257  MatrixType& SMatrix,
258  MatrixType& VMatrix
259  )
260  {
261  const TDataType t = (InputMatrix(0, 1) - InputMatrix(1, 0))/(InputMatrix(0, 0) + InputMatrix(1, 1));
262  const TDataType c = 1.0/std::sqrt(1.0 + t*t);
263  const TDataType s = t*c;
264  MatrixType r_matrix(2, 2);
265  r_matrix(0, 0) = c;
266  r_matrix(0, 1) = -s;
267  r_matrix(1, 0) = s;
268  r_matrix(1, 1) = c;
269 
270  MatrixType m_matrix = prod(r_matrix, InputMatrix);
271 
272  SingularValueDecomposition2x2Symmetric(m_matrix, UMatrix, SMatrix, VMatrix);
273 
274  MatrixType auxiliar_matrix_m(UMatrix.size1(), UMatrix.size2());
275  noalias(auxiliar_matrix_m) = prod(trans(r_matrix), UMatrix);
276  noalias(UMatrix) = auxiliar_matrix_m;
277  }
278 
289  const MatrixType& InputMatrix,
290  MatrixType& UMatrix,
291  MatrixType& SMatrix,
292  MatrixType& VMatrix
293  )
294  {
295  if(SMatrix.size1() != 2 || SMatrix.size2() != 2) {
296  SMatrix.resize(2 ,2, false);
297  }
298  if(UMatrix.size1() != 2 || UMatrix.size2() != 2) {
299  UMatrix.resize(2, 2, false);
300  }
301  if(VMatrix.size1() != 2 || VMatrix.size2() != 2) {
302  VMatrix.resize(2, 2, false);
303  }
304 
305  if (std::abs(InputMatrix(1, 0)) < ZeroTolerance) { // Already symmetric
306  noalias(SMatrix) = InputMatrix;
307  noalias(UMatrix) = IdentityMatrix(2);
308  noalias(VMatrix) = UMatrix;
309  } else {
310  const TDataType w = InputMatrix(0, 0);
311  const TDataType y = InputMatrix(1, 0);
312  const TDataType z = InputMatrix(1, 1);
313  const TDataType ro = (z - w)/(2.0 * y);
314  const TDataType t = MathUtils<TDataType>::Sign(ro)/(std::abs(ro) + std::sqrt(1 + ro * ro));
315  const TDataType c = 1.0/(std::sqrt(1.0 + t*t));
316  const TDataType s = t*c;
317 
318  UMatrix(0, 0) = c;
319  UMatrix(0, 1) = s;
320  UMatrix(1, 0) = -s;
321  UMatrix(1, 1) = c;
322  noalias(VMatrix) = trans(UMatrix);
323 
324  noalias(SMatrix) = prod(trans(UMatrix), MatrixType(prod(InputMatrix, trans(VMatrix))));
325  }
326 
327  MatrixType z_matrix(2, 2);
328  z_matrix(0, 0) = MathUtils<TDataType>::Sign(SMatrix(0, 0));
329  z_matrix(0, 1) = 0.0;
330  z_matrix(1, 0) = 0.0;
331  z_matrix(1, 1) = MathUtils<TDataType>::Sign(SMatrix(1, 1));
332 
333  // Auxiliar matrix for alias operations
334  MatrixType aux_2_2_matrix(2, 2);
335  noalias(aux_2_2_matrix) = prod(UMatrix, z_matrix);
336  noalias(UMatrix) = aux_2_2_matrix;
337  noalias(aux_2_2_matrix) = prod(z_matrix, SMatrix);
338  noalias(SMatrix) = aux_2_2_matrix;
339 
340  if (SMatrix(0, 0) < SMatrix(1, 1)) {
341  MatrixType p_matrix(2, 2);
342  p_matrix(0, 0) = 0.0;
343  p_matrix(0, 1) = 1.0;
344  p_matrix(1, 0) = 1.0;
345  p_matrix(1, 1) = 0.0;
346 
347  noalias(aux_2_2_matrix) = prod(UMatrix, p_matrix);
348  noalias(UMatrix) = aux_2_2_matrix;
349  const MatrixType aux_matrix = prod(SMatrix, p_matrix);
350  noalias(SMatrix) = prod(p_matrix, aux_matrix);
351  noalias(aux_2_2_matrix) = prod(p_matrix, VMatrix);
352  noalias(VMatrix) = aux_2_2_matrix;
353  }
354  }
355 
366  static inline void Jacobi(
367  MatrixType& J1,
368  MatrixType& J2,
369  const MatrixType& InputMatrix,
370  const SizeType& Size1,
371  const SizeType& Size2,
372  const SizeType& Index1,
373  const SizeType& Index2
374  )
375  {
376  MatrixType b_matrix(2,2);
377  b_matrix(0, 0) = InputMatrix(Index1, Index1);
378  b_matrix(0, 1) = InputMatrix(Index1, Index2);
379  b_matrix(1, 0) = InputMatrix(Index2, Index1);
380  b_matrix(1, 1) = InputMatrix(Index2, Index2);
381 
382  MatrixType u_matrix, s_matrix, v_matrix;
383 
384  SingularValueDecomposition2x2(b_matrix, u_matrix, s_matrix, v_matrix);
385 
386  J1 = IdentityMatrix(Size1);
387  J1(Index1, Index1) = u_matrix(0, 0);
388  J1(Index1, Index2) = u_matrix(1, 0);
389  J1(Index2, Index1) = u_matrix(0, 1);
390  J1(Index2, Index2) = u_matrix(1, 1);
391 
393  J2(Index1, Index1) = v_matrix(0, 0);
394  J2(Index1, Index2) = v_matrix(1, 0);
395  J2(Index2, Index1) = v_matrix(0, 1);
396  J2(Index2, Index2) = v_matrix(1, 1);
397  }
398 
408  static inline void Jacobi(
409  MatrixType& J1,
410  const MatrixType& InputMatrix,
411  const SizeType& Size1,
412  const SizeType& Index1,
413  const SizeType& Index2
414  )
415  {
416  MatrixType b_matrix(2,2);
417  b_matrix(0, 0) = InputMatrix(Index1, Index1);
418  b_matrix(0, 1) = 0.0;
419  b_matrix(1, 0) = InputMatrix(Index2, Index1);
420  b_matrix(1, 1) = 0.0;
421 
422  MatrixType u_matrix, s_matrix, v_matrix;
423 
424  SingularValueDecomposition2x2(b_matrix, u_matrix, s_matrix, v_matrix);
425 
427  J1(Index1, Index1) = u_matrix(0, 0);
428  J1(Index1, Index2) = u_matrix(1, 0);
429  J1(Index2, Index1) = u_matrix(0, 1);
430  J1(Index2, Index2) = u_matrix(1, 1);
431  }
432 
440  static inline TDataType SVDConditionNumber(
441  const MatrixType& InputMatrix,
442  const std::string TypeSVD = "Jacobi",
443  const TDataType Tolerance = std::numeric_limits<double>::epsilon(),
444  const IndexType MaxIter = 200)
445  {
446  MatrixType u_matrix, s_matrix, v_matrix;
447  SingularValueDecomposition(InputMatrix, u_matrix, s_matrix, v_matrix, TypeSVD, Tolerance, MaxIter);
448 
449  const SizeType size_s = s_matrix.size1();
450  const TDataType condition_number = s_matrix(0, 0)/s_matrix(size_s - 1, size_s - 1);
451 
452  return condition_number;
453  }
454 
458 
459 
463 
464 
468 
472 
473 private:
474 
477 
481 
485 
489 
493 
497 
501 
505 
506  SVDUtils(void);
507 
508  SVDUtils(SVDUtils& rSource);
509 
510 }; /* Class SVDUtils */
511 
514 
515 
519 
520 } /* namespace Kratos.*/
521 
522 #endif /* KRATOS_SVD_UTILS defined */
void resize(std::size_t NewSize1, std::size_t NewSize2, bool preserve=0)
Definition: amatrix_interface.h:224
static int Sign(const double &ThisDataType)
Sign function.
Definition: math_utils.h:1269
This class provides to Kratos a data structure for I/O based on the standard of JSON.
Definition: kratos_parameters.h:59
double GetDouble() const
This method returns the double contained in the current Parameter.
Definition: kratos_parameters.cpp:657
void SetDouble(const double Value)
This method sets the double contained in the current Parameter.
Definition: kratos_parameters.cpp:787
int GetInt() const
This method returns the integer contained in the current Parameter.
Definition: kratos_parameters.cpp:666
void RecursivelyValidateAndAssignDefaults(const Parameters &rDefaultParameters)
This function is designed to verify that the parameters under testing match the form prescribed by th...
Definition: kratos_parameters.cpp:1389
std::string GetString() const
This method returns the string contained in the current Parameter.
Definition: kratos_parameters.cpp:684
Various mathematical utilities to compute SVD and the condition number of a matrix.
Definition: svd_utils.h:55
static void Jacobi(MatrixType &J1, const MatrixType &InputMatrix, const SizeType &Size1, const SizeType &Index1, const SizeType &Index2)
This method computes the Jacobi rotation operation.
Definition: svd_utils.h:408
static TDataType SVDConditionNumber(const MatrixType &InputMatrix, const std::string TypeSVD="Jacobi", const TDataType Tolerance=std::numeric_limits< double >::epsilon(), const IndexType MaxIter=200)
This method computes the condition number using the SVD.
Definition: svd_utils.h:440
static std::size_t JacobiSingularValueDecomposition(const MatrixType &InputMatrix, MatrixType &UMatrix, MatrixType &SMatrix, MatrixType &VMatrix, const TDataType Tolerance=std::numeric_limits< double >::epsilon(), const IndexType MaxIter=200)
This function gives the Jacobi SVD of a given mxn matrix (m>=n), returns U,S; where A=U*S*V.
Definition: svd_utils.h:170
static void SingularValueDecomposition2x2(const MatrixType &InputMatrix, MatrixType &UMatrix, MatrixType &SMatrix, MatrixType &VMatrix)
This function gives the Jacobi SVD of a given 2x2 matrix, returns U,S; where A=U*S*V.
Definition: svd_utils.h:254
static void Jacobi(MatrixType &J1, MatrixType &J2, const MatrixType &InputMatrix, const SizeType &Size1, const SizeType &Size2, const SizeType &Index1, const SizeType &Index2)
This method computes the Jacobi rotation operation.
Definition: svd_utils.h:366
std::size_t SizeType
Definition of the size type.
Definition: svd_utils.h:68
Vector VectorType
Definition of the vector type.
Definition: svd_utils.h:65
UblasSpace< TDataType, Matrix, Vector > LocalSpaceType
Definition of local space.
Definition: svd_utils.h:74
static std::size_t SingularValueDecomposition(const MatrixType &InputMatrix, MatrixType &UMatrix, MatrixType &SMatrix, MatrixType &VMatrix, Parameters ThisParameters)
This function gives the SVD of a given mxn matrix (m>=n), returns U,S; where A=U*S*V.
Definition: svd_utils.h:103
Matrix MatrixType
Definition of the matrix type.
Definition: svd_utils.h:62
static void SingularValueDecomposition2x2Symmetric(const MatrixType &InputMatrix, MatrixType &UMatrix, MatrixType &SMatrix, MatrixType &VMatrix)
Definition: svd_utils.h:288
std::size_t IndexType
Definition of index type.
Definition: svd_utils.h:71
constexpr static TDataType ZeroTolerance
Definition of epsilon zero tolerance.
Definition: svd_utils.h:77
static std::size_t SingularValueDecomposition(const MatrixType &InputMatrix, MatrixType &UMatrix, MatrixType &SMatrix, MatrixType &VMatrix, const std::string &TypeSVD="Jacobi", const TDataType Tolerance=std::numeric_limits< double >::epsilon(), const IndexType MaxIter=200)
This function gives the SVD of a given mxn matrix (m>=n), returns U,S; where A=U*S*V.
Definition: svd_utils.h:140
A class template for handling data types, matrices, and vectors in a Ublas space.
Definition: ublas_space.h:121
static TDataType TwoNorm(VectorType const &rX)
||rX||2
Definition: ublas_space.h:278
static TDataType JacobiNorm(const Matrix &rA)
Definition: ublas_space.h:313
#define KRATOS_ERROR
Definition: exception.h:161
#define KRATOS_ERROR_IF(conditional)
Definition: exception.h:162
#define KRATOS_WARNING(label)
Definition: logger.h:265
z
Definition: GenerateWind.py:163
TSpaceType::IndexType Size1(TSpaceType &dummy, typename TSpaceType::MatrixType const &rM)
Definition: add_strategies_to_python.cpp:117
TSpaceType::IndexType Size2(TSpaceType &dummy, typename TSpaceType::MatrixType const &rM)
Definition: add_strategies_to_python.cpp:123
REF: G. R. Cowper, GAUSSIAN QUADRATURE FORMULAS FOR TRIANGLES.
Definition: mesh_condition.cpp:21
AMatrix::IdentityMatrix< double > IdentityMatrix
Definition: amatrix_interface.h:564
AMatrix::MatrixProductExpression< TExpression1Type, TExpression2Type > prod(AMatrix::MatrixExpression< TExpression1Type, TCategory1 > const &First, AMatrix::MatrixExpression< TExpression2Type, TCategory2 > const &Second)
Definition: amatrix_interface.h:568
T & noalias(T &TheMatrix)
Definition: amatrix_interface.h:484
AMatrix::TransposeMatrix< const T > trans(const T &TheMatrix)
Definition: amatrix_interface.h:486
y
Other simbols definition.
Definition: generate_axisymmetric_navier_stokes_element.py:54
w
Definition: generate_convection_diffusion_explicit_element.py:108
c
Definition: generate_weakly_compressible_navier_stokes_element.py:108
int max_iter
Definition: hinsberg_optimization.py:139
float J2
Definition: isotropic_damage_automatic_differentiation.py:133
int t
Definition: ode_solve.py:392
int n
manufactured solution and derivatives (u=0 at z=0 dudz=0 at z=domain_height)
Definition: ode_solve.py:402
int j
Definition: quadrature.py:648
int m
Definition: run_marine_rain_substepping.py:8
integer i
Definition: TensorModule.f:17