/*========================================================================= Program: Tensor ToolKit - TTK Module: $URL$ Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) INRIA 2010. All rights reserved. See LICENSE.txt for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef _itkTensor_txx #define _itkTensor_txx #include "itkTensor.h" #include #include "vnl/vnl_vector.h" #include "vnl/vnl_trace.h" #include "vnl/algo/vnl_determinant.h" #include "itkObject.h" #include #include "ttkConfigure.h" #ifdef TTK_USE_MKL #include #else #ifdef TTK_USE_ACML #include #else #include #endif #endif namespace itk { /** Constructor */ template Tensor ::Tensor (const ValueType& r) { for(typename BaseArray::Iterator i = BaseArray::Begin(); i!=BaseArray::End(); i++) { *i = static_cast(0.0); } for( unsigned int i=0; i Tensor ::Tensor (const VectorType& v) { for( unsigned int nc=0; ncSetComponent(nl, nc, v[nl]*v[nc]); } } template Tensor& Tensor ::operator=(const Self& r) { BaseArray::operator=(r); return *this; } template Tensor& Tensor ::operator=(const ValueType r[NDegreesOfFreedom]) { BaseArray::operator=(r); return *this; } template const Tensor& Tensor ::operator*=(const ValueType &value) { for( unsigned int i=0; i const Tensor& Tensor ::operator/=(const ValueType &value) { for( unsigned int i=0; i const Tensor& Tensor ::operator+=(const Self &t) { for( unsigned int i=0; i const Tensor& Tensor ::operator-=(const Self &t) { for( unsigned int i=0; i Tensor Tensor ::operator+(const Self &t) const { Self result; for( unsigned int i=0; i Tensor Tensor ::operator-(const Self &t) const { Self result; for( unsigned int i=0; i typename Tensor::Self Tensor ::operator*(const Self &t) const { Self res; res.SetVnlMatrix ( this->GetVnlMatrix() * t.GetVnlMatrix() ); return res; //return this->ScalarProductWith (t); } template Tensor Tensor ::operator*(const ValueType& v) const { Self result; for( unsigned int i=0; i typename Tensor::VectorType Tensor ::operator*(const VectorType& v) const { VectorType result; for( unsigned int i=0; iGetComponent(i,j)*v[j]; } return result; } template Tensor Tensor ::operator/(const ValueType& v) const { Self result; for( unsigned int i=0; i typename Tensor::RealValueType Tensor ::GetSquaredNorm() const { typename NumericTraits::AccumulateType sum = NumericTraits::Zero; // diagonal elements: for( unsigned int j=0; jGetNthComponent (j*(j+1)/2 + j); sum += value*value; } // off-diagonal elements for( unsigned int j=1; jGetComponent (i,j); sum += 2.0*value*value; } } return sum; } template typename Tensor::RealValueType Tensor ::GetNorm() const { return RealValueType( std::sqrt( double(this->GetSquaredNorm()) )); } template void Tensor ::SetComponent (int i, int j, const ComponentType &v) { if( i < j ) this->SetNthComponent(j*(j+1)/2+i,v); else this->SetNthComponent (i*(i+1)/2+j,v); } template typename Tensor::ValueType Tensor ::GetComponent (int i, int j) const { if(j>i) return (*this)[j*(j+1)/2+i]; else return (*this)[i*(i+1)/2+j]; } template void Tensor ::SetVnlMatrix( const vnl_matrix & mat) { for(unsigned int j=0;j vnl_matrix Tensor ::GetVnlMatrix() const { T* block = new T[NDimension*NDimension]; for(unsigned int j=0;jGetComponent (i,j); } vnl_matrix< T > result = vnl_matrix< T >(block, NDimension, NDimension); delete [] block; return result; } template Tensor Tensor ::Log () const { if (!this->IsFinite()) { throw ExceptionObject (__FILE__,__LINE__,"Tensor is not finite"); } Self result; #if defined (TTK_USE_MKL) || defined (TTK_USE_ACML) char job = 'V'; char uplo = 'U'; double *ev = new double[NDimension]; double *work = new double[NDimension*NDimension]; int ldz = NDimension; double *z = new double[NDimension*NDimension]; int info = 0; int order = NDimension; // need to copy double *buffer = new double[NDegreesOfFreedom]; for(unsigned int i=0;i((*this)[i]); #ifdef TTK_USE_MKL dspev(&job,&uplo,&order,buffer,ev,z,&ldz,work,&info); #else // ACML dspev(job,uplo,order,buffer,ev,z,ldz,&info); #endif // logarithm of the eigenvalues: for(unsigned int i=0;i(res); } } // free the buffers delete [] ev; delete [] work; delete [] z; delete [] buffer; #else typedef vnl_symmetric_eigensystem< T > SymEigenSystemType; SymEigenSystemType eig (this->GetVnlMatrix()); for(unsigned int i=0;i Tensor Tensor ::Exp () const { if (!this->IsFinite()) { throw ExceptionObject (__FILE__,__LINE__,"Tensor is not finite"); } Self result; #if defined (TTK_USE_MKL) || defined (TTK_USE_ACML) char job = 'V'; char uplo = 'U'; double *ev = new double[NDimension]; double *work = new double[NDimension*NDimension]; int ldz = NDimension; double *z = new double[NDimension*NDimension]; int info = 0; int order = NDimension; // need to copy double *buffer = new double[NDegreesOfFreedom]; for(unsigned int i=0;i((*this)[i]); #ifdef TTK_USE_MKL dspev(&job,&uplo,&order,buffer,ev,z,&ldz,work,&info); #else // ACML dspev(job,uplo,order,buffer,ev,z,ldz,&info); #endif // exponential of the eigenvalues: for(unsigned int i=0;i(res); } } // free the buffers delete [] ev; delete [] work; delete [] z; delete [] buffer; #else typedef vnl_symmetric_eigensystem< T > SymEigenSystemType; SymEigenSystemType eig(this->GetVnlMatrix()); for(unsigned int i=0;i Tensor Tensor ::Pow (double n) const { if (!this->IsFinite()) { throw ExceptionObject (__FILE__,__LINE__,"Tensor is not finite"); } Self result; #if defined (TTK_USE_MKL) || defined (TTK_USE_ACML) char job = 'V'; char uplo = 'U'; double *ev = new double[NDimension]; double *work = new double[NDimension*NDimension]; int ldz = NDimension; double *z = new double[NDimension*NDimension]; int info = 0; int order = NDimension; // need to copy double *buffer = new double[NDegreesOfFreedom]; for(unsigned int i=0;i((*this)[i]); #ifdef TTK_USE_MKL dspev(&job,&uplo,&order,buffer,ev,z,&ldz,work,&info); #else // ACML dspev(job,uplo,order,buffer,ev,z,ldz,&info); #endif // power of the eigenvalues: for(unsigned int i=0;i(res); } } // free the buffers delete [] ev; delete [] work; delete [] z; delete [] buffer; #else typedef vnl_symmetric_eigensystem< T > SymEigenSystemType; SymEigenSystemType eig (this->GetVnlMatrix()); for(unsigned int i=0;i (std::pow (static_cast(eig.D[i]), n)); result.SetVnlMatrix ( eig.recompose() ); #endif return result; } template Tensor Tensor ::Inv () const { return this->Pow (-1.0); } template Tensor Tensor ::Sqrt () const { return this->Pow (0.5); } template Tensor Tensor ::InvSqrt () const { return this->Pow (-0.5); } template T Tensor ::GetEigenvalue (unsigned int n) const { if (!this->IsFinite()) { throw ExceptionObject (__FILE__,__LINE__,"Tensor is not finite"); } T result; #if defined (TTK_USE_MKL) || defined (TTK_USE_ACML) char job = 'V'; char uplo = 'U'; double *ev = new double[NDimension]; double *work = new double[NDimension*NDimension]; int ldz = NDimension; double *z = new double[NDimension*NDimension]; int info = 0; int order = NDimension; // need to copy double *buffer = new double[NDegreesOfFreedom]; for(unsigned int i=0;i((*this)[i]); #ifdef TTK_USE_MKL dspev(&job,&uplo,&order,buffer,ev,z,&ldz,work,&info); #else // ACML dspev(job,uplo,order,buffer,ev,z,ldz,&info); #endif result = static_cast(ev[n]); // free the buffers delete [] ev; delete [] work; delete [] z; delete [] buffer; #else typedef vnl_symmetric_eigensystem< T > SymEigenSystemType; SymEigenSystemType eig (this->GetVnlMatrix()); result = eig.D[n]; #endif return result; } template typename Tensor::VectorType Tensor ::GetEigenvector (unsigned int n) const { if (!this->IsFinite()) { throw ExceptionObject (__FILE__,__LINE__,"Tensor is not finite"); } VectorType result; #if defined (TTK_USE_MKL) || defined (TTK_USE_ACML) char job = 'V'; char uplo = 'U'; double *ev = new double[NDimension]; double *work = new double[NDimension*NDimension]; int ldz = NDimension; double *z = new double[NDimension*NDimension]; int info = 0; int order = NDimension; // need to copy double *buffer = new double[NDegreesOfFreedom]; for(unsigned int i=0;i((*this)[i]); #ifdef TTK_USE_MKL dspev(&job,&uplo,&order,buffer,ev,z,&ldz,work,&info); #else // ACML dspev(job,uplo,order,buffer,ev,z,ldz,&info); #endif for(unsigned int i=0;i SymEigenSystemType; SymEigenSystemType eig (this->GetVnlMatrix()); for(unsigned int i=0;i T Tensor ::GetDeterminant () const { T result; vnl_matrix< T > M = this->GetVnlMatrix(); result = vnl_determinant( M ); return result; } template bool Tensor ::IsZero () const { for(typename BaseArray::ConstIterator i = BaseArray::Begin(); i!=BaseArray::End(); i++) if( (*i) != NumericTraits::Zero ) return false; return true; } template bool Tensor ::IsPositive () const { if (!this->IsFinite()) { throw ExceptionObject (__FILE__,__LINE__,"Tensor is not finite"); } bool result = true; #if defined (TTK_USE_MKL) || defined (TTK_USE_ACML) char job = 'V'; char uplo = 'U'; double *ev = new double[NDimension]; double *work = new double[NDimension*NDimension]; int ldz = NDimension; double *z = new double[NDimension*NDimension]; int info = 0; int order = NDimension; // need to copy double *buffer = new double[NDegreesOfFreedom]; for(unsigned int i=0;i((*this)[i]); #ifdef TTK_USE_MKL dspev(&job,&uplo,&order,buffer,ev,z,&ldz,work,&info); #else // ACML dspev(job,uplo,order,buffer,ev,z,ldz,&info); #endif if( ev[0] <= NumericTraits::Zero ) result = false; // free the buffers delete [] ev; delete [] work; delete [] z; delete [] buffer; #else using SymEigenSystemType = vnl_symmetric_eigensystem< T >; SymEigenSystemType eig (this->GetVnlMatrix()); if( eig.D[0] <= NumericTraits::Zero ) result = false; #endif return result; } template bool Tensor ::IsNegative () const { if (!this->IsFinite()) { throw ExceptionObject (__FILE__,__LINE__,"Tensor is not finite"); } bool result = true; #if defined (TTK_USE_MKL) || defined (TTK_USE_ACML) char job = 'V'; char uplo = 'U'; double *ev = new double[NDimension]; double *work = new double[NDimension*NDimension]; int ldz = NDimension; double *z = new double[NDimension*NDimension]; int info = 0; int order = NDimension; // need to copy double *buffer = new double[NDegreesOfFreedom]; for(unsigned int i=0;i((*this)[i]); #ifdef TTK_USE_MKL dspev(&job,&uplo,&order,buffer,ev,z,&ldz,work,&info); #else // ACML dspev(job,uplo,order,buffer,ev,z,ldz,&info); #endif if( ev[0] >= NumericTraits::Zero ) result = false; // free the buffers delete [] ev; delete [] work; delete [] z; delete [] buffer; #else using SymEigenSystemType = vnl_symmetric_eigensystem< T >; SymEigenSystemType eig (this->GetVnlMatrix()); if( eig.D[0] <= NumericTraits::Zero ) result = false; #endif return result; } template bool Tensor ::IsFinite () const { return this->GetVnlMatrix().is_finite(); } template bool Tensor ::HasNans () const { return this->GetVnlMatrix().has_nans(); } template typename Tensor::ValueType Tensor ::ScalarProductWith (const Self& W) const { // compute trace (This * W): // trace(A.B) = Sum_i ( [A.B]_ii ) = Sum_i Sum_k ( a_ik * b_ki ) ValueType res = static_cast( 0.0 ); for(unsigned int i=0; iGetComponent(i,k) * W.GetComponent(k,i); } return res; } template typename Tensor::ValueType Tensor ::ScalarProductWith (const VectorType& v) const { return this->ScalarProductWith ( Self (v) ); } template typename Tensor::ValueType Tensor ::GetTrace () const { ValueType res = static_cast(0.0); for ( unsigned int i=0;iGetNthComponent ( i*(i+3) / 2 ); return res; } template typename Tensor::ValueType Tensor ::GetFA () const { vnl_matrix M = this->GetVnlMatrix(); ValueType t = vnl_trace(M); ValueType t2 = vnl_trace(M*M); ValueType tmp = (t*t)/(3.0*t2); if(tmp>1.0) tmp = 1.0; ValueType fa = static_cast ( std::sqrt ( 1.5* ( 1.0 - tmp )) ); return fa; } template typename Tensor::ValueType Tensor ::GetGA () const { vnl_matrix L = this->GetVnlMatrix(); ValueType lt = vnl_trace(L) / static_cast(NDimension); Self eye; vnl_matrix EYE = eye.GetVnlMatrix(); EYE.set_identity(); vnl_matrix TOT = lt*lt*EYE + L*L - lt*static_cast(2.0)*L; ValueType ga = static_cast( std::sqrt ( vnl_trace (TOT) ) ); return ga; } template typename Tensor::ValueType Tensor ::GetRA () const { vnl_matrix M = this->GetVnlMatrix(); ValueType t = vnl_trace(M); ValueType t2 = vnl_trace(M*M); ValueType ra = static_cast( std::sqrt ( t2/t - t/3.0 ) ); return ra; } template typename Tensor::ValueType Tensor ::GetVR () const { ValueType n = 1.0; ValueType d = 0.0; for( unsigned int i=0; iGetEigenvalue( i ); n *= l; d += l; } return n/(d*d*d); } template Tensor Tensor ::DifferentialExp (const Self& G) const { if (!this->IsFinite()) { throw ExceptionObject (__FILE__,__LINE__,"Tensor is not finite"); } Self Result; #if defined (TTK_USE_MKL) || defined (TTK_USE_ACML) char job = 'V'; char uplo = 'U'; double *ev = new double[NDimension]; double *work = new double[NDimension*NDimension]; int ldz = NDimension; double *z = new double[NDimension*NDimension]; int info = 0; int order = NDimension; // need to copy double *buffer = new double[NDegreesOfFreedom]; for(unsigned int i=0;i((*this)[i]); #ifdef TTK_USE_MKL dspev(&job,&uplo,&order,buffer,ev,z,&ldz,work,&info); #else // ACML dspev(job,uplo,order,buffer,ev,z,ldz,&info); #endif vnl_matrix R (z, NDimension, NDimension); vnl_matrix TMP1 = R * G.GetVnlMatrix() *R.transpose(); vnl_matrix TMP2 (NDimension, NDimension); for( unsigned int nc=0; nc( sx (ev[nl],ev[nc]) ) * TMP1(nl,nc); } TMP2 = R.transpose() * TMP2 * R; Result.SetVnlMatrix (TMP2); // free the buffers delete [] ev; delete [] work; delete [] z; delete [] buffer; #else typedef vnl_symmetric_eigensystem< T > SymEigenSystemType; SymEigenSystemType eig (this->GetVnlMatrix()); vnl_matrix R = eig.V; vnl_matrix TMP1 = R.transpose() * G.GetVnlMatrix() * R; vnl_matrix TMP2 (NDimension, NDimension); for( unsigned int nc=0; nc( sx (eig.D[nl],eig.D[nc]) ) * TMP1(nl,nc); } TMP2 = R.transpose() * TMP2 * R; Result.SetVnlMatrix (TMP2); #endif return Result; } template double Tensor ::sx (const double& s1, const double& s2) const { double s = 0.0; double diff = static_cast( s1-s2 ); double EPS = 0.00001; if( fabs ( diff ) < EPS ) s = std::exp (s1)*(1 + diff/2.0 + diff*diff/6.0 ); else s = ( std::exp (s1) - std::exp (s2) )/(s1 - s2); return s; } template void Tensor ::SetNthComponentAsVector ( int c, const ComponentType& v ) { ValueType factor = 1.0/std::sqrt (2.0); for( unsigned int i=0;ioperator[](c) = v*factor; } template typename Tensor::ValueType Tensor ::GetNthComponentAsVector ( int c ) const { ValueType factor = std::sqrt (2.0); for( unsigned int i=0;ioperator[](c)*factor; } template Tensor Tensor ::ApplyMatrix (const MatrixType& R) const { Self res; auto matrix = this->ApplyMatrix(static_cast>(R.GetVnlMatrix())); res.SetVnlMatrix(matrix.as_ref()); return res; } template vnl_matrix Tensor ::ApplyMatrix (const vnl_matrix & R) const { vnl_matrix res; res = ( R*(this->GetVnlMatrix())*R.transpose() ); return res; } template typename Tensor::ValueType Tensor ::GetCl () const { ValueType l1 = this->GetEigenvalue( Dimension - 1 ); ValueType l2 = this->GetEigenvalue( Dimension - 2 ); return (l1-l2)/this->GetTrace(); } template typename Tensor::ValueType Tensor ::GetCp () const { ValueType l2 = this->GetEigenvalue( Dimension - 2 ); ValueType l3 = this->GetEigenvalue( Dimension - 3 ); return 2.0*(l2-l3)/this->GetTrace(); } template typename Tensor::ValueType Tensor ::GetCs () const { ValueType l3 = this->GetEigenvalue( Dimension - 3 ); return 3.0*l3/this->GetTrace(); } } // end of namespace itk #endif