24 #ifndef MOAB_MATRIX3_HPP
25 #define MOAB_MATRIX3_HPP
41 #ifdef MOAB_HAVE_EIGEN3
45 #pragma GCC diagnostic push
47 #pragma GCC diagnostic ignored "-Wshadow"
50 #define EIGEN_DEFAULT_TO_ROW_MAJOR
51 #define EIGEN_INITIALIZE_MATRICES_BY_ZERO
53 #include "Eigen/Dense"
57 #pragma GCC diagnostic pop
62 #ifdef MOAB_HAVE_LAPACK
64 #if defined( MOAB_FC_FUNC_ )
65 #define MOAB_FC_WRAPPER MOAB_FC_FUNC_
66 #elif defined( MOAB_FC_FUNC )
67 #define MOAB_FC_WRAPPER MOAB_FC_FUNC
69 #define MOAB_FC_WRAPPER( name, NAME ) name##_
78 #define MOAB_dsyevd MOAB_FC_FUNC( dsyevd, DSYEVD )
79 #define MOAB_dgeev MOAB_FC_FUNC( dgeev, DGEEV )
83 #define MOAB_dsyevd MOAB_FC_WRAPPER( dsyevd, DSYEVD )
84 #define MOAB_dgeev MOAB_FC_WRAPPER( dgeev, DGEEV )
93 void MOAB_dsyevd(
char* jobz,
107 void MOAB_dgeev(
char* jobvl,
125 #define MOAB_DMEMZERO( a, b ) memset( a, 0, ( b ) * sizeof( double ) )
132 template <
typename Matrix >
133 inline Matrix
mmult3(
const Matrix& a,
const Matrix& b )
135 return Matrix( a( 0, 0 ) * b( 0, 0 ) + a( 0, 1 ) * b( 1, 0 ) + a( 0, 2 ) * b( 2, 0 ),
136 a( 0, 0 ) * b( 0, 1 ) + a( 0, 1 ) * b( 1, 1 ) + a( 0, 2 ) * b( 2, 1 ),
137 a( 0, 0 ) * b( 0, 2 ) + a( 0, 1 ) * b( 1, 2 ) + a( 0, 2 ) * b( 2, 2 ),
138 a( 1, 0 ) * b( 0, 0 ) + a( 1, 1 ) * b( 1, 0 ) + a( 1, 2 ) * b( 2, 0 ),
139 a( 1, 0 ) * b( 0, 1 ) + a( 1, 1 ) * b( 1, 1 ) + a( 1, 2 ) * b( 2, 1 ),
140 a( 1, 0 ) * b( 0, 2 ) + a( 1, 1 ) * b( 1, 2 ) + a( 1, 2 ) * b( 2, 2 ),
141 a( 2, 0 ) * b( 0, 0 ) + a( 2, 1 ) * b( 1, 0 ) + a( 2, 2 ) * b( 2, 0 ),
142 a( 2, 0 ) * b( 0, 1 ) + a( 2, 1 ) * b( 1, 1 ) + a( 2, 2 ) * b( 2, 1 ),
143 a( 2, 0 ) * b( 0, 2 ) + a( 2, 1 ) * b( 1, 2 ) + a( 2, 2 ) * b( 2, 2 ) );
146 template <
typename Matrix >
147 inline const Matrix
inverse(
const Matrix& d )
149 const double det = 1.0 / determinant3( d );
153 template <
typename Vector,
typename Matrix >
156 return Vector( v[0] * m( 0, 0 ) + v[1] * m( 1, 0 ) + v[2] * m( 2, 0 ),
157 v[0] * m( 0, 1 ) + v[1] * m( 1, 1 ) + v[2] * m( 2, 1 ),
158 v[0] * m( 0, 2 ) + v[1] * m( 1, 2 ) + v[2] * m( 2, 2 ) );
161 template <
typename Vector,
typename Matrix >
165 res[0] = v[0] * m( 0, 0 ) + v[1] * m( 0, 1 ) + v[2] * m( 0, 2 );
166 res[1] = v[0] * m( 1, 0 ) + v[1] * m( 1, 1 ) + v[2] * m( 1, 2 );
167 res[2] = v[0] * m( 2, 0 ) + v[1] * m( 2, 1 ) + v[2] * m( 2, 2 );
179 #ifdef MOAB_HAVE_EIGEN3
180 Eigen::Matrix3d
_mat;
189 #ifdef MOAB_HAVE_EIGEN3
196 #ifdef MOAB_HAVE_EIGEN3
197 inline Matrix3( Eigen::Matrix3d mat ) :
_mat( mat ) {}
204 #ifdef MOAB_HAVE_EIGEN3
214 #ifdef MOAB_HAVE_EIGEN3
231 #ifdef MOAB_HAVE_EIGEN3
251 #ifdef MOAB_HAVE_EIGEN3
252 _mat << v00, v01, v02, v10, v11, v12, v20, v21, v22;
270 #ifdef MOAB_HAVE_EIGEN3
278 template <
typename Vector >
279 inline Matrix3(
const Vector& row0,
const Vector& row1,
const Vector& row2,
const bool isRow )
281 #ifdef MOAB_HAVE_EIGEN3
284 _mat << row0[0], row0[1], row0[2], row1[0], row1[1], row1[2], row2[0], row2[1], row2[2];
288 _mat << row0[0], row1[0], row2[0], row0[1], row1[1], row2[1], row0[2], row1[2], row2[2];
325 #ifdef MOAB_HAVE_EIGEN3
326 _mat << v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8];
328 memcpy(
_mat, v,
size *
sizeof(
double ) );
334 #ifdef MOAB_HAVE_EIGEN3
337 memcpy( v,
_mat,
size *
sizeof(
double ) );
343 #ifdef MOAB_HAVE_EIGEN3
353 #ifdef MOAB_HAVE_EIGEN3
354 _mat << v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8];
356 memcpy(
_mat, v,
size *
sizeof(
double ) );
363 #ifdef MOAB_HAVE_EIGEN3
364 return _mat.row( i ).data();
372 #ifdef MOAB_HAVE_EIGEN3
373 return _mat.row( i ).data();
381 #ifdef MOAB_HAVE_EIGEN3
384 return _mat[r * 3 + c];
390 #ifdef MOAB_HAVE_EIGEN3
393 return _mat[r * 3 + c];
399 #ifdef MOAB_HAVE_EIGEN3
408 #ifdef MOAB_HAVE_EIGEN3
418 #ifdef MOAB_HAVE_EIGEN3
427 #ifdef MOAB_HAVE_EIGEN3
436 #ifdef MOAB_HAVE_EIGEN3
447 #ifdef MOAB_HAVE_EIGEN3
458 #ifdef MOAB_HAVE_EIGEN3
469 #ifdef MOAB_HAVE_EIGEN3
480 #ifdef MOAB_HAVE_EIGEN3
485 std::vector< double > dmat;
502 const double EPS = 1e-14;
503 #ifdef MOAB_HAVE_EIGEN3
518 #ifdef MOAB_HAVE_EIGEN3
523 const double det =
_mat( 6 ) * subdet6 +
_mat( 7 ) * subdet7 +
_mat( 8 ) * subdet8;
524 return _mat( 0 ) > 0 && subdet8 > 0 && det > 0;
530 const double det =
_mat[6] * subdet6 +
_mat[7] * subdet7 +
_mat[8] * subdet8;
531 return _mat[0] > 0 && subdet8 > 0 && det > 0;
535 #ifdef MOAB_HAVE_LAPACK
536 template <
typename Vector >
537 inline ErrorCode eigen_decomposition_lapack(
bool bisSymmetric, Vector& evals,
Matrix3& evecs )
541 double devreal[3], drevecs[9];
544 double devimag[3], dlevecs[9], dwork[102];
545 char dgeev_opts[2] = {
'N',
'V' };
546 int N = 3, LWORK = 102, NL = 1, NR = N;
547 std::vector< double > devmat( 9 );
548 #ifdef MOAB_HAVE_EIGEN3
550 std::copy(
_mat.data(),
_mat.data() +
size, devmat.data() );
552 memcpy( devmat.data(),
_mat,
size *
sizeof(
double ) );
554 MOAB_dgeev( &dgeev_opts[0], &dgeev_opts[1], &N, &devmat[0], &N, devreal, devimag, dlevecs, &NL, drevecs,
555 &NR, dwork, &LWORK, &info );
557 evals[0] = devreal[2];
558 evals[1] = devreal[1];
559 evals[2] = devreal[0];
560 evecs.
_mat[0] = drevecs[6];
561 evecs.
_mat[1] = drevecs[3];
562 evecs.
_mat[2] = drevecs[0];
563 evecs.
_mat[3] = drevecs[7];
564 evecs.
_mat[4] = drevecs[4];
565 evecs.
_mat[5] = drevecs[1];
566 evecs.
_mat[6] = drevecs[8];
567 evecs.
_mat[7] = drevecs[5];
568 evecs.
_mat[8] = drevecs[2];
569 std::cout <<
"DGEEV: Optimal work vector: dsize = " << dwork[0] <<
".\n";
573 char dgeev_opts[2] = {
'V',
'L' };
574 const bool find_optimal =
false;
575 std::vector< int > iwork( 18 );
576 std::vector< double > devmat( 9, 0.0 );
577 std::vector< double > dwork( 38 );
578 int N = 3, lwork = 38, liwork = 18;
589 double query_work_size = 0;
590 int query_iwork_size = 0;
592 MOAB_dsyevd( &dgeev_opts[0], &dgeev_opts[1], &N, NULL, &N, NULL, &query_work_size, &_lwork,
593 &query_iwork_size, &_liwork, &info );
594 lwork = (int)query_work_size;
595 dwork.resize( lwork );
596 liwork = query_iwork_size;
597 iwork.resize( liwork );
598 std::cout <<
"DSYEVD: Optimal work vector: dsize = " << lwork <<
", and isize = " << liwork <<
".\n";
601 MOAB_dsyevd( &dgeev_opts[0], &dgeev_opts[1], &N, &devmat[0], &N, devreal, &dwork[0], &lwork, &iwork[0],
603 for(
int i = 0; i < 9; ++i )
604 drevecs[i] = devmat[i];
606 evals[0] = devreal[0];
607 evals[1] = devreal[1];
608 evals[2] = devreal[2];
609 evecs.
_mat[0] = drevecs[0];
610 evecs.
_mat[3] = drevecs[1];
611 evecs.
_mat[6] = drevecs[2];
612 evecs.
_mat[1] = drevecs[3];
613 evecs.
_mat[4] = drevecs[4];
614 evecs.
_mat[7] = drevecs[5];
615 evecs.
_mat[2] = drevecs[6];
616 evecs.
_mat[5] = drevecs[7];
617 evecs.
_mat[8] = drevecs[8];
626 std::cout <<
"Failure in LAPACK_" << ( bisSymmetric ?
"DSYEVD" :
"DGEEV" )
627 <<
" call for eigen decomposition.\n";
628 std::cout <<
"Failed with error = " << info <<
".\n";
634 template <
typename Vector >
640 MB_CHK_SET_ERR( MB_FAILURE,
"Unsymmetric matrix implementation with Matrix3 are currently not supported." );
642 #if defined( MOAB_HAVE_EIGEN3 )
643 Eigen::SelfAdjointEigenSolver< Eigen::Matrix3d > eigensolver( this->_mat );
644 if( eigensolver.info() != Eigen::Success )
return MB_FAILURE;
645 const Eigen::SelfAdjointEigenSolver< Eigen::Matrix3d >::RealVectorType& e3evals = eigensolver.eigenvalues();
646 evals[0] = e3evals( 0 );
647 evals[1] = e3evals( 1 );
648 evals[2] = e3evals( 2 );
649 evecs.
_mat = eigensolver.eigenvectors();
652 #elif defined( MOAB_HAVE_LAPACK )
653 return eigen_decomposition_lapack( bisSymmetric, evals, evecs );
665 template <
typename Vector >
669 constexpr
double EPSILON = 1e-14;
670 constexpr
int maxiters = 500;
678 double theta, t, c, s;
679 theta = ( A( q, q ) - A( p, p ) ) / ( 2.0 * A( p, q ) );
680 t = ( theta >= 0 ) ? 1.0 / ( theta + std::sqrt( 1.0 + theta * theta ) )
681 : 1.0 / ( theta - std::sqrt( 1.0 + theta * theta ) );
682 c = 1.0 / std::sqrt( 1.0 + t * t );
685 double app = A( p, p ), aqq = A( q, q ), apq = A( p, q );
686 A( p, p ) = c * c * app - 2.0 * c * s * apq + s * s * aqq;
687 A( q, q ) = s * s * app + 2.0 * c * s * apq + c * c * aqq;
688 A( p, q ) = A( q, p ) = 0.0;
691 for(
int i = 0; i < 3; i++ )
693 if( i != p && i != q )
695 double aip = A( i, p ), aiq = A( i, q );
696 A( i, p ) = A( p, i ) = c * aip - s * aiq;
697 A( i, q ) = A( q, i ) = s * aip + c * aiq;
702 for(
int i = 0; i < 3; i++ )
704 double vip = V( i, p ), viq = V( i, q );
705 V( i, p ) = c * vip - s * viq;
706 V( i, q ) = s * vip + c * viq;
712 bool converged =
false;
713 for(
int iter = 0; iter < maxiters; ++iter )
717 double maxOffDiag = std::abs( matrix( p, q ) );
718 for(
int i = 0; i < n; ++i )
720 for(
int j = i + 1; j < n; ++j )
722 if( std::abs( matrix( i, j ) ) > maxOffDiag )
724 maxOffDiag = std::abs( matrix( i, j ) );
739 if( fabs( matrix( p, q ) ) >
EPSILON ) jacobiRotate( matrix, eigenvectors, p, q );
743 for(
int i = 0; i < n; ++i )
746 eigenvalues[i] = matrix( i, i );
753 std::cerr <<
"Jacobi method did not converge within " << maxiters <<
" iterations\n";
758 auto sortIndices = [](
const CartVect& vec ) -> std::array< int, 3 > {
760 std::array< int, 3 > indices = { 0, 1, 2 };
763 std::sort( indices.begin(), indices.end(), [&](
int i,
int j ) { return vec[i] < vec[j]; } );
768 auto newIndices = sortIndices( eigenvalues );
771 CartVect teigenvalues = eigenvalues;
772 Matrix3 teigenvectors = eigenvectors;
773 for(
int i = 0; i < 3; i++ )
775 eigenvalues[i] = teigenvalues[newIndices[i]];
776 eigenvectors( i, 0 ) = teigenvectors( i, newIndices[0] );
777 eigenvectors( i, 1 ) = teigenvectors( i, newIndices[1] );
778 eigenvectors( i, 2 ) = teigenvectors( i, newIndices[2] );
782 return ( converged ?
MB_SUCCESS : MB_FAILURE );
788 return Matrix3( 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0 );
793 #ifdef MOAB_HAVE_EIGEN3
794 _mat.transposeInPlace();
808 #ifdef MOAB_HAVE_EIGEN3
822 template <
typename Vector >
825 #ifdef MOAB_HAVE_EIGEN3
826 _mat.col( index ).swap( vol );
849 inline void swapcol(
int srcindex,
int destindex )
853 #ifdef MOAB_HAVE_EIGEN3
854 _mat.col( srcindex ).swap(
_mat.col( destindex ) );
856 CartVect svol = this->vcol< CartVect >( srcindex );
857 CartVect dvol = this->vcol< CartVect >( destindex );
897 template <
typename Vector >
898 inline Vector
vcol(
int index )
const
901 #ifdef MOAB_HAVE_EIGEN3
902 return _mat.col( index );
913 return Vector( 0.0 );
920 #ifdef MOAB_HAVE_EIGEN3
921 _mat.col( index ) *= scale;
947 #ifdef MOAB_HAVE_EIGEN3
948 _mat.row( index ) *= scale;
974 #ifdef MOAB_HAVE_EIGEN3
975 Eigen::Vector3d mvec =
_mat.col( index );
976 return CartVect( mvec[0], mvec[1], mvec[2] );
994 #ifdef MOAB_HAVE_EIGEN3
995 Eigen::Vector3d mvec =
_mat.row( index );
996 return CartVect( mvec[0], mvec[1], mvec[2] );
1013 #ifdef MOAB_HAVE_EIGEN3
1022 #ifdef MOAB_HAVE_EIGEN3
1023 return _mat.trace();
1035 #ifdef MOAB_HAVE_EIGEN3
1036 return _mat.determinant();
1045 #ifdef MOAB_HAVE_EIGEN3
1050 const double d_determinant = 1.0 / this->
determinant();
1066 bool invertible =
false;
1067 double d_determinant;
1068 #ifdef MOAB_HAVE_EIGEN3
1069 Eigen::Matrix3d invMat;
1070 _mat.computeInverseAndDetWithCheck( invMat, d_determinant, invertible );
1076 if( d_determinant > 1e-13 ) invertible =
true;
1077 d_determinant = 1.0 / d_determinant;
1078 std::vector< double > _m;
1080 _mat[0] = d_determinant * ( _m[4] * _m[8] - _m[5] * _m[7] );
1081 _mat[1] = d_determinant * ( _m[2] * _m[7] - _m[8] * _m[1] );
1082 _mat[2] = d_determinant * ( _m[1] * _m[5] - _m[4] * _m[2] );
1083 _mat[3] = d_determinant * ( _m[5] * _m[6] - _m[8] * _m[3] );
1084 _mat[4] = d_determinant * ( _m[0] * _m[8] - _m[6] * _m[2] );
1085 _mat[5] = d_determinant * ( _m[2] * _m[3] - _m[5] * _m[0] );
1086 _mat[6] = d_determinant * ( _m[3] * _m[7] - _m[6] * _m[4] );
1087 _mat[7] = d_determinant * ( _m[1] * _m[6] - _m[7] * _m[0] );
1088 _mat[8] = d_determinant * ( _m[0] * _m[4] - _m[3] * _m[1] );
1097 assert( r >= 0 && c >= 0 );
1098 if( r < 0 || c < 0 )
return DBL_MAX;
1099 #ifdef MOAB_HAVE_EIGEN3
1100 const int r1 = ( r + 1 ) % 3, r2 = ( r + 2 ) % 3;
1101 const int c1 = ( c + 1 ) % 3, c2 = ( c + 2 ) % 3;
1105 const int c1 = ( c + 1 ) % 3, c2 = ( c + 2 ) % 3;
1110 inline void print( std::ostream& s )
const
1112 #ifdef MOAB_HAVE_EIGEN3
1113 s <<
"| " <<
_mat( 0 ) <<
" " <<
_mat( 1 ) <<
" " <<
_mat( 2 ) <<
" | " <<
_mat( 3 ) <<
" " <<
_mat( 4 ) <<
" "
1114 <<
_mat( 5 ) <<
" | " <<
_mat( 6 ) <<
" " <<
_mat( 7 ) <<
" " <<
_mat( 8 ) <<
" |";
1117 <<
" | " <<
_mat[6] <<
" " <<
_mat[7] <<
" " <<
_mat[8] <<
" |";
1123 template <
typename Vector >
1126 return Matrix3( u[0] * v[0], u[0] * v[1], u[0] * v[2], u[1] * v[0], u[1] * v[1], u[1] * v[2], u[2] * v[0],
1127 u[2] * v[1], u[2] * v[2] );
1132 #ifdef MOAB_HAVE_EIGEN3
1137 s( i ) += b.
_mat[i];
1144 #ifdef MOAB_HAVE_EIGEN3
1149 s( i ) -= b.
_mat[i];
1156 #ifdef MOAB_HAVE_EIGEN3
1163 template <
typename T >
1169 template <
typename T >
1187 #ifdef MOAB_HAVE_LAPACK
1188 #undef MOAB_DMEMZERO
1191 #ifndef MOAB_MATRIX3_OPERATORLESS
1192 #define MOAB_MATRIX3_OPERATORLESS
1195 return s <<
"| " << m( 0, 0 ) <<
" " << m( 0, 1 ) <<
" " << m( 0, 2 ) <<
" | " << m( 1, 0 ) <<
" " << m( 1, 1 )
1196 <<
" " << m( 1, 2 ) <<
" | " << m( 2, 0 ) <<
" " << m( 2, 1 ) <<
" " << m( 2, 2 ) <<
" |";