/************************************************************************************* Grid physics library, www.github.com/paboyle/Grid Source file: ./Grid/serialisation/VectorUtils.h Copyright (C) 2015 Author: Antonin Portelli Author: Peter Boyle Author: paboyle Author: Michael Marshall 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 */ #ifndef GRID_SERIALISATION_VECTORUTILS_H #define GRID_SERIALISATION_VECTORUTILS_H #include #include namespace Grid { // Pair IO utilities ///////////////////////////////////////////////////////// // helper function to parse input in the format "" template inline std::istream & operator>>(std::istream &is, std::pair &buf) { T1 buf1; T2 buf2; char c; // Search for "pair" delimiters. do { is.get(c); } while (c != '(' && !is.eof()); if (c == '(') { int start = is.tellg(); do { is.get(c); } while (c != ')' && !is.eof()); if (c == ')') { int end = is.tellg(); int psize = end - start - 1; // Only read data between pair limiters. is.seekg(start); std::string tmpstr(psize, ' '); is.read(&tmpstr[0], psize); std::istringstream temp(tmpstr); temp >> buf1 >> buf2; buf = std::make_pair(buf1, buf2); is.seekg(end); } } is.peek(); return is; } // output to streams for pairs template inline std::ostream & operator<<(std::ostream &os, const std::pair &p) { os << "(" << p.first << " " << p.second << ")"; return os; } // std::vector> nested to specified Rank ////////////////////////////////// template struct NestedStdVector { typedef typename std::vector::type> type; }; template struct NestedStdVector { typedef T type; }; // Grid scalar tensors to nested std::vectors ////////////////////////////////// template struct TensorToVec { typedef T type; }; template struct TensorToVec> { typedef typename TensorToVec::type type; }; template struct TensorToVec> { typedef typename std::vector::type> type; }; template struct TensorToVec> { typedef typename std::vector::type>> type; }; template void tensorDim(std::vector &dim, const T &t, const bool wipe = true) { if (wipe) { dim.clear(); } } template void tensorDim(std::vector &dim, const iScalar &t, const bool wipe = true) { if (wipe) { dim.clear(); } tensorDim(dim, t._internal, false); } template void tensorDim(std::vector &dim, const iVector &t, const bool wipe = true) { if (wipe) { dim.clear(); } dim.push_back(N); tensorDim(dim, t._internal[0], false); } template void tensorDim(std::vector &dim, const iMatrix &t, const bool wipe = true) { if (wipe) { dim.clear(); } dim.push_back(N); dim.push_back(N); tensorDim(dim, t._internal[0][0], false); } template typename TensorToVec::type tensorToVec(const T &t) { return t; } template typename TensorToVec>::type tensorToVec(const iScalar& t) { return tensorToVec(t._internal); } template typename TensorToVec>::type tensorToVec(const iVector& t) { typename TensorToVec>::type v; v.resize(N); for (unsigned int i = 0; i < N; i++) { v[i] = tensorToVec(t._internal[i]); } return v; } template typename TensorToVec>::type tensorToVec(const iMatrix& t) { typename TensorToVec>::type v; v.resize(N); for (unsigned int i = 0; i < N; i++) { v[i].resize(N); for (unsigned int j = 0; j < N; j++) { v[i][j] = tensorToVec(t._internal[i][j]); } } return v; } template void vecToTensor(T &t, const typename TensorToVec::type &v) { t = v; } template void vecToTensor(iScalar &t, const typename TensorToVec>::type &v) { vecToTensor(t._internal, v); } template void vecToTensor(iVector &t, const typename TensorToVec>::type &v) { for (unsigned int i = 0; i < N; i++) { vecToTensor(t._internal[i], v[i]); } } template void vecToTensor(iMatrix &t, const typename TensorToVec>::type &v) { for (unsigned int i = 0; i < N; i++) for (unsigned int j = 0; j < N; j++) { vecToTensor(t._internal[i][j], v[i][j]); } } // is_flattenable::value is true if T is a std::vector<> which can be flattened ////////////////////// template struct is_flattenable : std::false_type { using type = T; using grid_type = T; static constexpr int vecRank = 0; static constexpr bool isGridTensor = false; static constexpr bool children_flattenable = std::is_arithmetic::value or is_complex::value; }; template struct is_flattenable::value>::type> : std::false_type { using type = typename GridTypeMapper::scalar_type; using grid_type = T; static constexpr int vecRank = 0; static constexpr bool isGridTensor = true; static constexpr bool children_flattenable = true; }; template struct is_flattenable, typename std::enable_if::children_flattenable>::type> : std::true_type { using type = typename is_flattenable::type; using grid_type = typename is_flattenable::grid_type; static constexpr bool isGridTensor = is_flattenable::isGridTensor; static constexpr int vecRank = is_flattenable::vecRank + 1; static constexpr bool children_flattenable = true; }; // Vector flattening utility class //////////////////////////////////////////// // Class to flatten a multidimensional std::vector template class Flatten { public: using Scalar = typename is_flattenable::type; static constexpr bool isGridTensor = is_flattenable::isGridTensor; public: explicit Flatten(const V &vector); const V & getVector(void) const { return vector_; } const std::vector & getFlatVector(void) const { return flatVector_; } const std::vector & getDim(void) const { return dim_; } private: template typename std::enable_if::value && !is_flattenable::isGridTensor>::type accumulate(const W &e); template typename std::enable_if::value && is_flattenable::isGridTensor>::type accumulate(const W &e); template typename std::enable_if< is_flattenable::value>::type accumulate(const W &v); template typename std::enable_if::value && !is_flattenable::isGridTensor>::type accumulateDim(const W &e) {} // Innermost is a scalar - do nothing template typename std::enable_if::value && is_flattenable::isGridTensor>::type accumulateDim(const W &e); template typename std::enable_if< is_flattenable::value>::type accumulateDim(const W &v); private: const V &vector_; std::vector flatVector_; std::vector dim_; }; // Class to reconstruct a multidimensional std::vector template class Reconstruct { public: using Scalar = typename is_flattenable::type; static constexpr bool isGridTensor = is_flattenable::isGridTensor; public: Reconstruct(const std::vector &flatVector, const std::vector &dim); const V & getVector(void) const { return vector_; } const std::vector & getFlatVector(void) const { return flatVector_; } const std::vector & getDim(void) const { return dim_; } private: template typename std::enable_if::value && !is_flattenable::isGridTensor>::type fill(W &v); template typename std::enable_if::value && is_flattenable::isGridTensor>::type fill(W &v); template typename std::enable_if< is_flattenable::value>::type fill(W &v); template typename std::enable_if< is_flattenable::value && is_flattenable::vecRank==1>::type resize(W &v, const unsigned int dim); template typename std::enable_if< is_flattenable::value && (is_flattenable::vecRank>1)>::type resize(W &v, const unsigned int dim); template typename std::enable_if::isGridTensor>::type checkInnermost(const W &e) {} // Innermost is a scalar - do nothing template typename std::enable_if< is_flattenable::isGridTensor>::type checkInnermost(const W &e); private: V vector_; const std::vector &flatVector_; std::vector dim_; size_t ind_{0}; unsigned int dimInd_{0}; }; // Flatten class template implementation template template typename std::enable_if::value && !is_flattenable::isGridTensor>::type Flatten::accumulate(const W &e) { flatVector_.push_back(e); } template template typename std::enable_if::value && is_flattenable::isGridTensor>::type Flatten::accumulate(const W &e) { for (const Scalar &x: e) { flatVector_.push_back(x); } } template template typename std::enable_if::value>::type Flatten::accumulate(const W &v) { for (auto &e: v) { accumulate(e); } } template template typename std::enable_if::value && is_flattenable::isGridTensor>::type Flatten::accumulateDim(const W &e) { using Traits = GridTypeMapper::grid_type>; for (int rank=0; rank < Traits::Rank; ++rank) dim_.push_back(Traits::Dimension(rank)); } template template typename std::enable_if::value>::type Flatten::accumulateDim(const W &v) { dim_.push_back(v.size()); accumulateDim(v[0]); } template Flatten::Flatten(const V &vector) : vector_(vector) { accumulateDim(vector_); std::size_t TotalSize{ dim_[0] }; for (int i = 1; i < dim_.size(); ++i) { TotalSize *= dim_[i]; } flatVector_.reserve(TotalSize); accumulate(vector_); } // Reconstruct class template implementation template template typename std::enable_if::value && !is_flattenable::isGridTensor>::type Reconstruct::fill(W &v) { v = flatVector_[ind_++]; } template template typename std::enable_if::value && is_flattenable::isGridTensor>::type Reconstruct::fill(W &v) { for (auto &e: v) { e = flatVector_[ind_++]; } } template template typename std::enable_if::value>::type Reconstruct::fill(W &v) { for (auto &e: v) { fill(e); } } template template typename std::enable_if::value && is_flattenable::vecRank==1>::type Reconstruct::resize(W &v, const unsigned int dim) { v.resize(dim_[dim]); } template template typename std::enable_if::value && (is_flattenable::vecRank>1)>::type Reconstruct::resize(W &v, const unsigned int dim) { v.resize(dim_[dim]); for (auto &e: v) { resize(e, dim + 1); } } template template typename std::enable_if::isGridTensor>::type Reconstruct::checkInnermost(const W &) { using Traits = GridTypeMapper::grid_type>; const int gridRank{Traits::Rank}; const int dimRank{static_cast(dim_.size())}; assert(dimRank >= gridRank && "Tensor rank too low for Grid tensor"); for (int i=0; i Reconstruct::Reconstruct(const std::vector &flatVector, const std::vector &dim) : flatVector_(flatVector) , dim_(dim) { checkInnermost(vector_); assert(dim_.size() == is_flattenable::vecRank && "Tensor rank doesn't match nested std::vector rank"); resize(vector_, 0); fill(vector_); } // Vector IO utilities /////////////////////////////////////////////////////// // helper function to read space-separated values template std::vector strToVec(const std::string s) { std::istringstream sstr(s); std::vector v; for(T buf; sstr >> buf;) { v.push_back(buf); } return v; } // output to streams for vectors template < class T > inline std::ostream & operator<<(std::ostream &os, const std::vector &v) { os << "["; for (unsigned int i = 0; i < v.size(); ++i) { os << v[i]; if (i < v.size() - 1) { os << " "; } } os << "]"; return os; } // In general, scalar types are considered "flattenable" (regularly shaped) template bool isRegularShapeHelper(const std::vector &, std::vector &, int, bool) { return true; } template bool isRegularShapeHelper(const std::vector> &v, std::vector &Dims, int Depth, bool bFirst) { if( bFirst) { assert( Dims.size() == Depth && "Bug: Delete this message after testing" ); Dims.push_back(v[0].size()); if (!Dims[Depth]) return false; } else { assert( Dims.size() >= Depth + 1 && "Bug: Delete this message after testing" ); } for (std::size_t i = 0; i < v.size(); ++i) { if (v[i].size() != Dims[Depth] || !isRegularShapeHelper(v[i], Dims, Depth + 1, bFirst && i==0)) { return false; } } return true; } template bool isRegularShape(const T &t) { return true; } template bool isRegularShape(const std::vector &v) { return !v.empty(); } // Return non-zero if all dimensions of this std::vector> are regularly shaped template bool isRegularShape(const std::vector> &v) { if (v.empty() || v[0].empty()) return false; // Make sure all of my rows are the same size std::vector Dims; Dims.reserve(is_flattenable::vecRank); Dims.push_back(v.size()); Dims.push_back(v[0].size()); for (std::size_t i = 0; i < Dims[0]; ++i) { if (v[i].size() != Dims[1] || !isRegularShapeHelper(v[i], Dims, 2, i==0)) { return false; } } return true; } } // helper function to read space-separated values template std::string vecToStr(const std::vector &v) { using Grid::operator<<; std::ostringstream sstr; sstr << v; return sstr.str(); } #endif