1
0
mirror of https://github.com/paboyle/Grid.git synced 2025-04-09 05:30:46 +01:00
Grid/Grid/tensors/Tensor_class.h
2019-08-14 13:08:01 +01:00

457 lines
16 KiB
C++

/*************************************************************************************
Grid physics library, www.github.com/paboyle/Grid
Source file: ./lib/tensors/Tensor_class.h
Copyright (C) 2015
Author: Azusa Yamaguchi <ayamaguc@staffmail.ed.ac.uk>
Author: Peter Boyle <paboyle@ph.ed.ac.uk>
Author: Michael Marshall <michael.marshall@ed.ac.au>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
See the full license in the file "LICENSE" in the top level distribution
directory
*************************************************************************************/
/* END LEGAL */
#pragma once
NAMESPACE_BEGIN(Grid);
///////////////////////////////////////////////////
// Scalar, Vector, Matrix objects.
// These can be composed to form tensor products of internal indices.
///////////////////////////////////////////////////
// It is useful to NOT have any constructors
// so that these classes assert "is_pod<class> == true"
// because then the standard C++ valarray container eliminates fill overhead on
// new allocation and
// non-move copying.
//
// However note that doing this eliminates some syntactical sugar such as
// calling the constructor explicitly or implicitly
//
class GridTensorBase {};
// Too late to remove these traits from Grid Tensors, so inherit from GridTypeMapper
#define GridVector_CopyTraits \
using element = vtype; \
using scalar_type = typename Traits::scalar_type; \
using vector_type = typename Traits::vector_type; \
using scalar_typeD = typename Traits::scalar_typeD; \
using vector_typeD = typename Traits::vector_typeD; \
using tensor_reduced = typename Traits::tensor_reduced; \
using scalar_object = typename Traits::scalar_object; \
using scalar_objectD = typename Traits::scalar_objectD; \
using Complexified = typename Traits::Complexified; \
using Realified = typename Traits::Realified; \
using DoublePrecision = typename Traits::DoublePrecision; \
static constexpr int TensorLevel = Traits::TensorLevel
template <class vtype>
class iScalar {
public:
vtype _internal;
using Traits = GridTypeMapper<iScalar<vtype> >;
GridVector_CopyTraits;
static accelerator_inline constexpr int Nsimd(void) { return sizeof(vector_type)/sizeof(scalar_type); }
// Scalar no action
accelerator iScalar() = default;
friend accelerator_inline void zeroit(iScalar<vtype> &that){
zeroit(that._internal);
}
accelerator_inline iScalar(scalar_type s) : _internal(s){}; // recurse down and hit the constructor for vector_type
accelerator_inline iScalar(const Zero &z) { zeroit(*this); };
accelerator_inline iScalar<vtype> &operator=(const Zero &hero) {
zeroit(*this); return *this;
}
friend accelerator_inline void vstream(iScalar<vtype> &out, const iScalar<vtype> &in) {
vstream(out._internal, in._internal);
}
friend accelerator_inline void vbroadcast(iScalar<vtype> &out,const iScalar<vtype> &in,int lane){
vbroadcast(out._internal,in._internal,lane);
}
friend accelerator_inline void prefetch(iScalar<vtype> &that) {
prefetch(that._internal);
}
friend accelerator_inline void permute(iScalar<vtype> &out, const iScalar<vtype> &in, int permutetype) {
permute(out._internal, in._internal, permutetype);
}
friend accelerator_inline void rotate(iScalar<vtype> &out,const iScalar<vtype> &in,int rot){
rotate(out._internal,in._internal,rot);
}
friend accelerator_inline void exchange(iScalar<vtype> &out1,iScalar<vtype> &out2,
const iScalar<vtype> &in1,const iScalar<vtype> &in2,int type)
{
exchange(out1._internal,out2._internal,in1._internal, in2._internal,type);
}
// Unary negation
friend accelerator_inline iScalar<vtype> operator-(const iScalar<vtype> &r) {
iScalar<vtype> ret;
ret._internal = -r._internal;
return ret;
}
// *=,+=,-= operators inherit from corresponding "*,-,+" behaviour
accelerator_inline iScalar<vtype> &operator*=(const iScalar<vtype> &r) {
*this = (*this) * r;
return *this;
}
accelerator_inline iScalar<vtype> &operator-=(const iScalar<vtype> &r) {
*this = (*this) - r;
return *this;
}
accelerator_inline iScalar<vtype> &operator+=(const iScalar<vtype> &r) {
*this = (*this) + r;
return *this;
}
accelerator_inline vtype &operator()(void) { return _internal; }
accelerator_inline const vtype &operator()(void) const { return _internal; }
// Type casts meta programmed, must be pure scalar to match TensorRemove
template <class U = vtype, class V = scalar_type, IfComplex<V> = 0, IfNotSimd<U> = 0> accelerator_inline
operator ComplexF() const {
return (TensorRemove(_internal));
}
template <class U = vtype, class V = scalar_type, IfComplex<V> = 0, IfNotSimd<U> = 0> accelerator_inline
operator ComplexD() const {
return (TensorRemove(_internal));
}
template <class U = vtype, class V = scalar_type, IfReal<V> = 0,IfNotSimd<U> = 0> accelerator_inline
operator RealD() const {
return TensorRemove(_internal);
}
template <class U = vtype, class V = scalar_type, IfInteger<V> = 0, IfNotSimd<U> = 0> accelerator_inline
operator Integer() const {
return Integer(TensorRemove(_internal));
}
// convert from a something to a scalar via constructor of something arg
template <class T, typename std::enable_if<!isGridTensor<T>::value, T>::type * = nullptr>
accelerator_inline iScalar<vtype> operator=(T arg) {
_internal = arg;
return *this;
}
// Convert elements
template <class ttype>
accelerator_inline iScalar<vtype> operator=(const iScalar<ttype> &arg) {
_internal = arg._internal;
return *this;
}
// Host only
friend std::ostream &operator<<(std::ostream &stream,const iScalar<vtype> &o) {
stream << "S {" << o._internal << "}";
return stream;
};
strong_inline const scalar_type * begin() const { return reinterpret_cast<const scalar_type *>(&_internal); }
strong_inline scalar_type * begin() { return reinterpret_cast< scalar_type *>(&_internal); }
strong_inline const scalar_type * end() const { return begin() + Traits::count; }
strong_inline scalar_type * end() { return begin() + Traits::count; }
};
///////////////////////////////////////////////////////////
// Allows to turn scalar<scalar<scalar<double>>>> back to double.
///////////////////////////////////////////////////////////
template <class T>
accelerator_inline typename std::enable_if<!isGridTensor<T>::value, T>::type
TensorRemove(T arg) {
return arg;
}
template <class vtype>
accelerator_inline auto TensorRemove(iScalar<vtype> arg)
-> decltype(TensorRemove(arg._internal)) {
return TensorRemove(arg._internal);
}
template <class vtype, int N>
class iVector {
public:
vtype _internal[N];
using Traits = GridTypeMapper<iVector<vtype, N> >;
GridVector_CopyTraits;
static accelerator_inline constexpr int Nsimd(void) { return sizeof(vector_type)/sizeof(scalar_type); }
template <class T, typename std::enable_if<!isGridTensor<T>::value, T>::type * = nullptr>
accelerator_inline auto operator=(T arg) -> iVector<vtype, N> {
zeroit(*this);
for (int i = 0; i < N; i++) _internal[i] = arg;
return *this;
}
accelerator iVector() = default;
accelerator_inline iVector(const Zero &z) { zeroit(*this); };
template<class other>
accelerator_inline iVector<vtype, N> &operator=(const iVector<other,N> &him)
{
for (int i = 0; i < N; i++) {
_internal[i] = him._internal[i];
}
return *this;
}
accelerator_inline iVector<vtype, N> &operator=(const Zero &hero) {
zeroit(*this);
return *this;
}
friend accelerator_inline void zeroit(iVector<vtype, N> &that) {
for (int i = 0; i < N; i++) {
zeroit(that._internal[i]);
}
}
friend accelerator_inline void prefetch(iVector<vtype, N> &that) {
for (int i = 0; i < N; i++) prefetch(that._internal[i]);
}
friend accelerator_inline void vstream(iVector<vtype, N> &out, const iVector<vtype, N> &in) {
for (int i = 0; i < N; i++) {
vstream(out._internal[i], in._internal[i]);
}
}
friend accelerator_inline void vbroadcast(iVector<vtype,N> &out,const iVector<vtype,N> &in,int lane){
for(int i=0;i<N;i++){
vbroadcast(out._internal[i],in._internal[i],lane);
}
}
friend accelerator_inline void permute(iVector<vtype,N> &out,const iVector<vtype,N> &in,int permutetype){
for(int i=0;i<N;i++){
permute(out._internal[i],in._internal[i],permutetype);
}
}
friend accelerator_inline void rotate(iVector<vtype,N> &out,const iVector<vtype,N> &in,int rot){
for(int i=0;i<N;i++){
rotate(out._internal[i],in._internal[i],rot);
}
}
friend accelerator_inline void exchange(iVector<vtype,N> &out1,iVector<vtype,N> &out2,
const iVector<vtype,N> &in1,const iVector<vtype,N> &in2,int type){
for(int i=0;i<N;i++){
exchange(out1._internal[i],out2._internal[i],in1._internal[i], in2._internal[i],type);
}
}
// Unary negation
friend accelerator_inline iVector<vtype, N> operator-(const iVector<vtype, N> &r) {
iVector<vtype, N> ret;
for (int i = 0; i < N; i++) ret._internal[i] = -r._internal[i];
return ret;
}
// *=,+=,-= operators inherit from corresponding "*,-,+" behaviour
accelerator_inline iVector<vtype, N> &operator*=(const iScalar<vtype> &r) {
*this = (*this) * r;
return *this;
}
accelerator_inline iVector<vtype, N> &operator-=(const iVector<vtype, N> &r) {
*this = (*this) - r;
return *this;
}
accelerator_inline iVector<vtype, N> &operator+=(const iVector<vtype, N> &r) {
*this = (*this) + r;
return *this;
}
accelerator_inline vtype &operator()(int i) { return _internal[i]; }
accelerator_inline const vtype &operator()(int i) const { return _internal[i]; }
// Host
friend std::ostream &operator<<(std::ostream &stream, const iVector<vtype, N> &o) {
stream << "V<" << N << ">{";
for (int i = 0; i < N; i++) {
stream << o._internal[i];
if (i < N - 1) stream << ",";
}
stream << "}";
return stream;
};
// strong_inline vtype && operator ()(int i) {
// return _internal[i];
// }
strong_inline const scalar_type * begin() const { return reinterpret_cast<const scalar_type *>(_internal); }
strong_inline scalar_type * begin() { return reinterpret_cast< scalar_type *>(_internal); }
strong_inline const scalar_type * end() const { return begin() + Traits::count; }
strong_inline scalar_type * end() { return begin() + Traits::count; }
};
template <class vtype, int N>
class iMatrix {
public:
vtype _internal[N][N];
using Traits = GridTypeMapper<iMatrix<vtype, N> >;
GridVector_CopyTraits;
static accelerator_inline constexpr int Nsimd(void) { return sizeof(vector_type)/sizeof(scalar_type); }
accelerator_inline iMatrix(const Zero &z) { zeroit(*this); };
accelerator iMatrix() = default;
// Allow for type conversion.
template<class other>
accelerator_inline iMatrix &operator=(const iMatrix<other,N> &rhs) {
for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++)
_internal[i][j] = rhs._internal[i][j];
return *this;
};
accelerator_inline iMatrix(scalar_type s) {
(*this) = s;
}; // recurse down and hit the constructor for vector_type
accelerator_inline iMatrix<vtype, N> &operator=(const Zero &hero) {
zeroit(*this);
return *this;
}
template <class T, typename std::enable_if<!isGridTensor<T>::value, T>::type * = nullptr>
accelerator_inline auto operator=(T arg) -> iMatrix<vtype, N> {
zeroit(*this);
for (int i = 0; i < N; i++) _internal[i][i] = arg;
return *this;
}
friend accelerator_inline void zeroit(iMatrix<vtype,N> &that){
for(int i=0;i<N;i++){
for(int j=0;j<N;j++){
zeroit(that._internal[i][j]);
}}
}
friend accelerator_inline void prefetch(iMatrix<vtype,N> &that){
for(int i=0;i<N;i++) {
for(int j=0;j<N;j++) {
prefetch(that._internal[i][j]);
}}
}
friend accelerator_inline void vstream(iMatrix<vtype,N> &out,const iMatrix<vtype,N> &in){
for(int i=0;i<N;i++){
for(int j=0;j<N;j++){
vstream(out._internal[i][j],in._internal[i][j]);
}}
}
friend accelerator_inline void vbroadcast(iMatrix<vtype,N> &out,const iMatrix<vtype,N> &in,int lane){
for(int i=0;i<N;i++){
for(int j=0;j<N;j++){
vbroadcast(out._internal[i][j],in._internal[i][j],lane);
}}
}
friend accelerator_inline void permute(iMatrix<vtype,N> &out,const iMatrix<vtype,N> &in,int permutetype){
for(int i=0;i<N;i++){
for(int j=0;j<N;j++){
permute(out._internal[i][j],in._internal[i][j],permutetype);
}}
}
friend accelerator_inline void rotate(iMatrix<vtype,N> &out,const iMatrix<vtype,N> &in,int rot){
for(int i=0;i<N;i++){
for(int j=0;j<N;j++){
rotate(out._internal[i][j],in._internal[i][j],rot);
}}
}
friend accelerator_inline void exchange(iMatrix<vtype,N> &out1,iMatrix<vtype,N> &out2,
const iMatrix<vtype,N> &in1,const iMatrix<vtype,N> &in2,int type){
for(int i=0;i<N;i++){
for(int j=0;j<N;j++){
exchange(out1._internal[i][j],out2._internal[i][j],in1._internal[i][j], in2._internal[i][j],type);
}}
}
// Unary negation
friend accelerator_inline iMatrix<vtype, N> operator-(const iMatrix<vtype, N> &r) {
iMatrix<vtype, N> ret;
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
ret._internal[i][j] = -r._internal[i][j];
}}
return ret;
}
// *=,+=,-= operators inherit from corresponding "*,-,+" behaviour
template <class T>
accelerator_inline iMatrix<vtype, N> &operator*=(const T &r) {
*this = (*this) * r;
return *this;
}
template <class T>
accelerator_inline iMatrix<vtype, N> &operator-=(const T &r) {
*this = (*this) - r;
return *this;
}
template <class T>
accelerator_inline iMatrix<vtype, N> &operator+=(const T &r) {
*this = (*this) + r;
return *this;
}
// returns an lvalue reference
accelerator_inline vtype &operator()(int i, int j) { return _internal[i][j]; }
accelerator_inline const vtype &operator()(int i, int j) const {
return _internal[i][j];
}
// Host function only
friend std::ostream &operator<<(std::ostream &stream, const iMatrix<vtype, N> &o) {
stream << "M<" << N << ">{";
for (int i = 0; i < N; i++) {
stream << "{";
for (int j = 0; j < N; j++) {
stream << o._internal[i][j];
if (i < N - 1) stream << ",";
}
stream << "}";
if (i != N - 1) stream << "\n\t\t";
}
stream << "}";
return stream;
};
// strong_inline vtype && operator ()(int i,int j) {
// return _internal[i][j];
// }
strong_inline const scalar_type * begin() const { return reinterpret_cast<const scalar_type *>(_internal[0]); }
strong_inline scalar_type * begin() { return reinterpret_cast< scalar_type *>(_internal[0]); }
strong_inline const scalar_type * end() const { return begin() + Traits::count; }
strong_inline scalar_type * end() { return begin() + Traits::count; }
};
template <class v> accelerator_inline
void vprefetch(const iScalar<v> &vv) {
vprefetch(vv._internal);
}
template <class v, int N> accelerator_inline
void vprefetch(const iVector<v, N> &vv) {
for (int i = 0; i < N; i++) {
vprefetch(vv._internal[i]);
}
}
template <class v, int N> accelerator_inline
void vprefetch(const iMatrix<v, N> &vv) {
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
vprefetch(vv._internal[i][j]);
}
}
}
NAMESPACE_END(Grid);