diff --git a/regtest/basic/rt-make-0/config b/regtest/basic/rt-make-0/config index df1f95bf3e..3e5d21664c 100644 --- a/regtest/basic/rt-make-0/config +++ b/regtest/basic/rt-make-0/config @@ -1 +1,2 @@ type=make +#should we rename this to something meaningful? like "rt-VectorTensor"? diff --git a/regtest/basic/rt-make-4/main.cpp b/regtest/basic/rt-make-4/main.cpp index 86f79df350..84315d99a0 100644 --- a/regtest/basic/rt-make-4/main.cpp +++ b/regtest/basic/rt-make-4/main.cpp @@ -50,7 +50,9 @@ int main () { PLMD::TensorGeneric<4,4> mat; PLMD::TensorGeneric<1,4> evec; PLMD::VectorGeneric<4> eval_underlying; - + + //The both of the two following lines are scary, but on my machine are equivalent + //PLMD::Vector1d* eval=reinterpret_cast(eval_underlying.data()); auto eval = new(&eval_underlying[0]) PLMD::VectorGeneric<1>; mat[1][0]=mat[0][1]=3.0; diff --git a/src/tools/Communicator.h b/src/tools/Communicator.h index 16ef37ddfb..1a2bf02d1c 100644 --- a/src/tools/Communicator.h +++ b/src/tools/Communicator.h @@ -73,13 +73,13 @@ class Communicator { /// Init from reference template explicit Data(T&p): pointer(&p), size(1), nbytes(sizeof(T)), type(getMPIType()) {} /// Init from pointer to VectorGeneric - template explicit Data(VectorGeneric *p,int s): pointer(p), size(n*s), nbytes(sizeof(double)), type(getMPIType()) {} + template explicit Data(VectorTyped *p,int s): pointer(p), size(n*s), nbytes(sizeof(T)), type(getMPIType()) {} /// Init from reference to VectorGeneric - template explicit Data(VectorGeneric &p): pointer(&p), size(n), nbytes(sizeof(double)), type(getMPIType()) {} -/// Init from pointer to TensorGeneric - template explicit Data(TensorGeneric *p,int s): pointer(p), size(n*m*s), nbytes(sizeof(double)), type(getMPIType()) {} -/// Init from reference to TensorGeneric - template explicit Data(TensorGeneric &p): pointer(&p), size(n*m), nbytes(sizeof(double)), type(getMPIType()) {} + template explicit Data(VectorTyped &p): pointer(&p), size(n), nbytes(sizeof(T)), type(getMPIType()) {} +/// Init from pointer to TensorTyped + template explicit Data(TensorTyped *p,int s): pointer(p), size(n*m*s), nbytes(sizeof(T)), type(getMPIType()) {} +/// Init from reference to TensorTyped + template explicit Data(TensorTyped &p): pointer(&p), size(n*m), nbytes(sizeof(T)), type(getMPIType()) {} /// Init from reference to std::vector template explicit Data(std::vector&v) { Data d(v.data(),v.size()); @@ -121,10 +121,10 @@ class Communicator { MPI_Datatype type; template explicit ConstData(const T*p,int s): pointer(p), size(s), nbytes(sizeof(T)), type(getMPIType()) {} template explicit ConstData(const T&p): pointer(&p), size(1), nbytes(sizeof(T)), type(getMPIType()) {} - template explicit ConstData(const VectorGeneric *p,int s): pointer(p), size(n*s), nbytes(sizeof(double)), type(getMPIType()) {} - template explicit ConstData(const VectorGeneric &p): pointer(&p), size(n), nbytes(sizeof(double)), type(getMPIType()) {} - template explicit ConstData(const TensorGeneric *p,int s): pointer(p), size(n*m*s), nbytes(sizeof(double)), type(getMPIType()) {} - template explicit ConstData(const TensorGeneric &p): pointer(&p), size(n*m), nbytes(sizeof(double)), type(getMPIType()) {} + template explicit ConstData(const VectorTyped *p,int s): pointer(p), size(n*s), nbytes(sizeof(T)), type(getMPIType()) {} + template explicit ConstData(const VectorTyped &p): pointer(&p), size(n), nbytes(sizeof(T)), type(getMPIType()) {} + template explicit ConstData(const TensorTyped *p,int s): pointer(p), size(n*m*s), nbytes(sizeof(T)), type(getMPIType()) {} + template explicit ConstData(const TensorTyped &p): pointer(&p), size(n*m), nbytes(sizeof(T)), type(getMPIType()) {} template explicit ConstData(const std::vector&v) { ConstData d(v.data(),v.size()); pointer=d.pointer; diff --git a/src/tools/LoopUnroller.h b/src/tools/LoopUnroller.h index 6d16761da0..ad1308a3cf 100644 --- a/src/tools/LoopUnroller.h +++ b/src/tools/LoopUnroller.h @@ -47,114 +47,89 @@ Implementation is made using template metaprogramming, that is: Here xxx is any of the methods of the class. */ -template +//the typename is the second parameter argument so that it can be deduced +template class LoopUnroller { public: /// Set to zero. /// Same as `for(unsigned i=0;i -void LoopUnroller::_zero(double*d) { - LoopUnroller::_zero(d); - d[n-1]=0.0; +template +constexpr void LoopUnroller::_zero(T*d) { + if constexpr (n>1) { + LoopUnroller::_zero(d); + } + d[n-1]=T(0); } -template<> -inline -void LoopUnroller<1>::_zero(double*d) { - d[0]=0.0; -} - -template -void LoopUnroller::_add(double*d,const double*a) { - LoopUnroller::_add(d,a); +template +constexpr void LoopUnroller::_add(T*d,const T*a) { + if constexpr (n>1) { + LoopUnroller::_add(d,a); + } d[n-1]+=a[n-1]; } -template<> -inline -void LoopUnroller<1>::_add(double*d,const double*a) { - d[0]+=a[0]; -} - -template -void LoopUnroller::_sub(double*d,const double*a) { - LoopUnroller::_sub(d,a); +template +constexpr void LoopUnroller::_sub(T*d,const T*a) { + if constexpr (n>1) { + LoopUnroller::_sub(d,a); + } d[n-1]-=a[n-1]; } -template<> -inline -void LoopUnroller<1>::_sub(double*d,const double*a) { - d[0]-=a[0]; -} - -template -void LoopUnroller::_mul(double*d,const double s) { - LoopUnroller::_mul(d,s); +template +constexpr void LoopUnroller::_mul(T*d,const T s) { + if constexpr (n>1) { + LoopUnroller::_mul(d,s); + } d[n-1]*=s; } -template<> -inline -void LoopUnroller<1>::_mul(double*d,const double s) { - d[0]*=s; -} - -template -void LoopUnroller::_neg(double*d,const double*a ) { - LoopUnroller::_neg(d,a); +template +constexpr void LoopUnroller::_neg(T*d,const T*a ) { + if constexpr (n>1) { + LoopUnroller::_neg(d,a); + } d[n-1]=-a[n-1]; } -template<> -inline -void LoopUnroller<1>::_neg(double*d,const double*a) { - d[0]=-a[0]; +template +constexpr T LoopUnroller::_sum2(const T*d) { + if constexpr (n>1) { + return LoopUnroller::_sum2(d)+d[n-1]*d[n-1]; + } else { + return d[0]*d[0]; + } } - -template -double LoopUnroller::_sum2(const double*d) { - return LoopUnroller::_sum2(d)+d[n-1]*d[n-1]; -} - -template<> -inline -double LoopUnroller<1>::_sum2(const double*d) { - return d[0]*d[0]; -} - -template -double LoopUnroller::_dot(const double*d,const double*v) { - return LoopUnroller::_dot(d,v)+d[n-1]*v[n-1]; -} - -template<> -inline -double LoopUnroller<1>::_dot(const double*d,const double*v) { - return d[0]*v[0]; -} - +template +constexpr T LoopUnroller::_dot(const T*d,const T*v) { + if constexpr (n>1) { + return LoopUnroller::_dot(d,v)+d[n-1]*v[n-1]; + } else { + return d[0]*v[0]; + } } +} //PLMD -#endif +#endif //__PLUMED_tools_LoopUnroller_h diff --git a/src/tools/MatrixSquareBracketsAccess.h b/src/tools/MatrixSquareBracketsAccess.h index 8de3e28f85..1509a8b7ab 100644 --- a/src/tools/MatrixSquareBracketsAccess.h +++ b/src/tools/MatrixSquareBracketsAccess.h @@ -73,10 +73,10 @@ class MatrixSquareBracketsAccess { // the user should not manipulate it directly const MatrixSquareBracketsAccess& t; const I i; - Const_row(const MatrixSquareBracketsAccess&t,I i); // constructor is private and cannot be manipulated by the user + constexpr Const_row(const MatrixSquareBracketsAccess&t,I i); // constructor is private and cannot be manipulated by the user public: /// access element - const C & operator[] (J j)const; + constexpr const C & operator[] (J j)const; }; /// Small utility class which just contains a pointer to the T and the row number class Row { @@ -84,28 +84,28 @@ class MatrixSquareBracketsAccess { // the user should not manipulate it directly MatrixSquareBracketsAccess& t; const I i; - Row(MatrixSquareBracketsAccess&t,I i); // constructor is private and cannot be manipulated by the user + constexpr Row(MatrixSquareBracketsAccess&t,I i); // constructor is private and cannot be manipulated by the user public: /// access element - C & operator[] (J j); + constexpr C & operator[] (J j); }; public: /// access element (with [][] syntax) - Row operator[] (I i); + constexpr Row operator[] (I i); /// access element (with [][] syntax) - Const_row operator[] (I i)const; + constexpr Const_row operator[] (I i)const; }; template -MatrixSquareBracketsAccess::Const_row::Const_row(const MatrixSquareBracketsAccess&t,I i): +constexpr MatrixSquareBracketsAccess::Const_row::Const_row(const MatrixSquareBracketsAccess&t,I i): t(t),i(i) {} template -MatrixSquareBracketsAccess::Row::Row(MatrixSquareBracketsAccess&t,I i): +constexpr MatrixSquareBracketsAccess::Row::Row(MatrixSquareBracketsAccess&t,I i): t(t),i(i) {} template -const C & MatrixSquareBracketsAccess::Const_row::operator[] (J j)const { +constexpr const C & MatrixSquareBracketsAccess::Const_row::operator[] (J j)const { // This appears as a reference to a temporary object // however, in reality we know it is a reference to an object that is stored in the // t object. We thus suppress the warning raised by cppcheck @@ -113,7 +113,7 @@ const C & MatrixSquareBracketsAccess::Const_row::operator[] (J j)const } template -C & MatrixSquareBracketsAccess::Row::operator[] (J j) { +constexpr C & MatrixSquareBracketsAccess::Row::operator[] (J j) { // This appears as a reference to a temporary object // however, in reality we know it is a reference to an object that is stored in the // t object. We thus suppress the warning raised by cppcheck @@ -121,12 +121,12 @@ C & MatrixSquareBracketsAccess::Row::operator[] (J j) { } template -typename MatrixSquareBracketsAccess::Row MatrixSquareBracketsAccess::operator[] (I i) { +constexpr typename MatrixSquareBracketsAccess::Row MatrixSquareBracketsAccess::operator[] (I i) { return Row(*this,i); } template -typename MatrixSquareBracketsAccess::Const_row MatrixSquareBracketsAccess::operator[] (I i)const { +constexpr typename MatrixSquareBracketsAccess::Const_row MatrixSquareBracketsAccess::operator[] (I i)const { return Const_row(*this,i); } diff --git a/src/tools/Tensor.h b/src/tools/Tensor.h index 4ed456b3d7..6bb813c336 100644 --- a/src/tools/Tensor.h +++ b/src/tools/Tensor.h @@ -31,10 +31,10 @@ namespace PLMD { +//should I add something for calling ssyevr? /// Small class to contain local utilities. /// Should not be used outside of the TensorGeneric class. -class TensorGenericAux { -public: +struct TensorGenericAux { // local redefinition, just to avoid including lapack.h here static void local_dsyevr(const char *jobz, const char *range, const char *uplo, int *n, double *a, int *lda, double *vl, double *vu, int * @@ -83,166 +83,146 @@ int main(){ \endverbatim */ -template -class TensorGeneric: - public MatrixSquareBracketsAccess,double> { - std::array d; +template class TensorTyped; + +template +std::ostream & operator<<(std::ostream &os, const TensorTyped& t); + +template +class TensorTyped: + public MatrixSquareBracketsAccess,T> { + std::array d; /// Auxiliary private function for constructor - void auxiliaryConstructor(); + constexpr void auxiliaryConstructor(); /// Auxiliary private function for constructor template - void auxiliaryConstructor(double first,Args... arg); + constexpr void auxiliaryConstructor(T first,Args... arg); + template + using is3x3 = std::enable_if_t<(n_==3 && m_==3)>; public: -/// Constructor accepting n*m double parameters. +/// Constructor accepting n*m T parameters. /// Can be used as Tensor<2,2>(1.0,2.0,3.0,4.0) /// In case a wrong number of parameters is given, a static assertion will fail. template - TensorGeneric(double first,Args... arg); + constexpr TensorTyped(T first,Args... arg); /// initialize the tensor to zero - TensorGeneric(); + constexpr TensorTyped(); /// initialize a tensor as an external product of two Vector - TensorGeneric(const VectorGeneric&v1,const VectorGeneric&v2); + constexpr TensorTyped(const VectorTyped&v1,const VectorTyped&v2); /// set it to zero - void zero(); + constexpr void zero(); +/// get the underline pointer to data + constexpr T* data(); +/// get the underline pointer to data + constexpr const T* data() const; /// access element - double & operator() (unsigned i,unsigned j); + constexpr T & operator() (unsigned i,unsigned j); /// access element - const double & operator() (unsigned i,unsigned j)const; + constexpr const T & operator() (unsigned i,unsigned j)const; /// increment - TensorGeneric& operator +=(const TensorGeneric& b); + constexpr TensorTyped& operator +=(const TensorTyped& b); /// decrement - TensorGeneric& operator -=(const TensorGeneric& b); + constexpr TensorTyped& operator -=(const TensorTyped& b); /// multiply - TensorGeneric& operator *=(double); + constexpr TensorTyped& operator *=(T); /// divide - TensorGeneric& operator /=(double); + constexpr TensorTyped& operator /=(T); /// return +t - TensorGeneric operator +()const; + constexpr TensorTyped operator +()const; /// return -t - TensorGeneric operator -()const; + constexpr TensorTyped operator -()const; /// set j-th column - TensorGeneric& setCol(unsigned j,const VectorGeneric & c); + constexpr TensorTyped& setCol(unsigned j,const VectorTyped & c); /// set i-th row - TensorGeneric& setRow(unsigned i,const VectorGeneric & r); + constexpr TensorTyped& setRow(unsigned i,const VectorTyped & r); /// get j-th column - VectorGeneric getCol(unsigned j)const; + constexpr VectorTyped getCol(unsigned j)const; /// get i-th row - VectorGeneric getRow(unsigned i)const; -/// return t1+t2 - template - friend TensorGeneric operator+(const TensorGeneric&,const TensorGeneric&); -/// return t1+t2 - template - friend TensorGeneric operator-(const TensorGeneric&,const TensorGeneric&); -/// scale the tensor by a factor s - template - friend TensorGeneric operator*(double,const TensorGeneric&); -/// scale the tensor by a factor s - template - friend TensorGeneric operator*(const TensorGeneric&,double s); -/// scale the tensor by a factor 1/s - template - friend TensorGeneric operator/(const TensorGeneric&,double s); + constexpr VectorTyped getRow(unsigned i)const; /// returns the determinant - double determinant()const; + template> + constexpr T determinant()const; /// return an identity tensor - static TensorGeneric identity(); + static constexpr TensorTyped identity(); /// return the matrix inverse - TensorGeneric inverse()const; + template> + constexpr TensorTyped inverse()const; /// return the transpose matrix - TensorGeneric transpose()const; -/// matrix-matrix multiplication - template - friend TensorGeneric matmul(const TensorGeneric&,const TensorGeneric&); -/// matrix-vector multiplication - template - friend VectorGeneric matmul(const TensorGeneric&,const VectorGeneric&); -/// vector-matrix multiplication - template - friend VectorGeneric matmul(const VectorGeneric&,const TensorGeneric&); -/// vector-vector multiplication (maps to dotProduct) - template - friend double matmul(const VectorGeneric&,const VectorGeneric&); -/// matrix-matrix-matrix multiplication - template - friend TensorGeneric matmul(const TensorGeneric&,const TensorGeneric&,const TensorGeneric&); -/// matrix-matrix-vector multiplication - template - friend VectorGeneric matmul(const TensorGeneric&,const TensorGeneric&,const VectorGeneric&); -/// vector-matrix-matrix multiplication - template - friend VectorGeneric matmul(const VectorGeneric&,const TensorGeneric&,const TensorGeneric&); -/// vector-matrix-vector multiplication - template - friend double matmul(const VectorGeneric&,const TensorGeneric&,const VectorGeneric&); -/// returns the determinant of a tensor - friend double determinant(const TensorGeneric<3,3>&); -/// returns the inverse of a tensor (same as inverse()) - friend TensorGeneric<3,3> inverse(const TensorGeneric<3,3>&); -/// returns the transpose of a tensor (same as transpose()) - template - friend TensorGeneric transpose(const TensorGeneric&); -/// returns the transpose of a tensor (same as TensorGeneric(const VectorGeneric&,const VectorGeneric&)) - template - friend TensorGeneric extProduct(const VectorGeneric&,const VectorGeneric&); - friend TensorGeneric<3,3> dcrossDv1(const VectorGeneric<3>&,const VectorGeneric<3>&); - friend TensorGeneric<3,3> dcrossDv2(const VectorGeneric<3>&,const VectorGeneric<3>&); - friend TensorGeneric<3,3> VcrossTensor(const VectorGeneric<3>&,const TensorGeneric<3,3>&); - friend TensorGeneric<3,3> VcrossTensor(const TensorGeneric<3,3>&,const VectorGeneric<3>&); -/// Derivative of a normalized vector - friend TensorGeneric<3,3> deriNorm(const VectorGeneric<3>&,const TensorGeneric<3,3>&); + constexpr TensorTyped transpose()const; /// << operator. /// Allows printing tensor `t` with `std::cout< - friend std::ostream & operator<<(std::ostream &os, const TensorGeneric&); -/// Diagonalize tensor. -/// Syntax is the same as Matrix::diagMat. -/// In addition, it is possible to call if with m_ smaller than n_. In this case, -/// only the first (smaller) m_ eigenvalues and eigenvectors are retrieved. -/// If case lapack fails (info!=0) it throws an exception. -/// Notice that tensor is assumed to be symmetric!!! - template - friend void diagMatSym(const TensorGeneric&,VectorGeneric&evals,TensorGeneric&evec); + friend std::ostream & operator<< <>(std::ostream &os, const TensorTyped&); }; -template -void TensorGeneric::auxiliaryConstructor() +template +constexpr void TensorTyped::auxiliaryConstructor() {} -template +template template -void TensorGeneric::auxiliaryConstructor(double first,Args... arg) { +constexpr void TensorTyped::auxiliaryConstructor(T first,Args... arg) { d[n*m-(sizeof...(Args))-1]=first; auxiliaryConstructor(arg...); } -template +template template -TensorGeneric::TensorGeneric(double first,Args... arg) { +constexpr TensorTyped::TensorTyped(T first,Args... arg) { static_assert((sizeof...(Args))+1==n*m,"you are trying to initialize a Tensor with the wrong number of arguments"); auxiliaryConstructor(first,arg...); } -template -TensorGeneric::TensorGeneric() { - LoopUnroller::_zero(d.data()); +template +constexpr T* TensorTyped::data() { + return d.data(); +} +template +constexpr const T* TensorTyped::data() const { + return d.data(); } -template -TensorGeneric::TensorGeneric(const VectorGeneric&v1,const VectorGeneric&v2) { - for(unsigned i=0; i +constexpr TensorTyped::TensorTyped() { + LoopUnroller::_zero(d.data()); +} + +/* between RVO and compile time this should be faster, but slows down openACC, a lot +template +void external_rec(T*const out,const T*const v1, const T*const v2){ + if constexpr (j>0) { + external_rec(out,v1,v2); + } else if constexpr (i>0) { + external_rec(out,v1,v2); + } + out[i*m+j]=v1[i]*v2[j]; +} +template +std::array externaProd(const VectorGeneric&v1,const VectorGeneric&v2){ +std::array toRet; +external_rec(toRet.data(),v1.data(),v2.data()); +return toRet; +} +template +TensorGeneric::TensorGeneric(const VectorGeneric&v1,const VectorGeneric&v2) +:d(externaProd(v1,v2)) {} +*/ + +template +constexpr TensorTyped::TensorTyped(const VectorTyped&v1,const VectorTyped&v2) { + for(unsigned i=0; i -void TensorGeneric::zero() { - LoopUnroller::_zero(d.data()); +template +constexpr void TensorTyped::zero() { + LoopUnroller::_zero(d.data()); } -template -double & TensorGeneric::operator() (unsigned i,unsigned j) { +template +constexpr T & TensorTyped::operator() (unsigned i,unsigned j) { #ifdef _GLIBCXX_DEBUG // index i is implicitly checked by the std::array class plumed_assert(j::operator() (unsigned i,unsigned j) { return d[m*i+j]; } -template -const double & TensorGeneric::operator() (unsigned i,unsigned j)const { +template +constexpr const T & TensorTyped::operator() (unsigned i,unsigned j)const { #ifdef _GLIBCXX_DEBUG // index i is implicitly checked by the std::array class plumed_assert(j::operator() (unsigned i,unsigned j)const { return d[m*i+j]; } -template -TensorGeneric& TensorGeneric::operator +=(const TensorGeneric& b) { - LoopUnroller::_add(d.data(),b.d.data()); +template +constexpr TensorTyped& TensorTyped::operator +=(const TensorTyped& b) { + LoopUnroller::_add(d.data(),b.d.data()); return *this; } -template -TensorGeneric& TensorGeneric::operator -=(const TensorGeneric& b) { - LoopUnroller::_sub(d.data(),b.d.data()); +template +constexpr TensorTyped& TensorTyped::operator -=(const TensorTyped& b) { + LoopUnroller::_sub(d.data(),b.d.data()); return *this; } -template -TensorGeneric& TensorGeneric::operator *=(double s) { - LoopUnroller::_mul(d.data(),s); +template +constexpr TensorTyped& TensorTyped::operator *=(T s) { + LoopUnroller::_mul(d.data(),s); return *this; } -template -TensorGeneric& TensorGeneric::operator /=(double s) { - LoopUnroller::_mul(d.data(),1.0/s); +template +constexpr TensorTyped& TensorTyped::operator /=(T s) { + LoopUnroller::_mul(d.data(),1.0/s); return *this; } -template -TensorGeneric TensorGeneric::operator+()const { +template +constexpr TensorTyped TensorTyped::operator+()const { return *this; } -template -TensorGeneric TensorGeneric::operator-()const { - TensorGeneric r; - LoopUnroller::_neg(r.d.data(),d.data()); +template +constexpr TensorTyped TensorTyped::operator-()const { + TensorTyped r; + LoopUnroller::_neg(r.d.data(),d.data()); return r; } -template -TensorGeneric& TensorGeneric::setCol(unsigned j,const VectorGeneric & c) { +template +constexpr TensorTyped& TensorTyped::setCol(unsigned j,const VectorTyped & c) { for(unsigned i=0; i -TensorGeneric& TensorGeneric::setRow(unsigned i,const VectorGeneric & r) { +template +constexpr TensorTyped& TensorTyped::setRow(unsigned i,const VectorTyped & r) { for(unsigned j=0; j -VectorGeneric TensorGeneric::getCol(unsigned j)const { - VectorGeneric v; +template +constexpr VectorTyped TensorTyped::getCol(unsigned j)const { + VectorTyped v; for(unsigned i=0; i -VectorGeneric TensorGeneric::getRow(unsigned i)const { - VectorGeneric v; +template +constexpr VectorTyped TensorTyped::getRow(unsigned i)const { + VectorTyped v; for(unsigned j=0; j -TensorGeneric operator+(const TensorGeneric&t1,const TensorGeneric&t2) { - TensorGeneric t(t1); +template +constexpr TensorTyped operator+(const TensorTyped&t1,const TensorTyped&t2) { + TensorTyped t(t1); t+=t2; return t; } -template -TensorGeneric operator-(const TensorGeneric&t1,const TensorGeneric&t2) { - TensorGeneric t(t1); +template +constexpr TensorTyped operator-(const TensorTyped&t1,const TensorTyped&t2) { + TensorTyped t(t1); t-=t2; return t; } -template -TensorGeneric operator*(const TensorGeneric&t1,double s) { - TensorGeneric t(t1); +template +constexpr TensorTyped operator*(const TensorTyped&t1,J s) { + TensorTyped t(t1); t*=s; return t; } -template -TensorGeneric operator*(double s,const TensorGeneric&t1) { +template +constexpr TensorTyped operator*(J s,const TensorTyped&t1) { return t1*s; } -template -TensorGeneric operator/(const TensorGeneric&t1,double s) { - return t1*(1.0/s); +template +constexpr TensorTyped operator/(const TensorTyped&t1,J s) { + return t1*(T(1.0)/s); } -template<> -inline -double TensorGeneric<3,3>::determinant()const { +template +template +constexpr inline T TensorTyped::determinant()const { return d[0]*d[4]*d[8] + d[1]*d[5]*d[6] @@ -372,19 +352,19 @@ double TensorGeneric<3,3>::determinant()const { - d[2]*d[4]*d[6]; } -template -inline -TensorGeneric TensorGeneric::identity() { - TensorGeneric t; +//consider to make this a constexpr function +template +constexpr inline TensorTyped TensorTyped::identity() { + TensorTyped t; for(unsigned i=0; i -TensorGeneric TensorGeneric::transpose()const { - TensorGeneric t; +template +constexpr TensorTyped TensorTyped::transpose()const { + TensorTyped t; for(unsigned i=0; i TensorGeneric::transpose()const { return t; } -template<> -inline -TensorGeneric<3,3> TensorGeneric<3,3>::inverse()const { - TensorGeneric t; - double invdet=1.0/determinant(); +template +template +constexpr inline TensorTyped TensorTyped::inverse()const { + TensorTyped t; + T invdet=1.0/determinant(); for(unsigned i=0; i<3; i++) for(unsigned j=0; j<3; j++) t(j,i)=invdet*( (*this)((i+1)%3,(j+1)%3)*(*this)((i+2)%3,(j+2)%3) @@ -404,9 +384,10 @@ TensorGeneric<3,3> TensorGeneric<3,3>::inverse()const { return t; } -template -TensorGeneric matmul(const TensorGeneric&a,const TensorGeneric&b) { - TensorGeneric t; +/// matrix-matrix multiplication +template +constexpr TensorTyped matmul(const TensorTyped&a,const TensorTyped&b) { + TensorTyped t; for(unsigned i=0; i matmul(const TensorGeneric&a,const TensorGeneric&b) return t; } -template -VectorGeneric matmul(const TensorGeneric&a,const VectorGeneric&b) { - VectorGeneric t; +/// matrix-vector multiplication +template +constexpr VectorTyped matmul(const TensorTyped&a,const VectorTyped&b) { + VectorTyped t; for(unsigned i=0; i matmul(const TensorGeneric&a,const VectorGeneric&b) { return t; } -template -VectorGeneric matmul(const VectorGeneric&a,const TensorGeneric&b) { - VectorGeneric t; +/// vector-matrix multiplication +template +constexpr VectorTyped matmul(const VectorTyped&a,const TensorTyped&b) { + VectorTyped t; for(unsigned i=0; i matmul(const VectorGeneric&a,const TensorGeneric&b) { return t; } -template -double matmul(const VectorGeneric&a,const VectorGeneric&b) { +/// vector-vector multiplication (maps to dotProduct) +template +constexpr T matmul(const VectorTyped&a,const VectorTyped&b) { return dotProduct(a,b); } -template -TensorGeneric matmul(const TensorGeneric&a,const TensorGeneric&b,const TensorGeneric&c) { +/// matrix-matrix-matrix multiplication +template +constexpr TensorTyped matmul(const TensorTyped&a,const TensorTyped&b,const TensorTyped&c) { return matmul(matmul(a,b),c); } -template -VectorGeneric matmul(const TensorGeneric&a,const TensorGeneric&b,const VectorGeneric&c) { +/// matrix-matrix-vector multiplication +template +constexpr VectorTyped matmul(const TensorTyped&a,const TensorTyped&b,const VectorTyped&c) { return matmul(matmul(a,b),c); } -template -VectorGeneric matmul(const VectorGeneric&a,const TensorGeneric&b,const TensorGeneric&c) { +/// vector-matrix-matrix multiplication +template +constexpr VectorTyped matmul(const VectorTyped&a,const TensorTyped&b,const TensorTyped&c) { return matmul(matmul(a,b),c); } -template -double matmul(const VectorGeneric&a,const TensorGeneric&b,const VectorGeneric&c) { +/// vector-matrix-vector multiplication +template +constexpr T matmul(const VectorTyped&a,const TensorTyped&b,const VectorTyped&c) { return matmul(matmul(a,b),c); } +template inline -double determinant(const TensorGeneric<3,3>&t) { +constexpr T determinant(const TensorTyped&t) { return t.determinant(); } +template inline -TensorGeneric<3,3> inverse(const TensorGeneric<3,3>&t) { +constexpr TensorTyped inverse(const TensorTyped&t) { return t.inverse(); } -template -TensorGeneric transpose(const TensorGeneric&t) { +/// returns the transpose of a tensor (same as TensorGeneric::transpose()) +template +constexpr TensorTyped transpose(const TensorTyped&t) { return t.transpose(); } -template -TensorGeneric extProduct(const VectorGeneric&v1,const VectorGeneric&v2) { - return TensorGeneric(v1,v2); +/// returns the transpose of a tensor (same as TensorGeneric(const VectorGeneric&,const VectorGeneric&)) +template +constexpr TensorTyped extProduct(const VectorTyped&v1,const VectorTyped&v2) { + return TensorTyped(v1,v2); } +template inline -TensorGeneric<3,3> dcrossDv1(const VectorGeneric<3>&v1,const VectorGeneric<3>&v2) { +constexpr TensorTyped dcrossDv1(const VectorTyped&v1,const VectorTyped&v2) { (void) v1; // this is to avoid warnings. still the syntax of this function is a bit dummy... - return TensorGeneric<3,3>( - 0.0, v2[2],-v2[1], - -v2[2], 0.0, v2[0], - v2[1],-v2[0], 0.0); + return TensorTyped( + T(0.0), v2[2], -v2[1], + -v2[2], T(0.0), v2[0], + v2[1], -v2[0], T(0.0)); } +template inline -TensorGeneric<3,3> dcrossDv2(const VectorGeneric<3>&v1,const VectorGeneric<3>&v2) { +constexpr TensorTyped dcrossDv2(const VectorTyped&v1,const VectorTyped&v2) { (void) v2; // this is to avoid warnings. still the syntax of this function is a bit dummy... - return TensorGeneric<3,3>( - 0.0,-v1[2],v1[1], - v1[2],0.0,-v1[0], - -v1[1],v1[0],0.0); + return TensorTyped( + T(0.0),-v1[2], v1[1], + v1[2], T(0.0),-v1[0], + -v1[1],v1[0], T(0.0)); } -template -std::ostream & operator<<(std::ostream &os, const TensorGeneric& t) { +template +std::ostream & operator<<(std::ostream &os, const TensorTyped& t) { for(unsigned i=0; i& t) { return os; } +template +using TensorGeneric=TensorTyped; + /// \ingroup TOOLBOX typedef TensorGeneric<1,1> Tensor1d; /// \ingroup TOOLBOX @@ -524,33 +521,40 @@ typedef TensorGeneric<5,5> Tensor5d; /// \ingroup TOOLBOX typedef Tensor3d Tensor; +template inline -TensorGeneric<3,3> VcrossTensor(const VectorGeneric<3>&v1,const TensorGeneric<3,3>&v2) { - - TensorGeneric<3,3> t; +TensorTyped VcrossTensor(const VectorTyped&v1,const TensorTyped&v2) { + TensorTyped t; for(unsigned i=0; i<3; i++) { t.setRow(i,matmul(dcrossDv2(v1,v1),v2.getRow(i))); } return t; } +template inline -TensorGeneric<3,3> VcrossTensor(const TensorGeneric<3,3>&v2,const VectorGeneric<3>&v1) { - TensorGeneric<3,3> t; +TensorTyped VcrossTensor(const TensorTyped&v2,const VectorTyped&v1) { + TensorTyped t; for(unsigned i=0; i<3; i++) { t.setRow(i,-matmul(dcrossDv2(v1,v1),v2.getRow(i))); } return t; } - +template inline -TensorGeneric<3,3> deriNorm(const VectorGeneric<3>&v1,const TensorGeneric<3,3>&v2) { +TensorTyped deriNorm(const VectorTyped&v1,const TensorTyped&v2) { // delta(v) = delta(v1/v1.norm) = 1/v1.norm*(delta(v1) - (v.delta(v1))cross v; - double over_norm = 1./v1.modulo(); + T over_norm = 1./v1.modulo(); return over_norm*(v2 - over_norm*over_norm*(extProduct(matmul(v2,v1),v1))); } +/// Diagonalize tensor. +/// Syntax is the same as Matrix::diagMat. +/// In addition, it is possible to call if with m_ smaller than n_. In this case, +/// only the first (smaller) m_ eigenvalues and eigenvectors are retrieved. +/// If case lapack fails (info!=0) it throws an exception. +/// Notice that tensor is assumed to be symmetric!!! template void diagMatSym(const TensorGeneric&mat,VectorGeneric&evals,TensorGeneric&evec) { // some guess number to make sure work is large enough. @@ -573,8 +577,8 @@ void diagMatSym(const TensorGeneric&mat,VectorGeneric&evals,TensorGeneri int info=0; // result int liwork=iwork.size(); int lwork=work.size(); - TensorGenericAux::local_dsyevr("V", (n==m?"A":"I"), "U", &nn, const_cast(&mat_copy[0][0]), &nn, &vl, &vu, &one, &mm, - &abstol, &mout, &evals_tmp[0], &evec[0][0], &nn, + TensorGenericAux::local_dsyevr("V", (n==m?"A":"I"), "U", &nn, mat_copy.data(), &nn, &vl, &vu, &one, &mm, + &abstol, &mout, evals_tmp.data(), evec.data(), &nn, isup.data(), work.data(), &lwork, iwork.data(), &liwork, &info); if(info!=0) plumed_error()<<"Error diagonalizing matrix\n" @@ -604,7 +608,6 @@ void diagMatSym(const TensorGeneric&mat,VectorGeneric&evals,TensorGeneri static_assert(sizeof(Tensor)==9*sizeof(double), "code cannot work if this is not satisfied"); -} +} //PLMD #endif - diff --git a/src/tools/Tools.h b/src/tools/Tools.h index a1d07795f9..3142984084 100644 --- a/src/tools/Tools.h +++ b/src/tools/Tools.h @@ -85,7 +85,7 @@ class Tools { static bool convertToInt(const std::string & str,T &t); /// @brief the recursive part of the template fastpow implementation template =0), bool> = true> - static inline /*consteval*/ T fastpow_rec(T base, T result); + static constexpr inline T fastpow_rec(T base, T result); public: /// Split the line in words using separators. /// It also take into account parenthesis. Outer parenthesis found are removed from @@ -178,10 +178,11 @@ class Tools { /// extension("pippo/.t")="" whereas extension("pippo/a.t")="t" static std::string extension(const std::string&); /// Fast int power - static double fastpow(double base,int exp); + template + static constexpr inline T fastpow(T base,int exp); /// Fast int power for power known at compile time template - static inline /*consteval*/ T fastpow(T base); + static constexpr inline T fastpow(T base); /// Modified 0th-order Bessel function of the first kind static double bessel0(const double& val); /// Check if a string full starts with string start. @@ -248,16 +249,16 @@ class Tools { if(s==0) { return; } - set_to_zero(&vec[0][0],s*n); + set_to_zero(vec[0].data(),s*n); } - template - static void set_to_zero(std::vector> & vec) { + template + static void set_to_zero(std::vector> & vec) { unsigned s=vec.size(); if(s==0) { return; } - set_to_zero(&vec[0](0,0),s*n*m); + set_to_zero(vec[0].data(),s*n*m); } static std::unique_ptr> molfile_lock(); @@ -487,8 +488,8 @@ bool Tools::convertNoexcept(T i,std::string & str) { return true; } -inline -double Tools::fastpow(double base, int exp) { +template +constexpr inline T Tools::fastpow(T base, int exp) { if(exp<0) { exp=-exp; base=1.0/base; @@ -506,7 +507,7 @@ double Tools::fastpow(double base, int exp) { } template =0), bool>> -inline T Tools::fastpow_rec(T const base, T result) { +constexpr inline T Tools::fastpow_rec(T const base, T result) { if constexpr (exp == 0) { return result; } @@ -517,7 +518,7 @@ inline T Tools::fastpow_rec(T const base, T result) { } template -inline T Tools::fastpow(T const base) { +constexpr inline T Tools::fastpow(T const base) { if constexpr (exp<0) { return fastpow_rec<-exp,T>(1.0/base,1.0); } else { diff --git a/src/tools/Vector.h b/src/tools/Vector.h index 0f585be328..97fd3b59bd 100644 --- a/src/tools/Vector.h +++ b/src/tools/Vector.h @@ -73,239 +73,260 @@ int main(){ \endverbatim */ +template class VectorTyped; +template +constexpr VectorTyped delta(const VectorTyped&,const VectorTyped&); -template -class VectorGeneric { - std::array d; +template +constexpr T dotProduct(const VectorTyped&,const VectorTyped&); + + +template +std::ostream & operator<<(std::ostream &os, const VectorTyped& v); +template +class VectorTyped { + std::array d; /// Auxiliary private function for constructor - void auxiliaryConstructor(); + constexpr void auxiliaryConstructor(); /// Auxiliary private function for constructor template - void auxiliaryConstructor(double first,Args... arg); + constexpr void auxiliaryConstructor(T first,Args... arg); public: -/// Constructor accepting n double parameters. +/// Constructor accepting n T parameters. /// Can be used as Vector<3>(1.0,2.0,3.0) or Vector<2>(2.0,3.0). /// In case a wrong number of parameters is given, a static assertion will fail. template - VectorGeneric(double first,Args... arg); + constexpr VectorTyped(T first,Args... arg); /// create it null - VectorGeneric(); + constexpr VectorTyped(); +/// get the underline pointer to the data + constexpr T* data(); +/// get the underline pointer to the data + constexpr const T* data() const; /// set it to zero - void zero(); + constexpr void zero(); /// array-like access [i] - double & operator[](unsigned i); + constexpr T & operator[](unsigned i); /// array-like access [i] - const double & operator[](unsigned i)const; + constexpr const T & operator[](unsigned i)const; /// parenthesis access (i) - double & operator()(unsigned i); + constexpr T & operator()(unsigned i); /// parenthesis access (i) - const double & operator()(unsigned i)const; + constexpr const T & operator()(unsigned i)const; /// increment - VectorGeneric& operator +=(const VectorGeneric& b); + constexpr VectorTyped& operator +=(const VectorTyped& b); /// decrement - VectorGeneric& operator -=(const VectorGeneric& b); + constexpr VectorTyped& operator -=(const VectorTyped& b); /// multiply - VectorGeneric& operator *=(double s); + constexpr VectorTyped& operator *=(T s); /// divide - VectorGeneric& operator /=(double s); + constexpr VectorTyped& operator /=(T s); /// sign + - VectorGeneric operator +()const; + constexpr VectorTyped operator +()const; /// sign - - VectorGeneric operator -()const; + constexpr VectorTyped operator -()const; /// return v1+v2 - template - friend VectorGeneric operator+(const VectorGeneric&,const VectorGeneric&); + template + friend constexpr VectorTyped operator+(const VectorTyped&,const VectorTyped&); /// return v1-v2 - template - friend VectorGeneric operator-(const VectorGeneric&,const VectorGeneric&); + template + friend constexpr VectorTyped operator-(VectorTyped,const VectorTyped&); /// return s*v - template - friend VectorGeneric operator*(double,const VectorGeneric&); + template + friend constexpr VectorTyped operator*(J,VectorTyped); /// return v*s - template - friend VectorGeneric operator*(const VectorGeneric&,double); + template + friend constexpr VectorTyped operator*(VectorTyped,J); /// return v/s - template - friend VectorGeneric operator/(const VectorGeneric&,double); + template + friend constexpr VectorTyped operator/(const VectorTyped&,J); /// return v2-v1 - template - friend VectorGeneric delta(const VectorGeneric&v1,const VectorGeneric&v2); + friend constexpr VectorTyped delta<>(const VectorTyped&v1,const VectorTyped&v2); /// return v1 .scalar. v2 - template - friend double dotProduct(const VectorGeneric&,const VectorGeneric&); + friend constexpr T dotProduct<>(const VectorTyped&,const VectorTyped&); + //this bad boy produces a warning (in fact becasue declrare the crossproduc as a friend for ALL thhe possible combinations of n and T) /// return v1 .vector. v2 /// Only available for size 3 - friend VectorGeneric<3> crossProduct(const VectorGeneric<3>&,const VectorGeneric<3>&); + template + friend constexpr VectorTyped crossProduct(const VectorTyped&,const VectorTyped&); /// compute the squared modulo - double modulo2()const; + constexpr T modulo2()const; /// Compute the modulo. /// Shortcut for sqrt(v.modulo2()) - double modulo()const; + constexpr T modulo()const; /// friend version of modulo2 (to simplify some syntax) - template - friend double modulo2(const VectorGeneric&); + template + friend constexpr U modulo2(const VectorTyped&); /// friend version of modulo (to simplify some syntax) - template - friend double modulo(const VectorGeneric&); + template + friend constexpr U modulo(const VectorTyped&); /// << operator. /// Allows printing vector `v` with `std::cout< - friend std::ostream & operator<<(std::ostream &os, const VectorGeneric&); + friend std::ostream & operator<< <>(std::ostream &os, const VectorTyped&); }; -template -void VectorGeneric::auxiliaryConstructor() +template +constexpr void VectorTyped::auxiliaryConstructor() {} -template +template template -void VectorGeneric::auxiliaryConstructor(double first,Args... arg) { +constexpr void VectorTyped::auxiliaryConstructor(T first,Args... arg) { d[n-(sizeof...(Args))-1]=first; auxiliaryConstructor(arg...); } -template +template template -VectorGeneric::VectorGeneric(double first,Args... arg) { +constexpr VectorTyped::VectorTyped(T first,Args... arg) { static_assert((sizeof...(Args))+1==n,"you are trying to initialize a Vector with the wrong number of arguments"); auxiliaryConstructor(first,arg...); } -template -void VectorGeneric::zero() { - LoopUnroller::_zero(d.data()); +template +constexpr T* VectorTyped::data() { + return d.data(); +} + +template +constexpr const T* VectorTyped::data() const { + return d.data(); } -template -VectorGeneric::VectorGeneric() { - LoopUnroller::_zero(d.data()); +template +constexpr void VectorTyped::zero() { + LoopUnroller::_zero(d.data()); } -template -double & VectorGeneric::operator[](unsigned i) { +template +constexpr VectorTyped::VectorTyped() { + LoopUnroller::_zero(d.data()); +} + +template +constexpr T & VectorTyped::operator[](unsigned i) { return d[i]; } -template -const double & VectorGeneric::operator[](unsigned i)const { +template +constexpr const T & VectorTyped::operator[](unsigned i)const { return d[i]; } -template -double & VectorGeneric::operator()(unsigned i) { +template +constexpr T & VectorTyped::operator()(unsigned i) { return d[i]; } -template -const double & VectorGeneric::operator()(unsigned i)const { +template +constexpr const T & VectorTyped::operator()(unsigned i)const { return d[i]; } -template -VectorGeneric& VectorGeneric::operator +=(const VectorGeneric& b) { - LoopUnroller::_add(d.data(),b.d.data()); +template +constexpr VectorTyped& VectorTyped::operator +=(const VectorTyped& b) { + LoopUnroller::_add(d.data(),b.d.data()); return *this; } -template -VectorGeneric& VectorGeneric::operator -=(const VectorGeneric& b) { - LoopUnroller::_sub(d.data(),b.d.data()); +template +constexpr VectorTyped& VectorTyped::operator -=(const VectorTyped& b) { + LoopUnroller::_sub(d.data(),b.d.data()); return *this; } -template -VectorGeneric& VectorGeneric::operator *=(double s) { - LoopUnroller::_mul(d.data(),s); +template +constexpr VectorTyped& VectorTyped::operator *=(T s) { + LoopUnroller::_mul(d.data(),s); return *this; } -template -VectorGeneric& VectorGeneric::operator /=(double s) { - LoopUnroller::_mul(d.data(),1.0/s); +template +constexpr VectorTyped& VectorTyped::operator /=(T s) { + LoopUnroller::_mul(d.data(),1.0/s); return *this; } -template -VectorGeneric VectorGeneric::operator +()const { +template +constexpr VectorTyped VectorTyped::operator +()const { return *this; } -template -VectorGeneric VectorGeneric::operator -()const { - VectorGeneric r; - LoopUnroller::_neg(r.d.data(),d.data()); +template +constexpr VectorTyped VectorTyped::operator -()const { + VectorTyped r; + LoopUnroller::_neg(r.d.data(),d.data()); return r; } -template -VectorGeneric operator+(const VectorGeneric&v1,const VectorGeneric&v2) { - VectorGeneric v(v1); +template +constexpr VectorTyped operator+(const VectorTyped&v1,const VectorTyped&v2) { + VectorTyped v(v1); return v+=v2; } -template -VectorGeneric operator-(const VectorGeneric&v1,const VectorGeneric&v2) { - VectorGeneric v(v1); - return v-=v2; +template +constexpr VectorTyped operator-(VectorTypedv1,const VectorTyped&v2) { + return v1-=v2; } -template -VectorGeneric operator*(double s,const VectorGeneric&v) { - VectorGeneric vv(v); - return vv*=s; +template +constexpr VectorTyped operator*(J s,VectorTypedv) { + return v*=s; } -template -VectorGeneric operator*(const VectorGeneric&v,double s) { - return s*v; +template +constexpr VectorTyped operator*(VectorTyped v,J s) { + return v*=s; } -template -VectorGeneric operator/(const VectorGeneric&v,double s) { - return v*(1.0/s); +template +constexpr VectorTyped operator/(const VectorTyped&v,J s) { + return v*(T(1.0)/s); } -template -VectorGeneric delta(const VectorGeneric&v1,const VectorGeneric&v2) { +template +constexpr VectorTyped delta(const VectorTyped&v1,const VectorTyped&v2) { return v2-v1; } -template -double VectorGeneric::modulo2()const { - return LoopUnroller::_sum2(d.data()); +template +constexpr T VectorTyped::modulo2()const { + return LoopUnroller::_sum2(d.data()); } -template -double dotProduct(const VectorGeneric& v1,const VectorGeneric& v2) { - return LoopUnroller::_dot(v1.d.data(),v2.d.data()); +template +constexpr T dotProduct(const VectorTyped& v1,const VectorTyped& v2) { + return LoopUnroller::_dot(v1.d.data(),v2.d.data()); } -inline -VectorGeneric<3> crossProduct(const VectorGeneric<3>& v1,const VectorGeneric<3>& v2) { - return VectorGeneric<3>( +template +constexpr inline +VectorTyped crossProduct(const VectorTyped& v1,const VectorTyped& v2) { + return VectorTyped( v1[1]*v2[2]-v1[2]*v2[1], v1[2]*v2[0]-v1[0]*v2[2], v1[0]*v2[1]-v1[1]*v2[0]); } -template -double VectorGeneric::modulo()const { +template +constexpr T VectorTyped::modulo()const { return sqrt(modulo2()); } -template -double modulo2(const VectorGeneric&v) { +template +constexpr T modulo2(const VectorTyped&v) { return v.modulo2(); } -template -double modulo(const VectorGeneric&v) { +template +constexpr T modulo(const VectorTyped&v) { return v.modulo(); } -template -std::ostream & operator<<(std::ostream &os, const VectorGeneric& v) { +template +std::ostream & operator<<(std::ostream &os, const VectorTyped& v) { for(unsigned i=0; i& v) { return os; } +template +using VectorGeneric=VectorTyped; /// \ingroup TOOLBOX /// Alias for one dimensional vectors @@ -331,13 +354,13 @@ typedef VectorGeneric<4> Vector4d; typedef VectorGeneric<5> Vector5d; /// \ingroup TOOLBOX /// Alias for three dimensional vectors -typedef Vector3d Vector; +using Vector=Vector3d; +//using the using keyword seems to be more trasparent static_assert(sizeof(VectorGeneric<2>)==2*sizeof(double), "code cannot work if this is not satisfied"); static_assert(sizeof(VectorGeneric<3>)==3*sizeof(double), "code cannot work if this is not satisfied"); static_assert(sizeof(VectorGeneric<4>)==4*sizeof(double), "code cannot work if this is not satisfied"); -} - -#endif +} //PLMD +#endif //__PLUMED_tools_Vector_h