#ifndef GRID_MATH_H #define GRID_MATH_H #include #include #include // // Indexing; want to be able to dereference and // obtain either an lvalue or an rvalue. // namespace Grid { /////////////////////////////////////////////////////////////////////////////////////// // innerProduct Scalar x Scalar -> Scalar // innerProduct Vector x Vector -> Scalar // innerProduct Matrix x Matrix -> Scalar /////////////////////////////////////////////////////////////////////////////////////// template inline auto innerProduct (const iVector& lhs,const iVector& rhs) -> iScalar { typedef decltype(innerProduct(lhs._internal[0],rhs._internal[0])) ret_t; iScalar ret=zero; for(int c1=0;c1 inline auto innerProduct (const iMatrix& lhs,const iMatrix& rhs) -> iScalar { typedef decltype(innerProduct(lhs._internal[0][0],rhs._internal[0][0])) ret_t; iScalar ret=zero; iScalar tmp; for(int c1=0;c1 inline auto innerProduct (const iScalar& lhs,const iScalar& rhs) -> iScalar { typedef decltype(innerProduct(lhs._internal,rhs._internal)) ret_t; iScalar ret; ret._internal = innerProduct(lhs._internal,rhs._internal); return ret; } /////////////////////////////////////////////////////////////////////////////////////// // outerProduct Scalar x Scalar -> Scalar // Vector x Vector -> Matrix /////////////////////////////////////////////////////////////////////////////////////// template inline auto outerProduct (const iVector& lhs,const iVector& rhs) -> iMatrix { typedef decltype(outerProduct(lhs._internal[0],rhs._internal[0])) ret_t; iMatrix ret; for(int c1=0;c1 inline auto outerProduct (const iScalar& lhs,const iScalar& rhs) -> iScalar { typedef decltype(outerProduct(lhs._internal,rhs._internal)) ret_t; iScalar ret; ret._internal = outerProduct(lhs._internal,rhs._internal); return ret; } inline ComplexF outerProduct(const ComplexF &l, const ComplexF& r) { return l*r; } inline ComplexD outerProduct(const ComplexD &l, const ComplexD& r) { return l*r; } inline RealF outerProduct(const RealF &l, const RealF& r) { return l*r; } inline RealD outerProduct(const RealD &l, const RealD& r) { return l*r; } /////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////// CONJ /////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////// // Conj function for scalar, vector, matrix template inline iScalar conj(const iScalar&r) { iScalar ret; ret._internal = conj(r._internal); return ret; } template inline iVector conj(const iVector&r) { iVector ret; for(int i=0;i inline iMatrix conj(const iMatrix&r) { iMatrix ret; for(int i=0;i inline iScalar adj(const iScalar&r) { iScalar ret; ret._internal = adj(r._internal); return ret; } template inline iVector adj(const iVector&r) { iVector ret; for(int i=0;i inline iMatrix adj(const iMatrix &arg) { iMatrix ret; for(int c1=0;c1 inline typename std::enable_if::value, iMatrix >::type transpose(iMatrix arg) { iMatrix ret; for(int i=0;i inline typename std::enable_if::notvalue, iMatrix >::type transpose(iMatrix arg) { iMatrix ret; for(int i=0;i inline typename std::enable_if::value, iScalar >::type transpose(iScalar arg) { iScalar ret; ret._internal = transpose(arg._internal); // NB recurses return ret; } template inline typename std::enable_if::notvalue, iScalar >::type transpose(iScalar arg) { iScalar ret; ret._internal = arg._internal; // NB recursion stops return ret; } //////////////////////////////////////////////////////////////////////////////////////////// // Transpose a specific index; instructive to compare this style of recursion termination // to that of adj; which is easiers? //////////////////////////////////////////////////////////////////////////////////////////// template inline typename std::enable_if,Level>::value, iMatrix >::type transposeIndex (const iMatrix &arg) { iMatrix ret; for(int i=0;i inline typename std::enable_if,Level>::notvalue, iMatrix >::type transposeIndex (const iMatrix &arg) { iMatrix ret; for(int i=0;i(arg._internal[i][j]); }} return ret; } template inline typename std::enable_if,Level>::notvalue, iScalar >::type transposeIndex (const iScalar &arg) { iScalar ret; ret._internal=transposeIndex(arg._internal); return ret; } template inline typename std::enable_if,Level>::value, iScalar >::type transposeIndex (const iScalar &arg) { return arg; } ////////////////////////////////////////////////////////////////// // Traces: both all indices and a specific index ///////////////////////////////////////////////////////////////// inline ComplexF trace( const ComplexF &arg){ return arg;} inline ComplexD trace( const ComplexD &arg){ return arg;} inline RealF trace( const RealF &arg){ return arg;} inline RealD trace( const RealD &arg){ return arg;} template inline ComplexF traceIndex(const ComplexF arg) { return arg;} template inline ComplexD traceIndex(const ComplexD arg) { return arg;} template inline RealF traceIndex(const RealF arg) { return arg;} template inline RealD traceIndex(const RealD arg) { return arg;} template inline auto trace(const iMatrix &arg) -> iScalar { iScalar ret; zeroit(ret._internal); for(int i=0;i inline auto trace(const iScalar &arg) -> iScalar { iScalar ret; ret._internal=trace(arg._internal); return ret; } //////////////////////////////////////////////////////////////////////////////////////////////////////// // Trace Specific indices. //////////////////////////////////////////////////////////////////////////////////////////////////////// /* template inline auto traceIndex(const iScalar &arg) -> iScalar(arg._internal)) > { iScalar(arg._internal))> ret; ret._internal = traceIndex(arg._internal); return ret; } */ template inline auto traceIndex (const iScalar &arg) -> typename std::enable_if,Level>::notvalue, iScalar(arg._internal))> >::type { iScalar(arg._internal))> ret; ret._internal=traceIndex(arg._internal); return ret; } template inline auto traceIndex (const iScalar &arg) -> typename std::enable_if,Level>::value, iScalar >::type { return arg; } // If we hit the right index, return scalar and trace it with no further recursion template inline auto traceIndex(const iMatrix &arg) -> typename std::enable_if,Level>::value, // Index matches iScalar >::type // return scalar { iScalar ret; zeroit(ret._internal); for(int i=0;i inline auto traceIndex(const iMatrix &arg) -> typename std::enable_if,Level>::notvalue,// No index match iMatrix(arg._internal[0][0])),N> >::type // return matrix { iMatrix(arg._internal[0][0])),N> ret; for(int i=0;i(arg._internal[i][j]); }} return ret; } ////////////////////////////////////////////////////////////////////////////// // Peek on a specific index; returns a scalar in that index, tensor inherits rest ////////////////////////////////////////////////////////////////////////////// // If we hit the right index, return scalar with no further recursion //template inline ComplexF peekIndex(const ComplexF arg) { return arg;} //template inline ComplexD peekIndex(const ComplexD arg) { return arg;} //template inline RealF peekIndex(const RealF arg) { return arg;} //template inline RealD peekIndex(const RealD arg) { return arg;} // Scalar peek, no indices template inline auto peekIndex(const iScalar &arg) -> typename std::enable_if,Level>::value, // Index matches iScalar >::type // return scalar { return arg; } // Vector peek, one index template inline auto peekIndex(const iVector &arg,int i) -> typename std::enable_if,Level>::value, // Index matches iScalar >::type // return scalar { iScalar ret; // return scalar ret._internal = arg._internal[i]; return ret; } // Matrix peek, two indices template inline auto peekIndex(const iMatrix &arg,int i,int j) -> typename std::enable_if,Level>::value, // Index matches iScalar >::type // return scalar { iScalar ret; // return scalar ret._internal = arg._internal[i][j]; return ret; } ///////////// // No match peek for scalar,vector,matrix must forward on either 0,1,2 args. Must have 9 routines with notvalue ///////////// // scalar template inline auto peekIndex(const iScalar &arg) -> // Scalar 0 index typename std::enable_if,Level>::notvalue, // Index does NOT match iScalar(arg._internal))> >::type { iScalar(arg._internal))> ret; ret._internal= peekIndex(arg._internal); return ret; } template inline auto peekIndex(const iScalar &arg,int i) -> // Scalar 1 index typename std::enable_if,Level>::notvalue, // Index does NOT match iScalar(arg._internal,i))> >::type { iScalar(arg._internal,i))> ret; ret._internal=peekIndex(arg._internal,i); return ret; } template inline auto peekIndex(const iScalar &arg,int i,int j) -> // Scalar, 2 index typename std::enable_if,Level>::notvalue, // Index does NOT match iScalar(arg._internal,i,j))> >::type { iScalar(arg._internal,i,j))> ret; ret._internal=peekIndex(arg._internal,i,j); return ret; } // vector template inline auto peekIndex(const iVector &arg) -> typename std::enable_if,Level>::notvalue, // Index does not match iVector(arg._internal[0])),N> >::type { iVector(arg._internal[0])),N> ret; for(int ii=0;ii(arg._internal[ii]); } return ret; } template inline auto peekIndex(const iVector &arg,int i) -> typename std::enable_if,Level>::notvalue, // Index does not match iVector(arg._internal[0],i)),N> >::type { iVector(arg._internal[0],i)),N> ret; for(int ii=0;ii(arg._internal[ii],i); } return ret; } template inline auto peekIndex(const iVector &arg,int i,int j) -> typename std::enable_if,Level>::notvalue, // Index does not match iVector(arg._internal[0],i,j)),N> >::type { iVector(arg._internal[0],i,j)),N> ret; for(int ii=0;ii(arg._internal[ii],i,j); } return ret; } // matrix template inline auto peekIndex(const iMatrix &arg) -> typename std::enable_if,Level>::notvalue, // Index does not match iMatrix(arg._internal[0][0])),N> >::type { iMatrix(arg._internal[0][0])),N> ret; for(int ii=0;ii(arg._internal[ii][jj]);// Could avoid this because peeking a scalar is dumb }} return ret; } template inline auto peekIndex(const iMatrix &arg,int i) -> typename std::enable_if,Level>::notvalue, // Index does not match iMatrix(arg._internal[0],i)),N> >::type { iMatrix(arg._internal[0],i)),N> ret; for(int ii=0;ii(arg._internal[ii][jj],i); }} return ret; } template inline auto peekIndex(const iMatrix &arg,int i,int j) -> typename std::enable_if,Level>::notvalue, // Index does not match iMatrix(arg._internal[0][0],i,j)),N> >::type { iMatrix(arg._internal[0][0],i,j)),N> ret; for(int ii=0;ii(arg._internal[ii][jj],i,j); }} return ret; } ////////////////////////////////////////////////////////////////////////////// // Poke a specific index; ////////////////////////////////////////////////////////////////////////////// // Scalar poke template inline void pokeIndex(iScalar &ret, const typename std::enable_if,Level>::value,iScalar >::type &arg) { ret._internal = arg._internal; } // Vector poke, one index template inline void pokeIndex(iVector &ret, const typename std::enable_if,Level>::value,iScalar >::type &arg,int i) { ret._internal[i] = arg._internal; } // Vector poke, two indices template inline void pokeIndex(iMatrix &ret, const typename std::enable_if,Level>::value,iScalar >::type &arg,int i,int j) { ret._internal[i][j] = arg._internal; } ///////////// // No match poke for scalar,vector,matrix must forward on either 0,1,2 args. Must have 9 routines with notvalue ///////////// // scalar template inline void pokeIndex(iScalar &ret, const typename std::enable_if,Level>::notvalue,iScalar(ret._internal))> >::type &arg) { pokeIndex(ret._internal,arg._internal); } template inline void pokeIndex(iScalar &ret, const typename std::enable_if,Level>::notvalue,iScalar(ret._internal,0))> >::type &arg, int i) { pokeIndex(ret._internal,arg._internal,i); } template inline void pokeIndex(iScalar &ret, const typename std::enable_if,Level>::notvalue,iScalar(ret._internal,0,0))> >::type &arg, int i,int j) { pokeIndex(ret._internal,arg._internal,i,j); } // Vector template inline void pokeIndex(iVector &ret, const typename std::enable_if,Level>::notvalue,iVector(ret._internal)),N> >::type &arg) { for(int ii=0;ii(ret._internal[ii],arg._internal[ii]); } } template inline void pokeIndex(iVector &ret, const typename std::enable_if,Level>::notvalue,iVector(ret._internal,0)),N> >::type &arg, int i) { for(int ii=0;ii(ret._internal[ii],arg._internal[ii],i); } } template inline void pokeIndex(iVector &ret, const typename std::enable_if,Level>::notvalue,iVector(ret._internal,0,0)),N> >::type &arg, int i,int j) { for(int ii=0;ii(ret._internal[ii],arg._internal[ii],i,j); } } // Matrix template inline void pokeIndex(iMatrix &ret, const typename std::enable_if,Level>::notvalue,iMatrix(ret._internal)),N> >::type &arg) { for(int ii=0;ii(ret._internal[ii][jj],arg._internal[ii][jj]); }} } template inline void pokeIndex(iMatrix &ret, const typename std::enable_if,Level>::notvalue,iMatrix(ret._internal,0)),N> >::type &arg, int i) { for(int ii=0;ii(ret._internal[ii][jj],arg._internal[ii][jj],i); }} } template inline void pokeIndex(iMatrix &ret, const typename std::enable_if,Level>::notvalue,iMatrix(ret._internal,0,0)),N> >::type &arg, int i,int j) { for(int ii=0;ii(ret._internal[ii][jj],arg._internal[ii][jj],i,j); }} } ///////////////////////////////////////////////////////////////// // Can only take the real/imag part of scalar objects, since // lattice objects of different complex nature are non-conformable. ///////////////////////////////////////////////////////////////// template inline auto real(const iScalar &z) -> iScalar { iScalar ret; ret._internal = real(z._internal); return ret; } template inline auto real(const iMatrix &z) -> iMatrix { iMatrix ret; for(int c1=0;c1 inline auto real(const iVector &z) -> iVector { iVector ret; for(int c1=0;c1 inline auto imag(const iScalar &z) -> iScalar { iScalar ret; ret._internal = imag(z._internal); return ret; } template inline auto imag(const iMatrix &z) -> iMatrix { iMatrix ret; for(int c1=0;c1 inline auto imag(const iVector &z) -> iVector { iVector ret; for(int c1=0;c1