LvArray
fixedSizeSquareMatrixOpsImpl.hpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2021, Lawrence Livermore National Security, LLC and LvArray contributors.
3  * All rights reserved.
4  * See the LICENSE file for details.
5  * SPDX-License-Identifier: (BSD-3-Clause)
6  */
7 
13 #pragma once
14 
15 #include "genericTensorOps.hpp"
16 
17 namespace LvArray
18 {
19 namespace tensorOps
20 {
21 namespace internal
22 {
23 
36 template< std::ptrdiff_t M, typename FloatingPoint >
38 static void shiftAndScale( FloatingPoint (& matrix)[ ( M * ( M + 1 ) ) / 2 ],
39  FloatingPoint & shift,
40  FloatingPoint & maxEntryAfterShift )
41 {
42  // Compute the average eigenvalue.
43  shift = symTrace< M >( matrix ) / FloatingPoint( M );
44 
45  // Initialize the floating point copy of the matrix and shift the average eigenvalue to 0.
46  symAddIdentity< M >( matrix, -shift );
47 
48  // Now scale the entires of the copy to between [-1, 1].
49  maxEntryAfterShift = maxAbsoluteEntry< SYM_SIZE< M > >( matrix );
50  if( maxEntryAfterShift > 0 )
51  {
52  scale< SYM_SIZE< M > >( matrix, 1 / maxEntryAfterShift );
53  }
54 
55  // A second shift is necessary because of floating point round off and because the eigenvalue
56  // algorithm expects the trace of the matrix to be zero. However it isn't necessary to export
57  // this shift since when calculating the eigenvalues of the original matrix it will be lost
58  // to roundoff.
59  FloatingPoint const secondShift = symTrace< M >( matrix ) / FloatingPoint( M );
60  symAddIdentity< M >( matrix, -secondShift );
61 }
62 
70 template< std::ptrdiff_t M >
72 {};
73 
78 template<>
79 struct SquareMatrixOps< 2 >
80 {
86  template< typename MATRIX >
88  static auto determinant( MATRIX const & matrix )
89  {
90  checkSizes< 2, 2 >( matrix );
91  return matrix[ 0 ][ 0 ] * matrix[ 1 ][ 1 ] - matrix[ 0 ][ 1 ] * matrix[ 1 ][ 0 ];
92  }
93 
103  template< typename DST_MATRIX, typename SRC_MATRIX >
105  static auto invert( DST_MATRIX && LVARRAY_RESTRICT_REF dstMatrix,
106  SRC_MATRIX const & LVARRAY_RESTRICT_REF srcMatrix )
107  {
108  checkSizes< 2, 2 >( dstMatrix );
109  checkSizes< 2, 2 >( srcMatrix );
110 
111  using FloatingPoint = std::decay_t< decltype( dstMatrix[ 0 ][ 0 ] ) >;
112 
113  auto const det = determinant( srcMatrix );
114  FloatingPoint const invDet = FloatingPoint( 1 ) / det;
115 
116  dstMatrix[ 0 ][ 0 ] = srcMatrix[ 1 ][ 1 ] * invDet;
117  dstMatrix[ 1 ][ 1 ] = srcMatrix[ 0 ][ 0 ] * invDet;
118  dstMatrix[ 0 ][ 1 ] = srcMatrix[ 0 ][ 1 ] * -invDet;
119  dstMatrix[ 1 ][ 0 ] = srcMatrix[ 1 ][ 0 ] * -invDet;
120 
121  return det;
122  }
123 
131  template< typename MATRIX >
133  static auto invert( MATRIX && matrix )
134  {
135  checkSizes< 2, 2 >( matrix );
136 
137  auto const det = determinant( matrix );
138  auto const invDet = 1 / det;
139 
140  auto const temp = matrix[ 0 ][ 0 ];
141  matrix[ 0 ][ 0 ] = matrix[ 1 ][ 1 ] * invDet;
142  matrix[ 1 ][ 1 ] = temp * invDet;
143  matrix[ 0 ][ 1 ] *= -invDet;
144  matrix[ 1 ][ 0 ] *= -invDet;
145 
146  return det;
147  }
148 
154  template< typename SYM_MATRIX >
156  static auto symDeterminant( SYM_MATRIX const & symMatrix )
157  {
158  checkSizes< 3 >( symMatrix );
159  return symMatrix[ 0 ] * symMatrix[ 1 ] - symMatrix[ 2 ] * symMatrix[ 2 ];
160  }
161 
171  template< typename DST_SYM_MATRIX, typename SRC_SYM_MATRIX >
173  static auto symInvert( DST_SYM_MATRIX && LVARRAY_RESTRICT_REF dstSymMatrix,
174  SRC_SYM_MATRIX const & LVARRAY_RESTRICT_REF srcSymMatrix )
175  {
176  checkSizes< 3 >( dstSymMatrix );
177  checkSizes< 3 >( srcSymMatrix );
178 
179  using FloatingPoint = std::decay_t< decltype( dstSymMatrix[ 0 ] ) >;
180 
181  auto const det = symDeterminant( srcSymMatrix );
182  FloatingPoint const invDet = FloatingPoint( 1 ) / det;
183 
184  dstSymMatrix[ 0 ] = srcSymMatrix[ 1 ] * invDet;
185  dstSymMatrix[ 1 ] = srcSymMatrix[ 0 ] * invDet;
186  dstSymMatrix[ 2 ] = srcSymMatrix[ 2 ] * -invDet;
187 
188  return det;
189  }
190 
198  template< typename SYM_MATRIX >
200  static auto symInvert( SYM_MATRIX && symMatrix )
201  {
202  checkSizes< 3 >( symMatrix );
203 
204  auto const det = symDeterminant( symMatrix );
205  auto const invDet = 1 / det;
206 
207  auto const temp = symMatrix[ 0 ];
208  symMatrix[ 0 ] = symMatrix[ 1 ] * invDet;
209  symMatrix[ 1 ] = temp * invDet;
210  symMatrix[ 2 ] *= -invDet;
211 
212  return det;
213  }
214 
226  template< typename DST_VECTOR, typename SYM_MATRIX_A, typename VECTOR_B >
228  static void Ri_eq_symAijBj( DST_VECTOR && LVARRAY_RESTRICT_REF dstVector,
229  SYM_MATRIX_A const & LVARRAY_RESTRICT_REF symMatrixA,
230  VECTOR_B const & LVARRAY_RESTRICT_REF vectorB )
231  {
232  checkSizes< 2 >( dstVector );
233  checkSizes< 3 >( symMatrixA );
234  checkSizes< 2 >( vectorB );
235 
236  dstVector[ 0 ] = symMatrixA[ 0 ] * vectorB[ 0 ] + symMatrixA[ 2 ] * vectorB[ 1 ];
237  dstVector[ 1 ] = symMatrixA[ 2 ] * vectorB[ 0 ] + symMatrixA[ 1 ] * vectorB[ 1 ];
238  }
239 
250  template< typename DST_VECTOR, typename SYM_MATRIX_A, typename VECTOR_B >
252  static void Ri_add_symAijBj( DST_VECTOR && LVARRAY_RESTRICT_REF dstVector,
253  SYM_MATRIX_A const & LVARRAY_RESTRICT_REF symMatrixA,
254  VECTOR_B const & LVARRAY_RESTRICT_REF vectorB )
255  {
256  checkSizes< 2 >( dstVector );
257  checkSizes< 3 >( symMatrixA );
258  checkSizes< 2 >( vectorB );
259 
260  dstVector[ 0 ] = dstVector[ 0 ] + symMatrixA[ 0 ] * vectorB[ 0 ] + symMatrixA[ 2 ] * vectorB[ 1 ];
261  dstVector[ 1 ] = dstVector[ 1 ] + symMatrixA[ 2 ] * vectorB[ 0 ] + symMatrixA[ 1 ] * vectorB[ 1 ];
262  }
263 
275  template< typename DST_MATRIX, typename SYM_MATRIX_A, typename MATRIX_B >
277  static void Rij_eq_symAikBjk( DST_MATRIX && LVARRAY_RESTRICT_REF dstMatrix,
278  SYM_MATRIX_A const & LVARRAY_RESTRICT_REF symMatrixA,
279  MATRIX_B const & LVARRAY_RESTRICT_REF matrixB )
280  {
281  checkSizes< 2, 2 >( dstMatrix );
282  checkSizes< 3 >( symMatrixA );
283  checkSizes< 2, 2 >( matrixB );
284 
285  dstMatrix[ 0 ][ 0 ] = symMatrixA[ 0 ] * matrixB[ 0 ][ 0 ] + symMatrixA[ 2 ] * matrixB[ 0 ][ 1 ];
286  dstMatrix[ 0 ][ 1 ] = symMatrixA[ 0 ] * matrixB[ 1 ][ 0 ] + symMatrixA[ 2 ] * matrixB[ 1 ][ 1 ];
287 
288  dstMatrix[ 1 ][ 0 ] = symMatrixA[ 2 ] * matrixB[ 0 ][ 0 ] + symMatrixA[ 1 ] * matrixB[ 0 ][ 1 ];
289  dstMatrix[ 1 ][ 1 ] = symMatrixA[ 2 ] * matrixB[ 1 ][ 0 ] + symMatrixA[ 1 ] * matrixB[ 1 ][ 1 ];
290  }
291 
305  template< typename DST_SYM_MATRIX, typename MATRIX_A, typename SYM_MATRIX_B >
307  static void Rij_eq_AikSymBklAjl( DST_SYM_MATRIX && LVARRAY_RESTRICT_REF dstSymMatrix,
308  MATRIX_A const & LVARRAY_RESTRICT_REF matrixA,
309  SYM_MATRIX_B const & LVARRAY_RESTRICT_REF symMatrixB )
310  {
311  checkSizes< 3 >( dstSymMatrix );
312  checkSizes< 2, 2 >( matrixA );
313  checkSizes< 3 >( symMatrixB );
314 
315  // Calculate entry (0, 0).
316  dstSymMatrix[ 0 ] = matrixA[ 0 ][ 0 ] * symMatrixB[ 0 ] * matrixA[ 0 ][ 0 ] +
317  matrixA[ 0 ][ 0 ] * symMatrixB[ 2 ] * matrixA[ 0 ][ 1 ] +
318  matrixA[ 0 ][ 1 ] * symMatrixB[ 2 ] * matrixA[ 0 ][ 0 ] +
319  matrixA[ 0 ][ 1 ] * symMatrixB[ 1 ] * matrixA[ 0 ][ 1 ];
320 
321  // Calculate entry (1, 1).
322  dstSymMatrix[ 1 ] = matrixA[ 1 ][ 0 ] * symMatrixB[ 0 ] * matrixA[ 1 ][ 0 ] +
323  matrixA[ 1 ][ 0 ] * symMatrixB[ 2 ] * matrixA[ 1 ][ 1 ] +
324  matrixA[ 1 ][ 1 ] * symMatrixB[ 2 ] * matrixA[ 1 ][ 0 ] +
325  matrixA[ 1 ][ 1 ] * symMatrixB[ 1 ] * matrixA[ 1 ][ 1 ];
326 
327  // Calculate entry (1, 0) or (0, 1).
328  dstSymMatrix[ 2 ] = matrixA[ 1 ][ 0 ] * symMatrixB[ 0 ] * matrixA[ 0 ][ 0 ] +
329  matrixA[ 1 ][ 0 ] * symMatrixB[ 2 ] * matrixA[ 0 ][ 1 ] +
330  matrixA[ 1 ][ 1 ] * symMatrixB[ 2 ] * matrixA[ 0 ][ 0 ] +
331  matrixA[ 1 ][ 1 ] * symMatrixB[ 1 ] * matrixA[ 0 ][ 1 ];
332  }
333 
334 
344  template< typename DST_MATRIX, typename VECTOR_A >
346  static void symRij_eq_AiAj( DST_MATRIX && LVARRAY_RESTRICT_REF dstMatrix,
347  VECTOR_A const & LVARRAY_RESTRICT_REF vectorA )
348  {
349  internal::checkSizes< 3 >( dstMatrix );
350  internal::checkSizes< 2 >( vectorA );
351 
352  dstMatrix[ 0 ] = vectorA[ 0 ] * vectorA[ 0 ];
353  dstMatrix[ 1 ] = vectorA[ 1 ] * vectorA[ 1 ];
354  dstMatrix[ 2 ] = vectorA[ 0 ] * vectorA[ 1 ];
355  }
356 
368  template< typename DST_SYM_MATRIX, typename VECTOR_A, typename VECTOR_B >
370  static void symRij_eq_AiBj_plus_AjBi( DST_SYM_MATRIX && LVARRAY_RESTRICT_REF dstMatrix,
371  VECTOR_A const & LVARRAY_RESTRICT_REF vectorA,
372  VECTOR_B const & LVARRAY_RESTRICT_REF vectorB )
373  {
374  internal::checkSizes< 3 >( dstMatrix );
375  internal::checkSizes< 2 >( vectorA );
376  internal::checkSizes< 2 >( vectorB );
377 
378  dstMatrix[ 0 ] = 2 * vectorA[ 0 ] * vectorB[ 0 ];
379  dstMatrix[ 1 ] = 2 * vectorA[ 1 ] * vectorB[ 1 ];
380  dstMatrix[ 2 ] = vectorA[ 0 ] * vectorB[ 1 ] + vectorA[ 1 ] * vectorB[ 0 ];
381  }
382 
392  template< typename DST_VECTOR, typename SYM_MATRIX >
394  static void symEigenvalues( DST_VECTOR && LVARRAY_RESTRICT_REF eigenvalues,
395  SYM_MATRIX const & LVARRAY_RESTRICT_REF symMatrix )
396  {
397  checkSizes< 2 >( eigenvalues );
398  checkSizes< 3 >( symMatrix );
399 
400  using FloatingPoint = std::decay_t< decltype( eigenvalues[ 0 ] ) >;
401 
402  // Shift the and scale the matrix
403  FloatingPoint shift, maxEntryAfterShift;
404  FloatingPoint fpCopy[ 3 ];
405  copy< 3 >( fpCopy, symMatrix );
406  shiftAndScale< 2 >( fpCopy, shift, maxEntryAfterShift );
407 
408  // Compute the eigenvalues of the shifted matrix.
409  eigenvaluesOfShiftedMatrix( eigenvalues, fpCopy );
410 
411  // Rescale the eigenvalues.
412  eigenvalues[ 0 ] = eigenvalues[ 0 ] * maxEntryAfterShift + shift;
413  eigenvalues[ 1 ] = eigenvalues[ 1 ] * maxEntryAfterShift + shift;
414  }
415 
429  template< typename DST_VECTOR, typename DST_MATRIX, typename SYM_MATRIX >
431  static void symEigenvectors( DST_VECTOR && LVARRAY_RESTRICT_REF eigenvalues,
432  DST_MATRIX && LVARRAY_RESTRICT_REF eigenvectors,
433  SYM_MATRIX const & LVARRAY_RESTRICT_REF symMatrix )
434  {
435  checkSizes< 2 >( eigenvalues );
436  checkSizes< 2, 2 >( eigenvectors );
437  checkSizes< 3 >( symMatrix );
438 
439  using FloatingPoint = std::decay_t< decltype( eigenvalues[ 0 ] ) >;
440 
441  using FloatingPoint = std::decay_t< decltype( eigenvalues[ 0 ] ) >;
442 
443  // Shift the and scale the matrix
444  FloatingPoint shift, maxEntryAfterShift;
445  FloatingPoint fpCopy[ 3 ];
446  copy< 3 >( fpCopy, symMatrix );
447  shiftAndScale< 2 >( fpCopy, shift, maxEntryAfterShift );
448 
449  // Compute the eigenvalues of the shifted matrix.
450  eigenvaluesOfShiftedMatrix( eigenvalues, fpCopy );
451 
452  // If the eigenvalues are equal
453  if( ( eigenvalues[ 1 ] - eigenvalues[ 0 ] ) <= NumericLimits< FloatingPoint >::epsilon )
454  {
455  LVARRAY_TENSOROPS_ASSIGN_2x2( eigenvectors,
456  1, 0,
457  0, 1 );
458  }
459  else
460  {
461  // Compute the eigenvector corresponding to the largest eigenvalue.
462  // Done by constructing a rank 1 matrix and extracting the kernel.
463  symAddIdentity< 2 >( fpCopy, -eigenvalues[ 1 ] );
464  FloatingPoint const a2 = fpCopy[ 0 ] * fpCopy[ 0 ];
465  FloatingPoint const c2 = fpCopy[ 1 ] * fpCopy[ 1 ];
466  FloatingPoint const b2 = fpCopy[ 2 ] * fpCopy[ 2 ];
467 
468  // Pick the row with the greatest magnitude.
469  if( a2 > c2 )
470  {
471  FloatingPoint const inv = math::invSqrt( a2 + b2 );
472  eigenvectors[ 0 ][ 1 ] = -fpCopy[ 2 ] * inv;
473  eigenvectors[ 1 ][ 1 ] = fpCopy[ 0 ] * inv;
474  }
475  else
476  {
477  FloatingPoint const inv = math::invSqrt( c2 + b2 );
478  eigenvectors[ 0 ][ 1 ] = -fpCopy[ 1 ] * inv;
479  eigenvectors[ 1 ][ 1 ] = fpCopy[ 2 ] * inv;
480  }
481 
482  // The other eigenvector is orthonormal to the one just computed.
483  eigenvectors[ 0 ][ 0 ] = -eigenvectors[ 1 ][ 1 ];
484  eigenvectors[ 1 ][ 0 ] = eigenvectors[ 0 ][ 1 ];
485  }
486 
487  // Rescale the eigenvalues.
488  eigenvalues[ 0 ] = eigenvalues[ 0 ] * maxEntryAfterShift + shift;
489  eigenvalues[ 1 ] = eigenvalues[ 1 ] * maxEntryAfterShift + shift;
490  }
491 
499  template< typename DST_SYM_MATRIX, typename SRC_MATRIX >
501  static void denseToSymmetric( DST_SYM_MATRIX && dstSymMatrix, SRC_MATRIX const & srcMatrix )
502  {
503  tensorOps::internal::checkSizes< 3 >( dstSymMatrix );
504  tensorOps::internal::checkSizes< 2, 2 >( srcMatrix );
505 
506  dstSymMatrix[ 0 ] = srcMatrix[ 0 ][ 0 ];
507  dstSymMatrix[ 1 ] = srcMatrix[ 1 ][ 1 ];
508  dstSymMatrix[ 2 ] = srcMatrix[ 0 ][ 1 ];
509  }
510 
518  template< typename DST_MATRIX, typename SRC_SYM_MATRIX >
520  static void symmetricToDense( DST_MATRIX && dstMatrix, SRC_SYM_MATRIX const & srcSymMatrix )
521  {
522  tensorOps::internal::checkSizes< 2, 2 >( dstMatrix );
523  tensorOps::internal::checkSizes< 3 >( srcSymMatrix );
524 
525  dstMatrix[ 0 ][ 0 ] = srcSymMatrix[ 0 ];
526  dstMatrix[ 1 ][ 1 ] = srcSymMatrix[ 1 ];
527 
528  dstMatrix[ 0 ][ 1 ] = srcSymMatrix[ 2 ];
529  dstMatrix[ 1 ][ 0 ] = srcSymMatrix[ 2 ];
530  }
531 
532 private:
533 
541  template< typename FloatingPoint, typename VECTOR >
542  LVARRAY_HOST_DEVICE inline
543  static void eigenvaluesOfShiftedMatrix( VECTOR && eigenvalues, FloatingPoint const ( &matrix )[ 3 ] )
544  {
545  /*
546  For a 2x2 symmetric matrix
547  a0, a2
548  a2, a1
549  And eigenvalue x the characteristic equation is
550  x^2 - (a0 + a1) * x + a0 * a1 - a2^2 = 0
551  However the shifted matrix has a trace of 0 so this simplifies to
552  x^2 + a0 * a1 - a2^2 = 0
553  */
554  eigenvalues[ 1 ] = math::sqrt( matrix[ 2 ] * matrix[ 2 ] - matrix[ 0 ] * matrix[ 1 ] );
555  eigenvalues[ 0 ] = -eigenvalues[ 1 ];
556  }
557 };
558 
563 template<>
564 struct SquareMatrixOps< 3 >
565 {
571  template< typename MATRIX >
573  static auto determinant( MATRIX const & matrix )
574  {
575  checkSizes< 3, 3 >( matrix );
576 
577  return matrix[ 0 ][ 0 ] * ( matrix[ 1 ][ 1 ] * matrix[ 2 ][ 2 ] - matrix[ 1 ][ 2 ] * matrix[ 2 ][ 1 ] ) +
578  matrix[ 1 ][ 0 ] * ( matrix[ 0 ][ 2 ] * matrix[ 2 ][ 1 ] - matrix[ 0 ][ 1 ] * matrix[ 2 ][ 2 ] ) +
579  matrix[ 2 ][ 0 ] * ( matrix[ 0 ][ 1 ] * matrix[ 1 ][ 2 ] - matrix[ 0 ][ 2 ] * matrix[ 1 ][ 1 ] );
580  }
581 
591  template< typename DST_MATRIX, typename SRC_MATRIX >
593  static auto invert( DST_MATRIX && LVARRAY_RESTRICT_REF dstMatrix,
594  SRC_MATRIX const & LVARRAY_RESTRICT_REF srcMatrix )
595  {
596  checkSizes< 3, 3 >( dstMatrix );
597  checkSizes< 3, 3 >( srcMatrix );
598 
599  using FloatingPoint = std::decay_t< decltype( dstMatrix[ 0 ][ 0 ] ) >;
600 
601  dstMatrix[ 0 ][ 0 ] = srcMatrix[ 1 ][ 1 ] * srcMatrix[ 2 ][ 2 ] - srcMatrix[ 1 ][ 2 ] * srcMatrix[ 2 ][ 1 ];
602  dstMatrix[ 0 ][ 1 ] = srcMatrix[ 0 ][ 2 ] * srcMatrix[ 2 ][ 1 ] - srcMatrix[ 0 ][ 1 ] * srcMatrix[ 2 ][ 2 ];
603  dstMatrix[ 0 ][ 2 ] = srcMatrix[ 0 ][ 1 ] * srcMatrix[ 1 ][ 2 ] - srcMatrix[ 0 ][ 2 ] * srcMatrix[ 1 ][ 1 ];
604 
605  auto const det = srcMatrix[ 0 ][ 0 ] * dstMatrix[ 0 ][ 0 ] +
606  srcMatrix[ 1 ][ 0 ] * dstMatrix[ 0 ][ 1 ] +
607  srcMatrix[ 2 ][ 0 ] * dstMatrix[ 0 ][ 2 ];
608  FloatingPoint const invDet = FloatingPoint( 1 ) / det;
609 
610  dstMatrix[ 0 ][ 0 ] *= invDet;
611  dstMatrix[ 0 ][ 1 ] *= invDet;
612  dstMatrix[ 0 ][ 2 ] *= invDet;
613  dstMatrix[ 1 ][ 0 ] = ( srcMatrix[ 1 ][ 2 ] * srcMatrix[ 2 ][ 0 ] - srcMatrix[ 1 ][ 0 ] * srcMatrix[ 2 ][ 2 ] ) * invDet;
614  dstMatrix[ 1 ][ 1 ] = ( srcMatrix[ 0 ][ 0 ] * srcMatrix[ 2 ][ 2 ] - srcMatrix[ 0 ][ 2 ] * srcMatrix[ 2 ][ 0 ] ) * invDet;
615  dstMatrix[ 1 ][ 2 ] = ( srcMatrix[ 0 ][ 2 ] * srcMatrix[ 1 ][ 0 ] - srcMatrix[ 0 ][ 0 ] * srcMatrix[ 1 ][ 2 ] ) * invDet;
616  dstMatrix[ 2 ][ 0 ] = ( srcMatrix[ 1 ][ 0 ] * srcMatrix[ 2 ][ 1 ] - srcMatrix[ 1 ][ 1 ] * srcMatrix[ 2 ][ 0 ] ) * invDet;
617  dstMatrix[ 2 ][ 1 ] = ( srcMatrix[ 0 ][ 1 ] * srcMatrix[ 2 ][ 0 ] - srcMatrix[ 0 ][ 0 ] * srcMatrix[ 2 ][ 1 ] ) * invDet;
618  dstMatrix[ 2 ][ 2 ] = ( srcMatrix[ 0 ][ 0 ] * srcMatrix[ 1 ][ 1 ] - srcMatrix[ 0 ][ 1 ] * srcMatrix[ 1 ][ 0 ] ) * invDet;
619 
620  return det;
621  }
622 
630  template< typename MATRIX >
631  LVARRAY_HOST_DEVICE constexpr inline
632  static auto invert( MATRIX && matrix )
633  {
634  using realType = std::remove_reference_t< decltype( matrix[ 0 ][ 0 ] ) >;
635 #if 0
636  realType temp[ 3 ][ 3 ];
637  copy< 3, 3 >( temp, matrix );
638  return invert( matrix, temp );
639 #else
640  // cuda kernels use a couple fewer registers in some cases with this implementation.
641  realType const temp[3][3] =
642  { { matrix[1][1]*matrix[2][2] - matrix[1][2]*matrix[2][1], matrix[0][2]*matrix[2][1] - matrix[0][1]*matrix[2][2], matrix[0][1]*matrix[1][2] - matrix[0][2]*matrix[1][1] },
643  { matrix[1][2]*matrix[2][0] - matrix[1][0]*matrix[2][2], matrix[0][0]*matrix[2][2] - matrix[0][2]*matrix[2][0], matrix[0][2]*matrix[1][0] - matrix[0][0]*matrix[1][2] },
644  { matrix[1][0]*matrix[2][1] - matrix[1][1]*matrix[2][0], matrix[0][1]*matrix[2][0] - matrix[0][0]*matrix[2][1], matrix[0][0]*matrix[1][1] - matrix[0][1]*matrix[1][0] } };
645 
646  realType const det = matrix[0][0] * temp[0][0] + matrix[1][0] * temp[0][1] + matrix[2][0] * temp[0][2];
647  realType const invDet = 1.0 / det;
648 
649  for( int i=0; i<3; ++i )
650  {
651  for( int j=0; j<3; ++j )
652  {
653  matrix[i][j] = temp[i][j] * invDet;
654  }
655  }
656  return det;
657 #endif
658  }
659 
665  template< typename SYM_MATRIX >
667  static auto symDeterminant( SYM_MATRIX const & symMatrix )
668  {
669  checkSizes< 6 >( symMatrix );
670 
671  return symMatrix[ 0 ] * symMatrix[ 1 ] * symMatrix[ 2 ] +
672  symMatrix[ 5 ] * symMatrix[ 4 ] * symMatrix[ 3 ] * 2 -
673  symMatrix[ 0 ] * symMatrix[ 3 ] * symMatrix[ 3 ] -
674  symMatrix[ 1 ] * symMatrix[ 4 ] * symMatrix[ 4 ] -
675  symMatrix[ 2 ] * symMatrix[ 5 ] * symMatrix[ 5 ];
676  }
677 
687  template< typename DST_SYM_MATRIX, typename SRC_SYM_MATRIX >
689  static auto symInvert( DST_SYM_MATRIX && LVARRAY_RESTRICT_REF dstSymMatrix,
690  SRC_SYM_MATRIX const & LVARRAY_RESTRICT_REF srcSymMatrix )
691  {
692  checkSizes< 6 >( dstSymMatrix );
693  checkSizes< 6 >( srcSymMatrix );
694 
695  using FloatingPoint = std::decay_t< decltype( dstSymMatrix[ 0 ] ) >;
696 
697  dstSymMatrix[ 0 ] = srcSymMatrix[ 1 ] * srcSymMatrix[ 2 ] - srcSymMatrix[ 3 ] * srcSymMatrix[ 3 ];
698  dstSymMatrix[ 5 ] = srcSymMatrix[ 4 ] * srcSymMatrix[ 3 ] - srcSymMatrix[ 5 ] * srcSymMatrix[ 2 ];
699  dstSymMatrix[ 4 ] = srcSymMatrix[ 5 ] * srcSymMatrix[ 3 ] - srcSymMatrix[ 4 ] * srcSymMatrix[ 1 ];
700 
701  auto const det = srcSymMatrix[ 0 ] * dstSymMatrix[ 0 ] +
702  srcSymMatrix[ 5 ] * dstSymMatrix[ 5 ] +
703  srcSymMatrix[ 4 ] * dstSymMatrix[ 4 ];
704  FloatingPoint const invDet = FloatingPoint( 1 ) / det;
705 
706  dstSymMatrix[ 0 ] *= invDet;
707  dstSymMatrix[ 5 ] *= invDet;
708  dstSymMatrix[ 4 ] *= invDet;
709  dstSymMatrix[ 1 ] = ( srcSymMatrix[ 0 ] * srcSymMatrix[ 2 ] - srcSymMatrix[ 4 ] * srcSymMatrix[ 4 ] ) * invDet;
710  dstSymMatrix[ 3 ] = ( srcSymMatrix[ 5 ] * srcSymMatrix[ 4 ] - srcSymMatrix[ 0 ] * srcSymMatrix[ 3 ] ) * invDet;
711  dstSymMatrix[ 2 ] = ( srcSymMatrix[ 0 ] * srcSymMatrix[ 1 ] - srcSymMatrix[ 5 ] * srcSymMatrix[ 5 ] ) * invDet;
712 
713  return det;
714  }
715 
723  template< typename SYM_MATRIX >
725  static auto symInvert( SYM_MATRIX && symMatrix )
726  {
727  std::remove_reference_t< decltype( symMatrix[ 0 ] ) > temp[ 6 ];
728  auto const det = symInvert( temp, symMatrix );
729  copy< 6 >( symMatrix, temp );
730 
731  return det;
732  }
733 
745  template< typename DST_VECTOR, typename SYM_MATRIX_A, typename VECTOR_B >
747  static void Ri_eq_symAijBj( DST_VECTOR && LVARRAY_RESTRICT_REF dstVector,
748  SYM_MATRIX_A const & LVARRAY_RESTRICT_REF symMatrixA,
749  VECTOR_B const & LVARRAY_RESTRICT_REF vectorB )
750  {
751  checkSizes< 3 >( dstVector );
752  checkSizes< 6 >( symMatrixA );
753  checkSizes< 3 >( vectorB );
754 
755  dstVector[ 0 ] = symMatrixA[ 0 ] * vectorB[ 0 ] +
756  symMatrixA[ 5 ] * vectorB[ 1 ] +
757  symMatrixA[ 4 ] * vectorB[ 2 ];
758  dstVector[ 1 ] = symMatrixA[ 5 ] * vectorB[ 0 ] +
759  symMatrixA[ 1 ] * vectorB[ 1 ] +
760  symMatrixA[ 3 ] * vectorB[ 2 ];
761  dstVector[ 2 ] = symMatrixA[ 4 ] * vectorB[ 0 ] +
762  symMatrixA[ 3 ] * vectorB[ 1 ] +
763  symMatrixA[ 2 ] * vectorB[ 2 ];
764  }
765 
776  template< typename DST_VECTOR, typename SYM_MATRIX_A, typename VECTOR_B >
778  static void Ri_add_symAijBj( DST_VECTOR && LVARRAY_RESTRICT_REF dstVector,
779  SYM_MATRIX_A const & LVARRAY_RESTRICT_REF symMatrixA,
780  VECTOR_B const & LVARRAY_RESTRICT_REF vectorB )
781  {
782  checkSizes< 3 >( dstVector );
783  checkSizes< 6 >( symMatrixA );
784  checkSizes< 3 >( vectorB );
785 
786  dstVector[ 0 ] = dstVector[ 0 ] +
787  symMatrixA[ 0 ] * vectorB[ 0 ] +
788  symMatrixA[ 5 ] * vectorB[ 1 ] +
789  symMatrixA[ 4 ] * vectorB[ 2 ];
790  dstVector[ 1 ] = dstVector[ 1 ] +
791  symMatrixA[ 5 ] * vectorB[ 0 ] +
792  symMatrixA[ 1 ] * vectorB[ 1 ] +
793  symMatrixA[ 3 ] * vectorB[ 2 ];
794  dstVector[ 2 ] = dstVector[ 2 ] +
795  symMatrixA[ 4 ] * vectorB[ 0 ] +
796  symMatrixA[ 3 ] * vectorB[ 1 ] +
797  symMatrixA[ 2 ] * vectorB[ 2 ];
798  }
799 
811  template< typename DST_MATRIX, typename SYM_MATRIX_A, typename MATRIX_B >
813  static void Rij_eq_symAikBjk( DST_MATRIX && LVARRAY_RESTRICT_REF dstMatrix,
814  SYM_MATRIX_A const & LVARRAY_RESTRICT_REF symMatrixA,
815  MATRIX_B const & LVARRAY_RESTRICT_REF matrixB )
816  {
817  checkSizes< 3, 3 >( dstMatrix );
818  checkSizes< 6 >( symMatrixA );
819  checkSizes< 3, 3 >( matrixB );
820 
821  dstMatrix[ 0 ][ 0 ] = symMatrixA[ 0 ] * matrixB[ 0 ][ 0 ] +
822  symMatrixA[ 5 ] * matrixB[ 0 ][ 1 ] +
823  symMatrixA[ 4 ] * matrixB[ 0 ][ 2 ];
824  dstMatrix[ 0 ][ 1 ] = symMatrixA[ 0 ] * matrixB[ 1 ][ 0 ] +
825  symMatrixA[ 5 ] * matrixB[ 1 ][ 1 ] +
826  symMatrixA[ 4 ] * matrixB[ 1 ][ 2 ];
827  dstMatrix[ 0 ][ 2 ] = symMatrixA[ 0 ] * matrixB[ 2 ][ 0 ] +
828  symMatrixA[ 5 ] * matrixB[ 2 ][ 1 ] +
829  symMatrixA[ 4 ] * matrixB[ 2 ][ 2 ];
830 
831  dstMatrix[ 1 ][ 0 ] = symMatrixA[ 5 ] * matrixB[ 0 ][ 0 ] +
832  symMatrixA[ 1 ] * matrixB[ 0 ][ 1 ] +
833  symMatrixA[ 3 ] * matrixB[ 0 ][ 2 ];
834  dstMatrix[ 1 ][ 1 ] = symMatrixA[ 5 ] * matrixB[ 1 ][ 0 ] +
835  symMatrixA[ 1 ] * matrixB[ 1 ][ 1 ] +
836  symMatrixA[ 3 ] * matrixB[ 1 ][ 2 ];
837  dstMatrix[ 1 ][ 2 ] = symMatrixA[ 5 ] * matrixB[ 2 ][ 0 ] +
838  symMatrixA[ 1 ] * matrixB[ 2 ][ 1 ] +
839  symMatrixA[ 3 ] * matrixB[ 2 ][ 2 ];
840 
841  dstMatrix[ 2 ][ 0 ] = symMatrixA[ 4 ] * matrixB[ 0 ][ 0 ] +
842  symMatrixA[ 3 ] * matrixB[ 0 ][ 1 ] +
843  symMatrixA[ 2 ] * matrixB[ 0 ][ 2 ];
844  dstMatrix[ 2 ][ 1 ] = symMatrixA[ 4 ] * matrixB[ 1 ][ 0 ] +
845  symMatrixA[ 3 ] * matrixB[ 1 ][ 1 ] +
846  symMatrixA[ 2 ] * matrixB[ 1 ][ 2 ];
847  dstMatrix[ 2 ][ 2 ] = symMatrixA[ 4 ] * matrixB[ 2 ][ 0 ] +
848  symMatrixA[ 3 ] * matrixB[ 2 ][ 1 ] +
849  symMatrixA[ 2 ] * matrixB[ 2 ][ 2 ];
850  }
851 
865  template< typename DST_SYM_MATRIX, typename MATRIX_A, typename SYM_MATRIX_B >
867  static void Rij_eq_AikSymBklAjl( DST_SYM_MATRIX && LVARRAY_RESTRICT_REF dstSymMatrix,
868  MATRIX_A const & LVARRAY_RESTRICT_REF matrixA,
869  SYM_MATRIX_B const & LVARRAY_RESTRICT_REF symMatrixB )
870  {
871  checkSizes< 6 >( dstSymMatrix );
872  checkSizes< 3, 3 >( matrixA );
873  checkSizes< 6 >( symMatrixB );
874 
875  // Calculate entry (0, 0).
876  dstSymMatrix[ 0 ] = matrixA[ 0 ][ 0 ] * symMatrixB[ 0 ] * matrixA[ 0 ][ 0 ] +
877  matrixA[ 0 ][ 0 ] * symMatrixB[ 5 ] * matrixA[ 0 ][ 1 ] +
878  matrixA[ 0 ][ 0 ] * symMatrixB[ 4 ] * matrixA[ 0 ][ 2 ] +
879  matrixA[ 0 ][ 1 ] * symMatrixB[ 5 ] * matrixA[ 0 ][ 0 ] +
880  matrixA[ 0 ][ 1 ] * symMatrixB[ 1 ] * matrixA[ 0 ][ 1 ] +
881  matrixA[ 0 ][ 1 ] * symMatrixB[ 3 ] * matrixA[ 0 ][ 2 ] +
882  matrixA[ 0 ][ 2 ] * symMatrixB[ 4 ] * matrixA[ 0 ][ 0 ] +
883  matrixA[ 0 ][ 2 ] * symMatrixB[ 3 ] * matrixA[ 0 ][ 1 ] +
884  matrixA[ 0 ][ 2 ] * symMatrixB[ 2 ] * matrixA[ 0 ][ 2 ];
885 
886  // Calculate entry (1, 1).
887  dstSymMatrix[ 1 ] = matrixA[ 1 ][ 0 ] * symMatrixB[ 0 ] * matrixA[ 1 ][ 0 ] +
888  matrixA[ 1 ][ 0 ] * symMatrixB[ 5 ] * matrixA[ 1 ][ 1 ] +
889  matrixA[ 1 ][ 0 ] * symMatrixB[ 4 ] * matrixA[ 1 ][ 2 ] +
890  matrixA[ 1 ][ 1 ] * symMatrixB[ 5 ] * matrixA[ 1 ][ 0 ] +
891  matrixA[ 1 ][ 1 ] * symMatrixB[ 1 ] * matrixA[ 1 ][ 1 ] +
892  matrixA[ 1 ][ 1 ] * symMatrixB[ 3 ] * matrixA[ 1 ][ 2 ] +
893  matrixA[ 1 ][ 2 ] * symMatrixB[ 4 ] * matrixA[ 1 ][ 0 ] +
894  matrixA[ 1 ][ 2 ] * symMatrixB[ 3 ] * matrixA[ 1 ][ 1 ] +
895  matrixA[ 1 ][ 2 ] * symMatrixB[ 2 ] * matrixA[ 1 ][ 2 ];
896 
897  // Calculate entry (2, 2).
898  dstSymMatrix[ 2 ] = matrixA[ 2 ][ 0 ] * symMatrixB[ 0 ] * matrixA[ 2 ][ 0 ] +
899  matrixA[ 2 ][ 0 ] * symMatrixB[ 5 ] * matrixA[ 2 ][ 1 ] +
900  matrixA[ 2 ][ 0 ] * symMatrixB[ 4 ] * matrixA[ 2 ][ 2 ] +
901  matrixA[ 2 ][ 1 ] * symMatrixB[ 5 ] * matrixA[ 2 ][ 0 ] +
902  matrixA[ 2 ][ 1 ] * symMatrixB[ 1 ] * matrixA[ 2 ][ 1 ] +
903  matrixA[ 2 ][ 1 ] * symMatrixB[ 3 ] * matrixA[ 2 ][ 2 ] +
904  matrixA[ 2 ][ 2 ] * symMatrixB[ 4 ] * matrixA[ 2 ][ 0 ] +
905  matrixA[ 2 ][ 2 ] * symMatrixB[ 3 ] * matrixA[ 2 ][ 1 ] +
906  matrixA[ 2 ][ 2 ] * symMatrixB[ 2 ] * matrixA[ 2 ][ 2 ];
907 
908  // Calculate entry (1, 2) or (2, 1).
909  dstSymMatrix[ 3 ] = matrixA[ 1 ][ 0 ] * symMatrixB[ 0 ] * matrixA[ 2 ][ 0 ] +
910  matrixA[ 1 ][ 0 ] * symMatrixB[ 5 ] * matrixA[ 2 ][ 1 ] +
911  matrixA[ 1 ][ 0 ] * symMatrixB[ 4 ] * matrixA[ 2 ][ 2 ] +
912  matrixA[ 1 ][ 1 ] * symMatrixB[ 5 ] * matrixA[ 2 ][ 0 ] +
913  matrixA[ 1 ][ 1 ] * symMatrixB[ 1 ] * matrixA[ 2 ][ 1 ] +
914  matrixA[ 1 ][ 1 ] * symMatrixB[ 3 ] * matrixA[ 2 ][ 2 ] +
915  matrixA[ 1 ][ 2 ] * symMatrixB[ 4 ] * matrixA[ 2 ][ 0 ] +
916  matrixA[ 1 ][ 2 ] * symMatrixB[ 3 ] * matrixA[ 2 ][ 1 ] +
917  matrixA[ 1 ][ 2 ] * symMatrixB[ 2 ] * matrixA[ 2 ][ 2 ];
918 
919  // Calculate entry (0, 2) or (2, 0).
920  dstSymMatrix[ 4 ] = matrixA[ 0 ][ 0 ] * symMatrixB[ 0 ] * matrixA[ 2 ][ 0 ] +
921  matrixA[ 0 ][ 0 ] * symMatrixB[ 5 ] * matrixA[ 2 ][ 1 ] +
922  matrixA[ 0 ][ 0 ] * symMatrixB[ 4 ] * matrixA[ 2 ][ 2 ] +
923  matrixA[ 0 ][ 1 ] * symMatrixB[ 5 ] * matrixA[ 2 ][ 0 ] +
924  matrixA[ 0 ][ 1 ] * symMatrixB[ 1 ] * matrixA[ 2 ][ 1 ] +
925  matrixA[ 0 ][ 1 ] * symMatrixB[ 3 ] * matrixA[ 2 ][ 2 ] +
926  matrixA[ 0 ][ 2 ] * symMatrixB[ 4 ] * matrixA[ 2 ][ 0 ] +
927  matrixA[ 0 ][ 2 ] * symMatrixB[ 3 ] * matrixA[ 2 ][ 1 ] +
928  matrixA[ 0 ][ 2 ] * symMatrixB[ 2 ] * matrixA[ 2 ][ 2 ];
929 
930  // Calculate entry (0, 1) or (1, 0).
931  dstSymMatrix[ 5 ] = matrixA[ 0 ][ 0 ] * symMatrixB[ 0 ] * matrixA[ 1 ][ 0 ] +
932  matrixA[ 0 ][ 0 ] * symMatrixB[ 5 ] * matrixA[ 1 ][ 1 ] +
933  matrixA[ 0 ][ 0 ] * symMatrixB[ 4 ] * matrixA[ 1 ][ 2 ] +
934  matrixA[ 0 ][ 1 ] * symMatrixB[ 5 ] * matrixA[ 1 ][ 0 ] +
935  matrixA[ 0 ][ 1 ] * symMatrixB[ 1 ] * matrixA[ 1 ][ 1 ] +
936  matrixA[ 0 ][ 1 ] * symMatrixB[ 3 ] * matrixA[ 1 ][ 2 ] +
937  matrixA[ 0 ][ 2 ] * symMatrixB[ 4 ] * matrixA[ 1 ][ 0 ] +
938  matrixA[ 0 ][ 2 ] * symMatrixB[ 3 ] * matrixA[ 1 ][ 1 ] +
939  matrixA[ 0 ][ 2 ] * symMatrixB[ 2 ] * matrixA[ 1 ][ 2 ];
940  }
941 
951  template< typename DST_MATRIX, typename VECTOR_A >
953  static void symRij_eq_AiAj( DST_MATRIX && LVARRAY_RESTRICT_REF dstMatrix,
954  VECTOR_A const & LVARRAY_RESTRICT_REF vectorA )
955  {
956  internal::checkSizes< 6 >( dstMatrix );
957  internal::checkSizes< 3 >( vectorA );
958 
959  dstMatrix[ 0 ] = vectorA[ 0 ] * vectorA[ 0 ];
960  dstMatrix[ 1 ] = vectorA[ 1 ] * vectorA[ 1 ];
961  dstMatrix[ 2 ] = vectorA[ 2 ] * vectorA[ 2 ];
962  dstMatrix[ 3 ] = vectorA[ 1 ] * vectorA[ 2 ];
963  dstMatrix[ 4 ] = vectorA[ 0 ] * vectorA[ 2 ];
964  dstMatrix[ 5 ] = vectorA[ 0 ] * vectorA[ 1 ];
965  }
966 
978  template< typename DST_SYM_MATRIX, typename VECTOR_A, typename VECTOR_B >
980  static void symRij_eq_AiBj_plus_AjBi( DST_SYM_MATRIX && LVARRAY_RESTRICT_REF dstMatrix,
981  VECTOR_A const & LVARRAY_RESTRICT_REF vectorA,
982  VECTOR_B const & LVARRAY_RESTRICT_REF vectorB )
983  {
984  internal::checkSizes< 6 >( dstMatrix );
985  internal::checkSizes< 3 >( vectorA );
986  internal::checkSizes< 3 >( vectorB );
987 
988  dstMatrix[ 0 ] = 2 * vectorA[ 0 ] * vectorB[ 0 ];
989  dstMatrix[ 1 ] = 2 * vectorA[ 1 ] * vectorB[ 1 ];
990  dstMatrix[ 2 ] = 2 * vectorA[ 2 ] * vectorB[ 2 ];
991  dstMatrix[ 3 ] = vectorA[ 1 ] * vectorB[ 2 ] + vectorA[ 2 ] * vectorB[ 1 ];
992  dstMatrix[ 4 ] = vectorA[ 0 ] * vectorB[ 2 ] + vectorA[ 2 ] * vectorB[ 0 ];
993  dstMatrix[ 5 ] = vectorA[ 0 ] * vectorB[ 1 ] + vectorA[ 1 ] * vectorB[ 0 ];
994  }
995 
1005  template< typename DST_VECTOR, typename SYM_MATRIX >
1007  static void symEigenvalues( DST_VECTOR && LVARRAY_RESTRICT_REF eigenvalues,
1008  SYM_MATRIX const & LVARRAY_RESTRICT_REF symMatrix )
1009  {
1010  checkSizes< 3 >( eigenvalues );
1011  checkSizes< 6 >( symMatrix );
1012 
1013  using FloatingPoint = std::decay_t< decltype( eigenvalues[ 0 ] ) >;
1014 
1015  FloatingPoint shift, maxEntryAfterShift;
1016  FloatingPoint fpCopy[ 6 ];
1017  copy< 6 >( fpCopy, symMatrix );
1018  shiftAndScale< 3 >( fpCopy, shift, maxEntryAfterShift );
1019 
1020  eigenvaluesOfShiftedMatrix( eigenvalues, fpCopy );
1021 
1022  // Rescale back to the original size.
1023  eigenvalues[ 0 ] = maxEntryAfterShift * eigenvalues[ 0 ] + shift;
1024  eigenvalues[ 1 ] = maxEntryAfterShift * eigenvalues[ 1 ] + shift;
1025  eigenvalues[ 2 ] = maxEntryAfterShift * eigenvalues[ 2 ] + shift;
1026  }
1027 
1041  template< typename DST_VECTOR, typename DST_MATRIX, typename SYM_MATRIX >
1043  static void symEigenvectors( DST_VECTOR && LVARRAY_RESTRICT_REF eigenvalues,
1044  DST_MATRIX && LVARRAY_RESTRICT_REF eigenvectors,
1045  SYM_MATRIX const & LVARRAY_RESTRICT_REF symMatrix )
1046  {
1047  checkSizes< 3 >( eigenvalues );
1048  checkSizes< 3, 3 >( eigenvectors );
1049  checkSizes< 6 >( symMatrix );
1050 
1051  using FloatingPoint = std::decay_t< decltype( eigenvalues[ 0 ] ) >;
1052 
1053  FloatingPoint shift, maxEntryAfterShift;
1054  FloatingPoint fpCopy[ 6 ];
1055  copy< 6 >( fpCopy, symMatrix );
1056  shiftAndScale< 3 >( fpCopy, shift, maxEntryAfterShift );
1057 
1058  eigenvaluesOfShiftedMatrix( eigenvalues, fpCopy );
1059 
1060  // compute the eigenvectors
1061  FloatingPoint const eigenvalueDifference = eigenvalues[ 2 ] - eigenvalues[ 0 ];
1062  if( eigenvalueDifference <= NumericLimits< FloatingPoint >::epsilon )
1063  {
1064  // All three eigenvalues are numerically the same
1065  LVARRAY_TENSOROPS_ASSIGN_3x3( eigenvectors,
1066  1, 0, 0,
1067  0, 1, 0,
1068  0, 0, 1 );
1069  }
1070  else
1071  {
1072  // Compute the eigenvector of the most distinct eigenvalue first. Since the eigenvalues are sorted
1073  // this is the eigenvector corresponding to either the first or last eigenvalue.
1074  int const mostDistinct = ( ( eigenvalues[ 2 ] - eigenvalues[ 1 ] ) >
1075  ( eigenvalues[ 1 ] - eigenvalues[ 0 ] ) ) ? 2 : 0;
1076  int const secondMostDistinct = 2 - mostDistinct;
1077 
1078  // Compute the first eigenvector. This is done by subtracting the identity times the most distinct eigenvalue
1079  // from the matrix which gives us a rank 2 matrix where the nullspace is the corresponding eigenvector.
1080  FloatingPoint tmp[ 3 ][ 3 ] = { { fpCopy[ 0 ] - eigenvalues[ mostDistinct ], fpCopy[ 5 ], fpCopy[ 4 ] },
1081  { fpCopy[ 5 ], fpCopy[ 1 ] - eigenvalues[ mostDistinct ], fpCopy[ 3 ] },
1082  { fpCopy[ 4 ], fpCopy[ 3 ], fpCopy[ 2 ] - eigenvalues[ mostDistinct ] } };
1083 
1084  int const row = getNullVector( eigenvectors[ mostDistinct ], tmp );
1085 
1086  // Compute eigenvector of the second most distinct eigenvalue.
1087  FloatingPoint const minEigenvalueSpacing = math::abs( eigenvalues[ secondMostDistinct ] - eigenvalues[ 1 ] );
1088  if( minEigenvalueSpacing <= 2 * NumericLimits< FloatingPoint >::epsilon * eigenvalueDifference )
1089  {
1090  // If minEigenvalueSpacing is too small then the other two eigenvalues are numerically the same
1091  // we can use tmp[ row ].
1092  FloatingPoint const norm2 = l2NormSquared< 3 >( tmp[ row ] );
1093  scaledCopy< 3 >( eigenvectors[ secondMostDistinct ], tmp[ row ], math::invSqrt( norm2 ) );
1094  }
1095  else
1096  {
1097  // Otherwise repeat the procedure with the second most distinct eigenvalue.
1098  tmp[ 0 ][ 0 ] = fpCopy[ 0 ] - eigenvalues[ secondMostDistinct ];
1099  tmp[ 1 ][ 1 ] = fpCopy[ 1 ] - eigenvalues[ secondMostDistinct ];
1100  tmp[ 2 ][ 2 ] = fpCopy[ 2 ] - eigenvalues[ secondMostDistinct ];
1101 
1102  getNullVector( eigenvectors[ secondMostDistinct ], tmp );
1103  }
1104 
1105  // Compute last eigenvector from the other two
1106  crossProduct( eigenvectors[ 1 ], eigenvectors[ 2 ], eigenvectors[ 0 ] );
1107  normalize< 3 >( eigenvectors[ 1 ] );
1108  }
1109 
1110  // Rescale back to the original size.
1111  eigenvalues[ 0 ] = maxEntryAfterShift * eigenvalues[ 0 ] + shift;
1112  eigenvalues[ 1 ] = maxEntryAfterShift * eigenvalues[ 1 ] + shift;
1113  eigenvalues[ 2 ] = maxEntryAfterShift * eigenvalues[ 2 ] + shift;
1114  }
1115 
1123  template< typename DST_SYM_MATRIX, typename SRC_MATRIX >
1125  static void denseToSymmetric( DST_SYM_MATRIX && dstSymMatrix, SRC_MATRIX const & srcMatrix )
1126  {
1127  tensorOps::internal::checkSizes< 6 >( dstSymMatrix );
1128  tensorOps::internal::checkSizes< 3, 3 >( srcMatrix );
1129 
1130  dstSymMatrix[ 0 ] = srcMatrix[ 0 ][ 0 ];
1131  dstSymMatrix[ 1 ] = srcMatrix[ 1 ][ 1 ];
1132  dstSymMatrix[ 2 ] = srcMatrix[ 2 ][ 2 ];
1133  dstSymMatrix[ 3 ] = srcMatrix[ 1 ][ 2 ];
1134  dstSymMatrix[ 4 ] = srcMatrix[ 0 ][ 2 ];
1135  dstSymMatrix[ 5 ] = srcMatrix[ 0 ][ 1 ];
1136  }
1137 
1145  template< typename DST_MATRIX, typename SRC_SYM_MATRIX >
1147  static void symmetricToDense( DST_MATRIX && dstMatrix, SRC_SYM_MATRIX const & srcSymMatrix )
1148  {
1149  tensorOps::internal::checkSizes< 3, 3 >( dstMatrix );
1150  tensorOps::internal::checkSizes< 6 >( srcSymMatrix );
1151 
1152  dstMatrix[ 0 ][ 0 ] = srcSymMatrix[ 0 ];
1153  dstMatrix[ 1 ][ 1 ] = srcSymMatrix[ 1 ];
1154  dstMatrix[ 2 ][ 2 ] = srcSymMatrix[ 2 ];
1155 
1156  dstMatrix[ 0 ][ 1 ] = srcSymMatrix[ 5 ];
1157  dstMatrix[ 0 ][ 2 ] = srcSymMatrix[ 4 ];
1158  dstMatrix[ 1 ][ 2 ] = srcSymMatrix[ 3 ];
1159 
1160  dstMatrix[ 1 ][ 0 ] = srcSymMatrix[ 5 ];
1161  dstMatrix[ 2 ][ 0 ] = srcSymMatrix[ 4 ];
1162  dstMatrix[ 2 ][ 1 ] = srcSymMatrix[ 3 ];
1163  }
1164 
1165 private:
1173  template< typename FloatingPoint, typename VECTOR >
1174  LVARRAY_HOST_DEVICE inline
1175  static void eigenvaluesOfShiftedMatrix( VECTOR && eigenvalues,
1176  FloatingPoint const ( &matrix )[ 6 ] )
1177  {
1178  /*
1179  For a 3x3 symmetric matrix A
1180  a0, a5, a4
1181  a5, a1, a3
1182  a4, a3, a2
1183  And eigenvalue x the characteristic equation is
1184  x^3 - tr(A) * x^2 - 0.5 * (tr(A^2) - tr(A)^2) * x - det( A ) = 0
1185  However the shifted matrix has a trace of 0 so this simplifies to
1186  x^3 - 0.5 * tr(A^2) * x - det( A ) = 0
1187 
1188  This approach is a hybrid of the wikipedia algorithm and Eigen's algorithm.
1189  The wikipedia algorithm uses one less call to sqrt to find theta but Eigen's
1190  conversion from theta to the roots is faster.
1191 
1192  https://en.wikipedia.org/wiki/Eigenvalue_algorithm#3%C3%973_matrices.
1193  https://gitlab.com/libeigen/eigen/-/blob/3.3/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h#L567
1194  */
1195 
1196  // The calculation of the trace(A^2) uses the fact that trace(A) = 0 and hence a2 = -a1 - a0.
1197  FloatingPoint const oneSixthTraceASquared =
1198  ( matrix[ 2 ] * matrix[ 2 ] - matrix[ 0 ] * matrix[ 1 ] + matrix[ 3 ] * matrix[ 3 ] +
1199  matrix[ 4 ] * matrix[ 4 ] + matrix[ 5 ] * matrix[ 5 ] ) / 3;
1200 
1201  FloatingPoint const p = math::sqrt( oneSixthTraceASquared );
1202 
1203  FloatingPoint const det = ( p > 0 ) ? symDeterminant( matrix ) / ( p * p * p ) : 0;
1204 
1205  // det should be in [-2, 2] but it may be slightly outside do to floating point error.
1206  FloatingPoint const halfDetB = det > 2 ? 1 : ( det < -2 ? -1 : det / 2 );
1207  FloatingPoint const theta = math::acos( halfDetB ) / 3;
1208 
1209  FloatingPoint sinTheta, cosTheta;
1210  math::sincos( theta, sinTheta, cosTheta );
1211 
1212  // roots are already sorted, since cos is monotonically decreasing on [0, pi]
1213  constexpr FloatingPoint squareRootThree = 1.73205080756887729352744;
1214  eigenvalues[ 0 ] = -p * ( cosTheta + squareRootThree * sinTheta ); // == 2 * p * cos( theta + 2pi/3 )
1215  eigenvalues[ 1 ] = -p * ( cosTheta - squareRootThree * sinTheta ); // == 2 * p * cos( theta + pi/3 )
1216  eigenvalues[ 2 ] = 2 * p * cosTheta;
1217  }
1218 
1228  template< typename FLOAT, typename VECTOR >
1230  static int getNullVector( VECTOR && nullVector, FLOAT const (&mat)[ 3 ][ 3 ] )
1231  {
1232  // Find the row with the largest diagonal value.
1233  FLOAT const abs00 = math::abs( mat[ 0 ][ 0 ] );
1234  FLOAT const abs11 = math::abs( mat[ 1 ][ 1 ] );
1235  FLOAT const abs22 = math::abs( mat[ 2 ][ 2 ] );
1236 
1237  int const row = abs00 > abs11 ? ( abs00 > abs22 ? 0 : 2 ) :
1238  ( abs11 > abs22 ? 1 : 2 );
1239 
1240  // From each of the other two rows in the matrix construct an orthogonal vector.
1241  crossProduct( nullVector, mat[ row ], mat[ ( row + 1 ) % 3 ] );
1242  FLOAT const n0 = l2NormSquared< 3 >( nullVector );
1243 
1244  FLOAT nullVectorCandidate[ 3 ];
1245  crossProduct( nullVectorCandidate, mat[ row ], mat[ ( row + 2 ) % 3 ] );
1246  FLOAT const n1 = l2NormSquared< 3 >( nullVectorCandidate );
1247 
1248  // Choose the null vector with the largest magnitude.
1249  if( n0 > n1 )
1250  { scale< 3 >( nullVector, math::invSqrt( n0 ) ); }
1251  else
1252  { scaledCopy< 3 >( nullVector, nullVectorCandidate, math::invSqrt( n1 ) ); }
1253 
1254  return row;
1255  }
1256 };
1257 
1258 } // namespace internal
1259 } // namespace tensorOps
1260 } // namespace LvArray
LVARRAY_HOST_DEVICE static CONSTEXPR_WITHOUT_BOUNDS_CHECK auto symDeterminant(SYM_MATRIX const &symMatrix)
Definition: fixedSizeSquareMatrixOpsImpl.hpp:667
LVARRAY_HOST_DEVICE static CONSTEXPR_WITHOUT_BOUNDS_CHECK void symEigenvectors(DST_VECTOR &&LVARRAY_RESTRICT_REF eigenvalues, DST_MATRIX &&LVARRAY_RESTRICT_REF eigenvectors, SYM_MATRIX const &LVARRAY_RESTRICT_REF symMatrix)
Compute the eigenvalues and eigenvectors of the symmetric matrix symMatrix.
Definition: fixedSizeSquareMatrixOpsImpl.hpp:431
LVARRAY_HOST_DEVICE static CONSTEXPR_WITHOUT_BOUNDS_CHECK int getNullVector(VECTOR &&nullVector, FLOAT const (&mat)[3][3])
Extract the nullspace of the rank 2 3x3 symmetric matrix mat.
Definition: fixedSizeSquareMatrixOpsImpl.hpp:1230
LVARRAY_HOST_DEVICE static CONSTEXPR_WITHOUT_BOUNDS_CHECK void symEigenvectors(DST_VECTOR &&LVARRAY_RESTRICT_REF eigenvalues, DST_MATRIX &&LVARRAY_RESTRICT_REF eigenvectors, SYM_MATRIX const &LVARRAY_RESTRICT_REF symMatrix)
Compute the eigenvalues and eigenvectors of the symmetric matrix symMatrix.
Definition: fixedSizeSquareMatrixOpsImpl.hpp:1043
LVARRAY_HOST_DEVICE static CONSTEXPR_WITHOUT_BOUNDS_CHECK auto symDeterminant(SYM_MATRIX const &symMatrix)
Definition: fixedSizeSquareMatrixOpsImpl.hpp:156
LVARRAY_HOST_DEVICE static CONSTEXPR_WITHOUT_BOUNDS_CHECK auto symInvert(DST_SYM_MATRIX &&LVARRAY_RESTRICT_REF dstSymMatrix, SRC_SYM_MATRIX const &LVARRAY_RESTRICT_REF srcSymMatrix)
Invert the symmetric matrix srcSymMatrix and store the result in dstSymMatrix.
Definition: fixedSizeSquareMatrixOpsImpl.hpp:689
LVARRAY_HOST_DEVICE static CONSTEXPR_WITHOUT_BOUNDS_CHECK void symEigenvalues(DST_VECTOR &&LVARRAY_RESTRICT_REF eigenvalues, SYM_MATRIX const &LVARRAY_RESTRICT_REF symMatrix)
Compute the eigenvalues of the symmetric matrix symMatrix.
Definition: fixedSizeSquareMatrixOpsImpl.hpp:394
LVARRAY_HOST_DEVICE static CONSTEXPR_WITHOUT_BOUNDS_CHECK auto symInvert(SYM_MATRIX &&symMatrix)
Invert the symmetric matrix symMatrix overwritting it.
Definition: fixedSizeSquareMatrixOpsImpl.hpp:725
LVARRAY_HOST_DEVICE static CONSTEXPR_WITHOUT_BOUNDS_CHECK auto invert(MATRIX &&matrix)
Invert the matrix srcMatrix overwritting it.
Definition: fixedSizeSquareMatrixOpsImpl.hpp:133
Performs operations on square matrices.
Definition: fixedSizeSquareMatrixOpsImpl.hpp:71
static LVARRAY_HOST_DEVICE void shiftAndScale(FloatingPoint(&matrix)[(M *(M+1))/2], FloatingPoint &shift, FloatingPoint &maxEntryAfterShift)
Shift the and scale the MxM symmetric matrix matrix.
Definition: fixedSizeSquareMatrixOpsImpl.hpp:38
static LVARRAY_HOST_DEVICE void eigenvaluesOfShiftedMatrix(VECTOR &&eigenvalues, FloatingPoint const (&matrix)[6])
Compute the eigenvalues of the 3x3 symmetric matrix matrix.
Definition: fixedSizeSquareMatrixOpsImpl.hpp:1175
LVARRAY_HOST_DEVICE CONSTEXPR_WITHOUT_BOUNDS_CHECK auto invert(DST_MATRIX &&LVARRAY_RESTRICT_REF dstMatrix, SRC_MATRIX const &LVARRAY_RESTRICT_REF srcMatrix)
Invert the source matrix srcMatrix and store the result in dstMatrix.
Definition: fixedSizeSquareMatrixOps.hpp:53
LVARRAY_HOST_DEVICE static CONSTEXPR_WITHOUT_BOUNDS_CHECK void Rij_eq_AikSymBklAjl(DST_SYM_MATRIX &&LVARRAY_RESTRICT_REF dstSymMatrix, MATRIX_A const &LVARRAY_RESTRICT_REF matrixA, SYM_MATRIX_B const &LVARRAY_RESTRICT_REF symMatrixB)
Multiply the transpose of matrix matrixA by the symmetric matrix symMatrixB then by matrixA and store...
Definition: fixedSizeSquareMatrixOpsImpl.hpp:867
LVARRAY_HOST_DEVICE CONSTEXPR_WITHOUT_BOUNDS_CHECK auto symDeterminant(SYM_MATRIX const &symMatrix)
Definition: fixedSizeSquareMatrixOps.hpp:229
LVARRAY_HOST_DEVICE float acos(float const x)
Definition: math.hpp:888
LVARRAY_HOST_DEVICE static CONSTEXPR_WITHOUT_BOUNDS_CHECK void Rij_eq_symAikBjk(DST_MATRIX &&LVARRAY_RESTRICT_REF dstMatrix, SYM_MATRIX_A const &LVARRAY_RESTRICT_REF symMatrixA, MATRIX_B const &LVARRAY_RESTRICT_REF matrixB)
Multiply the transpose of matrix matrixB by the symmetric matrix symMatrixA and store the result in d...
Definition: fixedSizeSquareMatrixOpsImpl.hpp:813
#define LVARRAY_TENSOROPS_ASSIGN_3x3(var, exp00, exp01, exp02, exp10, exp11, exp12, exp20, exp21, exp22)
Assign to the 3x3 matrix var.
Definition: genericTensorOps.hpp:137
LVARRAY_HOST_DEVICE static CONSTEXPR_WITHOUT_BOUNDS_CHECK void symmetricToDense(DST_MATRIX &&dstMatrix, SRC_SYM_MATRIX const &srcSymMatrix)
Convert the srcSymMatrix into a dense matrix.
Definition: fixedSizeSquareMatrixOpsImpl.hpp:520
Contains the implementation of arbitrary sized vector and matrix operations.
#define CONSTEXPR_WITHOUT_BOUNDS_CHECK
Expands to constexpr when array bound checking is disabled.
Definition: Macros.hpp:609
LVARRAY_HOST_DEVICE static CONSTEXPR_WITHOUT_BOUNDS_CHECK void Ri_add_symAijBj(DST_VECTOR &&LVARRAY_RESTRICT_REF dstVector, SYM_MATRIX_A const &LVARRAY_RESTRICT_REF symMatrixA, VECTOR_B const &LVARRAY_RESTRICT_REF vectorB)
Multiply the vector vectorB by the symmetric matrix symMatrixA and add the result to dstVector...
Definition: fixedSizeSquareMatrixOpsImpl.hpp:252
LVARRAY_HOST_DEVICE static CONSTEXPR_WITHOUT_BOUNDS_CHECK void symmetricToDense(DST_MATRIX &&dstMatrix, SRC_SYM_MATRIX const &srcSymMatrix)
Convert the srcSymMatrix into a dense matrix.
Definition: fixedSizeSquareMatrixOpsImpl.hpp:1147
LVARRAY_HOST_DEVICE static CONSTEXPR_WITHOUT_BOUNDS_CHECK auto symInvert(SYM_MATRIX &&symMatrix)
Invert the symmetric matrix symMatrix overwritting it.
Definition: fixedSizeSquareMatrixOpsImpl.hpp:200
LVARRAY_HOST_DEVICE static CONSTEXPR_WITHOUT_BOUNDS_CHECK auto determinant(MATRIX const &matrix)
Definition: fixedSizeSquareMatrixOpsImpl.hpp:573
LVARRAY_HOST_DEVICE static CONSTEXPR_WITHOUT_BOUNDS_CHECK auto symInvert(DST_SYM_MATRIX &&LVARRAY_RESTRICT_REF dstSymMatrix, SRC_SYM_MATRIX const &LVARRAY_RESTRICT_REF srcSymMatrix)
Invert the symmetric matrix srcSymMatrix and store the result in dstSymMatrix.
Definition: fixedSizeSquareMatrixOpsImpl.hpp:173
LVARRAY_HOST_DEVICE void sincos(float const theta, float &sinTheta, float &cosTheta)
Compute the sine and cosine of theta.
Definition: math.hpp:636
LVARRAY_HOST_DEVICE static constexpr auto invert(MATRIX &&matrix)
Invert the matrix srcMatrix overwritting it.
Definition: fixedSizeSquareMatrixOpsImpl.hpp:632
LVARRAY_HOST_DEVICE static CONSTEXPR_WITHOUT_BOUNDS_CHECK auto invert(DST_MATRIX &&LVARRAY_RESTRICT_REF dstMatrix, SRC_MATRIX const &LVARRAY_RESTRICT_REF srcMatrix)
Invert the source matrix srcMatrix and store the result in dstMatrix.
Definition: fixedSizeSquareMatrixOpsImpl.hpp:593
LVARRAY_HOST_DEVICE static CONSTEXPR_WITHOUT_BOUNDS_CHECK void Rij_eq_AikSymBklAjl(DST_SYM_MATRIX &&LVARRAY_RESTRICT_REF dstSymMatrix, MATRIX_A const &LVARRAY_RESTRICT_REF matrixA, SYM_MATRIX_B const &LVARRAY_RESTRICT_REF symMatrixB)
Multiply the transpose of matrix matrixA by the symmetric matrix symMatrixB then by matrixA and store...
Definition: fixedSizeSquareMatrixOpsImpl.hpp:307
LVARRAY_HOST_DEVICE float sqrt(float const x)
Definition: math.hpp:461
The top level namespace.
Definition: Array.hpp:24
LVARRAY_HOST_DEVICE CONSTEXPR_WITHOUT_BOUNDS_CHECK void crossProduct(DST_VECTOR &&LVARRAY_RESTRICT_REF dstVector, VECTOR_A const &LVARRAY_RESTRICT_REF vectorA, VECTOR_B const &LVARRAY_RESTRICT_REF vectorB)
Compute the cross product of vectorA and vectorB and put it in dstVector.
Definition: genericTensorOps.hpp:792
LVARRAY_HOST_DEVICE static CONSTEXPR_WITHOUT_BOUNDS_CHECK void symEigenvalues(DST_VECTOR &&LVARRAY_RESTRICT_REF eigenvalues, SYM_MATRIX const &LVARRAY_RESTRICT_REF symMatrix)
Compute the eigenvalues of the symmetric matrix symMatrix.
Definition: fixedSizeSquareMatrixOpsImpl.hpp:1007
LVARRAY_HOST_DEVICE static CONSTEXPR_WITHOUT_BOUNDS_CHECK auto invert(DST_MATRIX &&LVARRAY_RESTRICT_REF dstMatrix, SRC_MATRIX const &LVARRAY_RESTRICT_REF srcMatrix)
Invert the source matrix srcMatrix and store the result in dstMatrix.
Definition: fixedSizeSquareMatrixOpsImpl.hpp:105
LVARRAY_HOST_DEVICE CONSTEXPR_WITHOUT_BOUNDS_CHECK auto determinant(MATRIX const &matrix)
Definition: fixedSizeSquareMatrixOps.hpp:38
LVARRAY_HOST_DEVICE static CONSTEXPR_WITHOUT_BOUNDS_CHECK void symRij_eq_AiBj_plus_AjBi(DST_SYM_MATRIX &&LVARRAY_RESTRICT_REF dstMatrix, VECTOR_A const &LVARRAY_RESTRICT_REF vectorA, VECTOR_B const &LVARRAY_RESTRICT_REF vectorB)
Perform the unscaled symmetric outer product of vectorA and vectorB writing the result to dstMatrix...
Definition: fixedSizeSquareMatrixOpsImpl.hpp:370
LVARRAY_HOST_DEVICE static CONSTEXPR_WITHOUT_BOUNDS_CHECK void symRij_eq_AiAj(DST_MATRIX &&LVARRAY_RESTRICT_REF dstMatrix, VECTOR_A const &LVARRAY_RESTRICT_REF vectorA)
Perform the outer product of vectorA with itself writing the result to dstMatrix. ...
Definition: fixedSizeSquareMatrixOpsImpl.hpp:346
A wrapper for the std::numeric_limits< T > member functions, this allows their values to be used on d...
Definition: limits.hpp:36
LVARRAY_HOST_DEVICE constexpr T abs(T const x)
Definition: math.hpp:402
LVARRAY_HOST_DEVICE static CONSTEXPR_WITHOUT_BOUNDS_CHECK void symRij_eq_AiAj(DST_MATRIX &&LVARRAY_RESTRICT_REF dstMatrix, VECTOR_A const &LVARRAY_RESTRICT_REF vectorA)
Perform the outer product of vectorA with itself writing the result to dstMatrix. ...
Definition: fixedSizeSquareMatrixOpsImpl.hpp:953
LVARRAY_HOST_DEVICE static CONSTEXPR_WITHOUT_BOUNDS_CHECK void Ri_eq_symAijBj(DST_VECTOR &&LVARRAY_RESTRICT_REF dstVector, SYM_MATRIX_A const &LVARRAY_RESTRICT_REF symMatrixA, VECTOR_B const &LVARRAY_RESTRICT_REF vectorB)
Multiply the vector vectorB by the symmetric matrix symMatrixA and store the result in dstVector...
Definition: fixedSizeSquareMatrixOpsImpl.hpp:747
static LVARRAY_HOST_DEVICE void eigenvaluesOfShiftedMatrix(VECTOR &&eigenvalues, FloatingPoint const (&matrix)[3])
Compute the eigenvalues of the 2x2 symmetric matrix matrix.
Definition: fixedSizeSquareMatrixOpsImpl.hpp:543
LVARRAY_HOST_DEVICE static CONSTEXPR_WITHOUT_BOUNDS_CHECK void symRij_eq_AiBj_plus_AjBi(DST_SYM_MATRIX &&LVARRAY_RESTRICT_REF dstMatrix, VECTOR_A const &LVARRAY_RESTRICT_REF vectorA, VECTOR_B const &LVARRAY_RESTRICT_REF vectorB)
Perform the unscaled symmetric outer product of vectorA and vectorB writing the result to dstMatrix...
Definition: fixedSizeSquareMatrixOpsImpl.hpp:980
LVARRAY_HOST_DEVICE float invSqrt(float const x)
Definition: math.hpp:503
LVARRAY_HOST_DEVICE static CONSTEXPR_WITHOUT_BOUNDS_CHECK void Ri_eq_symAijBj(DST_VECTOR &&LVARRAY_RESTRICT_REF dstVector, SYM_MATRIX_A const &LVARRAY_RESTRICT_REF symMatrixA, VECTOR_B const &LVARRAY_RESTRICT_REF vectorB)
Multiply the vector vectorB by the symmetric matrix symMatrixA and store the result in dstVector...
Definition: fixedSizeSquareMatrixOpsImpl.hpp:228
LVARRAY_HOST_DEVICE static CONSTEXPR_WITHOUT_BOUNDS_CHECK auto determinant(MATRIX const &matrix)
Definition: fixedSizeSquareMatrixOpsImpl.hpp:88
LVARRAY_HOST_DEVICE static CONSTEXPR_WITHOUT_BOUNDS_CHECK void denseToSymmetric(DST_SYM_MATRIX &&dstSymMatrix, SRC_MATRIX const &srcMatrix)
Convert the upper triangular part of srcMatrix to a symmetric matrix.
Definition: fixedSizeSquareMatrixOpsImpl.hpp:501
#define LVARRAY_TENSOROPS_ASSIGN_2x2(var, exp00, exp01, exp10, exp11)
Assign to the 2x2 matrix var.
Definition: genericTensorOps.hpp:111
LVARRAY_HOST_DEVICE CONSTEXPR_WITHOUT_BOUNDS_CHECK auto symInvert(DST_SYM_MATRIX &&LVARRAY_RESTRICT_REF dstSymMatrix, SRC_SYM_MATRIX const &LVARRAY_RESTRICT_REF srcSymMatrix)
Invert the symmetric matrix srcSymMatrix and store the result in dstSymMatrix.
Definition: fixedSizeSquareMatrixOps.hpp:244
LVARRAY_HOST_DEVICE static CONSTEXPR_WITHOUT_BOUNDS_CHECK void Ri_add_symAijBj(DST_VECTOR &&LVARRAY_RESTRICT_REF dstVector, SYM_MATRIX_A const &LVARRAY_RESTRICT_REF symMatrixA, VECTOR_B const &LVARRAY_RESTRICT_REF vectorB)
Multiply the vector vectorB by the symmetric matrix symMatrixA and add the result to dstVector...
Definition: fixedSizeSquareMatrixOpsImpl.hpp:778
#define LVARRAY_HOST_DEVICE
Mark a function for both host and device usage.
Definition: Macros.hpp:549
LVARRAY_HOST_DEVICE static CONSTEXPR_WITHOUT_BOUNDS_CHECK void Rij_eq_symAikBjk(DST_MATRIX &&LVARRAY_RESTRICT_REF dstMatrix, SYM_MATRIX_A const &LVARRAY_RESTRICT_REF symMatrixA, MATRIX_B const &LVARRAY_RESTRICT_REF matrixB)
Multiply the transpose of matrix matrixB by the symmetric matrix symMatrixA and store the result in d...
Definition: fixedSizeSquareMatrixOpsImpl.hpp:277
LVARRAY_HOST_DEVICE static CONSTEXPR_WITHOUT_BOUNDS_CHECK void denseToSymmetric(DST_SYM_MATRIX &&dstSymMatrix, SRC_MATRIX const &srcMatrix)
Convert the upper triangular part of srcMatrix to a symmetric matrix.
Definition: fixedSizeSquareMatrixOpsImpl.hpp:1125