1
0
mirror of https://github.com/paboyle/Grid.git synced 2025-04-11 14:40:46 +01:00

Can write both fixed and dynamic sized tensors

This commit is contained in:
Michael Marshall 2019-02-11 15:47:40 +00:00
parent 6f2663edf6
commit dff7d9261d
2 changed files with 62 additions and 42 deletions

View File

@ -53,7 +53,8 @@ namespace Grid {
typename std::enable_if<std::is_base_of<Serializable, U>::value, void>::type typename std::enable_if<std::is_base_of<Serializable, U>::value, void>::type
write(const std::string& s, const U &output); write(const std::string& s, const U &output);
template <typename U> template <typename U>
typename std::enable_if<!std::is_base_of<Serializable, U>::value, void>::type typename std::enable_if<!std::is_base_of<Serializable, U>::value
&& !std::is_base_of<Eigen::TensorBase<U, Eigen::ReadOnlyAccessors>, U>::value, void>::type
write(const std::string& s, const U &output); write(const std::string& s, const U &output);
template <typename U> template <typename U>
void write(const std::string &s, const iScalar<U> &output); void write(const std::string &s, const iScalar<U> &output);
@ -61,9 +62,12 @@ namespace Grid {
void write(const std::string &s, const iVector<U, N> &output); void write(const std::string &s, const iVector<U, N> &output);
template <typename U, int N> template <typename U, int N>
void write(const std::string &s, const iMatrix<U, N> &output); void write(const std::string &s, const iMatrix<U, N> &output);
template <typename Scalar_, int NumIndices_, int Options_, typename IndexType_> /*template <typename Scalar_, int NumIndices_, int Options_, typename IndexType_>
typename std::enable_if<std::is_arithmetic<Scalar_>::value || Grid::is_complex<Scalar_>::value, void>::type typename std::enable_if<std::is_arithmetic<Scalar_>::value || Grid::is_complex<Scalar_>::value, void>::type
write(const std::string &s, const Eigen::Tensor<Scalar_, NumIndices_, Options_, IndexType_> &output); write(const std::string &s, const Eigen::Tensor<Scalar_, NumIndices_, Options_, IndexType_> &output);*/
template <typename ETensor>
typename std::enable_if<std::is_base_of<Eigen::TensorBase<ETensor, Eigen::ReadOnlyAccessors>, ETensor>::value && (std::is_arithmetic<typename ETensor::Scalar>::value || Grid::is_complex<typename ETensor::Scalar>::value), void>::type
write(const std::string &s, const ETensor &output);
template<typename U, int NumIndices_, int Options_, typename IndexType_> template<typename U, int NumIndices_, int Options_, typename IndexType_>
void write(const std::string &s, const Eigen::Tensor<iScalar<U>, NumIndices_, Options_, IndexType_> &output); void write(const std::string &s, const Eigen::Tensor<iScalar<U>, NumIndices_, Options_, IndexType_> &output);
template<typename U, int N, int NumIndices_, int Options_, typename IndexType_> template<typename U, int N, int NumIndices_, int Options_, typename IndexType_>
@ -146,7 +150,8 @@ namespace Grid {
template <typename T> template <typename T>
template <typename U> template <typename U>
typename std::enable_if<!std::is_base_of<Serializable, U>::value, void>::type typename std::enable_if<!std::is_base_of<Serializable, U>::value
&& !std::is_base_of<Eigen::TensorBase<U, Eigen::ReadOnlyAccessors>, U>::value, void>::type
Writer<T>::write(const std::string &s, const U &output) Writer<T>::write(const std::string &s, const U &output)
{ {
upcast->writeDefault(s, output); upcast->writeDefault(s, output);
@ -176,51 +181,49 @@ namespace Grid {
// Eigen::Tensors of arithmetic/complex base type // Eigen::Tensors of arithmetic/complex base type
template <typename T> template <typename T>
template <typename Scalar_, int NumIndices_, int Options_, typename IndexType_> /*template <typename Scalar_, int NumIndices_, int Options_, typename IndexType_>
typename std::enable_if<std::is_arithmetic<Scalar_>::value || Grid::is_complex<Scalar_>::value, void>::type typename std::enable_if<std::is_arithmetic<Scalar_>::value || Grid::is_complex<Scalar_>::value, void>::type
Writer<T>::write(const std::string &s, const Eigen::Tensor<Scalar_, NumIndices_, Options_, IndexType_> &output) Writer<T>::write(const std::string &s, const Eigen::Tensor<Scalar_, NumIndices_, Options_, IndexType_> &output)*/
template <typename ETensor>
typename std::enable_if<std::is_base_of<Eigen::TensorBase<ETensor, Eigen::ReadOnlyAccessors>, ETensor>::value && (std::is_arithmetic<typename ETensor::Scalar>::value || Grid::is_complex<typename ETensor::Scalar>::value), void>::type
Writer<T>::write(const std::string &s, const ETensor &output)
{ {
typedef Eigen::Tensor<Scalar_, NumIndices_, Options_, IndexType_> Tensor; //typedef Eigen::Tensor<Scalar_, NumIndices_, Options_, IndexType_> Tensor;
const typename Tensor::Index NumElements{output.size()}; //typedef Eigen::TensorBase<ETensor, Eigen::ReadOnlyAccessors> Tensor;
const typename ETensor::Index NumElements{output.size()};
assert( NumElements > 0 ); assert( NumElements > 0 );
if( NumElements == 1 ) if( NumElements == 1 )
upcast->writeDefault(s, * output.data()); upcast->writeDefault(s, * output.data());
else { else {
// Create a single, flat vector to hold all the data // Create a single, flat vector to hold all the data
std::vector<Scalar_> flat(NumElements); std::vector<typename ETensor::Scalar> flat(NumElements);
// We're not interested in trivial dimensions, i.e. dimensions = 1 // We're not interested in trivial dimensions, i.e. dimensions = 1
const typename Tensor::Dimensions & DimsOriginal{output.dimensions()};
assert(DimsOriginal.size() == NumIndices_);
unsigned int TrivialDimCount{0}; unsigned int TrivialDimCount{0};
for(auto i : DimsOriginal ) { std::vector<size_t> ReducedDims;
if( i <= 1 ) { for(auto i = 0; i < output.NumDimensions; i++ ) {
auto dim = output.dimension(i);
if( dim <= 1 ) {
TrivialDimCount++; TrivialDimCount++;
assert( i == 1 ); // Not expecting dimension to be <= 0 assert( dim == 1 ); // Not expecting dimension to be <= 0
} } else {
} size_t s = static_cast<size_t>(dim);
const unsigned int ReducedDimCount{NumIndices_ - TrivialDimCount}; assert( s == dim ); // check we didn't lose anything in the conversion
assert( ReducedDimCount > 0 ); // NB: We've already checked this is not a scalar ReducedDims.push_back(s);
// Save a flat vector of the non-trivial dimensions
std::vector<size_t> ReducedDims(ReducedDimCount);
unsigned int ui = 0;
for(auto i : DimsOriginal ) {
if( i > 1 ) {
ReducedDims[ui] = static_cast<size_t>(i);
assert( ReducedDims[ui] == i ); // check we didn't lose anything in the conversion
ui++;
} }
} }
const unsigned int ReducedDimCount{output.NumDimensions - TrivialDimCount};
assert( ReducedDimCount > 0 ); // NB: NumElements > 1 implies this is not a scalar
// Now copy all the data to my flat vector // Now copy all the data to my flat vector
// Regardless of the Eigen::Tensor storage order, the copy will be Row Major // Regardless of the Eigen::Tensor storage order, the copy will be Row Major
std::array<typename Tensor::Index, NumIndices_> MyIndex; std::array<typename ETensor::Index, ETensor::NumIndices> MyIndex;
for( int i = 0 ; i < NumIndices_ ; i++ ) MyIndex[i] = 0; for( int i = 0 ; i < output.NumDimensions ; i++ ) MyIndex[i] = 0;
for( typename Tensor::Index n = 0; n < NumElements; n++ ) { for( typename ETensor::Index n = 0; n < NumElements; n++ ) {
flat[n] = output( MyIndex ); flat[n] = output( MyIndex );
// Now increment the index // Now increment the index
for( int i = NumIndices_ - 1; i >= 0 && ++MyIndex[i] == DimsOriginal[i]; i-- ) for( int i = output.NumDimensions - 1; i >= 0 && ++MyIndex[i] == output.dimension(i); i-- )
MyIndex[i] = 0; MyIndex[i] = 0;
} }
upcast->template writeMultiDim<Scalar_>(s, ReducedDims, flat); upcast->template writeMultiDim<typename ETensor::Scalar>(s, ReducedDims, flat);
} }
} }
@ -380,14 +383,15 @@ namespace Grid {
} }
template <typename T> template <typename T>
static inline bool CompareMember(const T &lhs, const T &rhs) { static inline typename std::enable_if<!std::is_base_of<Eigen::TensorBase<T, Eigen::ReadOnlyAccessors>, T>::value, bool>::type
CompareMember(const T &lhs, const T &rhs) {
return lhs == rhs; return lhs == rhs;
} }
template <typename Scalar_, int NumIndices_, int Options_, typename Index_> template <typename T>
static inline bool CompareMember(const Eigen::Tensor<Scalar_, NumIndices_, Options_, Index_> &lhs, static inline typename std::enable_if<std::is_base_of<Eigen::TensorBase<T, Eigen::ReadOnlyAccessors>, T>::value, bool>::type
const Eigen::Tensor<Scalar_, NumIndices_, Options_, Index_> &rhs) { CompareMember(const T &lhs, const T &rhs) {
Eigen::Tensor<bool, 0, Options_, Index_> bResult = (lhs == rhs).all(); Eigen::Tensor<bool, 0> bResult = (lhs == rhs).all();
return bResult(0); return bResult(0);
} }
}; };

View File

@ -446,16 +446,18 @@ typedef Eigen::Tensor<OddBall, 3> TensorOddBall;
//typedef int TestScalar; //typedef int TestScalar;
typedef std::complex<double> TestScalar; typedef std::complex<double> TestScalar;
typedef Eigen::Tensor<TestScalar, 3> TestTensor; typedef Eigen::Tensor<TestScalar, 3> TestTensor;
typedef Eigen::TensorFixedSize<TestScalar, Eigen::Sizes<9,4,2>> TestTensorFixed;
// From Test_serialisation.cc // From Test_serialisation.cc
class myclass: Serializable { class myclass: Serializable {
public: public:
GRID_SERIALIZABLE_CLASS_MEMBERS(myclass GRID_SERIALIZABLE_CLASS_MEMBERS(myclass
, TestTensor, critter , TestTensor, Critter
, TestTensorFixed, FixedCritter
, SpinColourVector, scv , SpinColourVector, scv
, SpinColourMatrix, scm , SpinColourMatrix, scm
); );
myclass() : critter(7,3,2) {} myclass() : Critter(7,3,2) {}
}; };
template <typename W, typename R, typename O> template <typename W, typename R, typename O>
@ -503,6 +505,9 @@ eval Eigen::TensorForcedEvalOp<const Eigen::TensorCwiseBinaryOp<Eigen::internal
} }
*/ */
template <typename T> constexpr T Inc{1,-1};
//template <> constexpr std::complex<double> Inc< < std::complex<double> > >{1,1};
bool DebugIOTest(void) { bool DebugIOTest(void) {
OddBall critter; OddBall critter;
ioTest<Hdf5Writer, Hdf5Reader, OddBall>("iotest_oddball.h5", critter, "OddBall"); ioTest<Hdf5Writer, Hdf5Reader, OddBall>("iotest_oddball.h5", critter, "OddBall");
@ -512,18 +517,17 @@ bool DebugIOTest(void) {
ioTest<Hdf5Writer, Hdf5Reader, SpinColourVector>("iotest_vector.h5", scv, "SpinColourVector"); ioTest<Hdf5Writer, Hdf5Reader, SpinColourVector>("iotest_vector.h5", scv, "SpinColourVector");
TestTensor t(3,6,2); TestTensor t(3,6,2);
TestScalar Val{1}; TestScalar Val{Inc<TestScalar>};
const TestScalar Inc{1};
for( int i = 0 ; i < 3 ; i++) for( int i = 0 ; i < 3 ; i++)
for( int j = 0 ; j < 6 ; j++) for( int j = 0 ; j < 6 ; j++)
for( int k = 0 ; k < 2 ; k++) { for( int k = 0 ; k < 2 ; k++) {
t(i,j,k) = Val; t(i,j,k) = Val;
Val += Inc; Val += Inc<TestScalar>;
} }
ioTest<Hdf5Writer, Hdf5Reader, TestTensor>("iotest_tensor.h5", t, "eigen_tensor_instance_name"); ioTest<Hdf5Writer, Hdf5Reader, TestTensor>("iotest_tensor.h5", t, "eigen_tensor_instance_name");
TestTensor t2(t); TestTensor t2(t);
t2(1,1,1) += Inc; t2(1,1,1) += Inc<TestScalar>;
Eigen::Tensor<bool, 0> rResult = (t == t2).all(); Eigen::Tensor<bool, 0> rResult = (t == t2).all();
if( rResult(0) ) if( rResult(0) )
std::cout << "t2 == t" << std::endl; std::cout << "t2 == t" << std::endl;
@ -531,6 +535,18 @@ bool DebugIOTest(void) {
std::cout << "t2 != t" << std::endl; std::cout << "t2 != t" << std::endl;
//std::cout << "(t == t2) : " << (t == t2).all()(0) << std::endl; //std::cout << "(t == t2) : " << (t == t2).all()(0) << std::endl;
// Now serialise a fixed size tensor
using FixedTensor = Eigen::TensorFixedSize<TestScalar, Eigen::Sizes<8,4,3>>;
FixedTensor tf;
Val = Inc<TestScalar>;
for( int i = 0 ; i < 8 ; i++)
for( int j = 0 ; j < 4 ; j++)
for( int k = 0 ; k < 3 ; k++) {
tf(i,j,k) = Val;
Val += Inc<TestScalar>;
}
ioTest<Hdf5Writer, Hdf5Reader, FixedTensor>("iotest_tensor_fixed.h5", tf, "eigen_tensor_fixed_name");
myclass o; myclass o;
ioTest<Hdf5Writer, Hdf5Reader, myclass>("iotest_object.h5", o, "myclass_object_instance_name"); ioTest<Hdf5Writer, Hdf5Reader, myclass>("iotest_object.h5", o, "myclass_object_instance_name");