Grid 0.7.0
VectorUtils.h
Go to the documentation of this file.
1/*************************************************************************************
2
3 Grid physics library, www.github.com/paboyle/Grid
4
5 Source file: ./Grid/serialisation/VectorUtils.h
6
7 Copyright (C) 2015
8
9 Author: Antonin Portelli <antonin.portelli@me.com>
10 Author: Peter Boyle <paboyle@ph.ed.ac.uk>
11 Author: paboyle <paboyle@ph.ed.ac.uk>
12 Author: Michael Marshall <michael.marshall@ed.ac.uk>
13
14 This program is free software; you can redistribute it and/or modify
15 it under the terms of the GNU General Public License as published by
16 the Free Software Foundation; either version 2 of the License, or
17 (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License for more details.
23
24 You should have received a copy of the GNU General Public License along
25 with this program; if not, write to the Free Software Foundation, Inc.,
26 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27
28 See the full license in the file "LICENSE" in the top level distribution directory
29 *************************************************************************************/
30/* END LEGAL */
31#ifndef GRID_SERIALISATION_VECTORUTILS_H
32#define GRID_SERIALISATION_VECTORUTILS_H
33
34#include <type_traits>
36
37namespace Grid {
38 // Pair IO utilities /////////////////////////////////////////////////////////
39 // helper function to parse input in the format "<obj1 obj2>"
40 template <typename T1, typename T2>
41 inline std::istream & operator>>(std::istream &is, std::pair<T1, T2> &buf)
42 {
43 T1 buf1;
44 T2 buf2;
45 char c;
46
47 // Search for "pair" delimiters.
48 do
49 {
50 is.get(c);
51 } while (c != '(' && !is.eof());
52 if (c == '(')
53 {
54 int start = is.tellg();
55 do
56 {
57 is.get(c);
58 } while (c != ')' && !is.eof());
59 if (c == ')')
60 {
61 int end = is.tellg();
62 int psize = end - start - 1;
63
64 // Only read data between pair limiters.
65 is.seekg(start);
66 std::string tmpstr(psize, ' ');
67 is.read(&tmpstr[0], psize);
68 std::istringstream temp(tmpstr);
69 temp >> buf1 >> buf2;
70 buf = std::make_pair(buf1, buf2);
71 is.seekg(end);
72 }
73 }
74 is.peek();
75 return is;
76 }
77
78 // output to streams for pairs
79 template <class T1, class T2>
80 inline std::ostream & operator<<(std::ostream &os, const std::pair<T1, T2> &p)
81 {
82 os << "(" << p.first << " " << p.second << ")";
83 return os;
84 }
85
86 // std::vector<std:vector<...>> nested to specified Rank //////////////////////////////////
87 template<typename T, unsigned int Rank>
89 typedef typename std::vector<typename NestedStdVector<T, Rank - 1>::type> type;
90 };
91
92 template<typename T>
93 struct NestedStdVector<T,0> {
94 typedef T type;
95 };
96
97 // Grid scalar tensors to nested std::vectors //////////////////////////////////
98 template <typename T>
100 {
101 typedef T type;
102 };
103
104 template <typename T>
106 {
107 typedef typename TensorToVec<T>::type type;
108 };
109
110 template <typename T, int N>
111 struct TensorToVec<iVector<T, N>>
112 {
113 typedef typename std::vector<typename TensorToVec<T>::type> type;
114 };
115
116 template <typename T, int N>
117 struct TensorToVec<iMatrix<T, N>>
118 {
119 typedef typename std::vector<std::vector<typename TensorToVec<T>::type>> type;
120 };
121
122 template <typename T>
123 void tensorDim(std::vector<size_t> &dim, const T &t, const bool wipe = true)
124 {
125 if (wipe)
126 {
127 dim.clear();
128 }
129 }
130
131 template <typename T>
132 void tensorDim(std::vector<size_t> &dim, const iScalar<T> &t, const bool wipe = true)
133 {
134 if (wipe)
135 {
136 dim.clear();
137 }
138 tensorDim(dim, t._internal, false);
139 }
140
141 template <typename T, int N>
142 void tensorDim(std::vector<size_t> &dim, const iVector<T, N> &t, const bool wipe = true)
143 {
144 if (wipe)
145 {
146 dim.clear();
147 }
148 dim.push_back(N);
149 tensorDim(dim, t._internal[0], false);
150 }
151
152 template <typename T, int N>
153 void tensorDim(std::vector<size_t> &dim, const iMatrix<T, N> &t, const bool wipe = true)
154 {
155 if (wipe)
156 {
157 dim.clear();
158 }
159 dim.push_back(N);
160 dim.push_back(N);
161 tensorDim(dim, t._internal[0][0], false);
162 }
163
164 template <typename T>
166 {
167 return t;
168 }
169
170 template <typename T>
172 {
173 return tensorToVec(t._internal);
174 }
175
176 template <typename T, int N>
178 {
180
181 v.resize(N);
182 for (unsigned int i = 0; i < N; i++)
183 {
184 v[i] = tensorToVec(t._internal[i]);
185 }
186
187 return v;
188 }
189
190 template <typename T, int N>
192 {
194
195 v.resize(N);
196 for (unsigned int i = 0; i < N; i++)
197 {
198 v[i].resize(N);
199 for (unsigned int j = 0; j < N; j++)
200 {
201 v[i][j] = tensorToVec(t._internal[i][j]);
202 }
203 }
204
205 return v;
206 }
207
208 template <typename T>
209 void vecToTensor(T &t, const typename TensorToVec<T>::type &v)
210 {
211 t = v;
212 }
213
214
215 template <typename T>
217 {
219 }
220
221 template <typename T, int N>
223 {
224 for (unsigned int i = 0; i < N; i++)
225 {
226 vecToTensor(t._internal[i], v[i]);
227 }
228 }
229
230 template <typename T, int N>
232 {
233 for (unsigned int i = 0; i < N; i++)
234 for (unsigned int j = 0; j < N; j++)
235 {
236 vecToTensor(t._internal[i][j], v[i][j]);
237 }
238 }
239
240 // is_flattenable<T>::value is true if T is a std::vector<> which can be flattened //////////////////////
241 template <typename T, typename V = void>
242 struct is_flattenable : std::false_type
243 {
244 using type = T;
245 using grid_type = T;
246 static constexpr int vecRank = 0;
247 static constexpr bool isGridTensor = false;
248 static constexpr bool children_flattenable = std::is_arithmetic<T>::value or is_complex<T>::value;
249 };
250
251 template <typename T>
252 struct is_flattenable<T, typename std::enable_if<isGridTensor<T>::value>::type> : std::false_type
253 {
255 using grid_type = T;
256 static constexpr int vecRank = 0;
257 static constexpr bool isGridTensor = true;
258 static constexpr bool children_flattenable = true;
259 };
260
261 template <typename T>
262 struct is_flattenable<std::vector<T>, typename std::enable_if<is_flattenable<T>::children_flattenable>::type>
263 : std::true_type
264 {
268 static constexpr int vecRank = is_flattenable<T>::vecRank + 1;
269 static constexpr bool children_flattenable = true;
270 };
271
272 // Vector flattening utility class ////////////////////////////////////////////
273 // Class to flatten a multidimensional std::vector
274 template <typename V>
276 {
277 public:
280 public:
281 explicit Flatten(const V &vector);
282 const V & getVector(void) const { return vector_; }
283 const std::vector<Scalar> & getFlatVector(void) const { return flatVector_; }
284 const std::vector<size_t> & getDim(void) const { return dim_; }
285 private:
286 template <typename W> typename std::enable_if<!is_flattenable<W>::value && !is_flattenable<W>::isGridTensor>::type
287 accumulate(const W &e);
288 template <typename W> typename std::enable_if<!is_flattenable<W>::value && is_flattenable<W>::isGridTensor>::type
289 accumulate(const W &e);
290 template <typename W> typename std::enable_if< is_flattenable<W>::value>::type
291 accumulate(const W &v);
292 template <typename W> typename std::enable_if<!is_flattenable<W>::value && !is_flattenable<W>::isGridTensor>::type
293 accumulateDim(const W &e) {} // Innermost is a scalar - do nothing
294 template <typename W> typename std::enable_if<!is_flattenable<W>::value && is_flattenable<W>::isGridTensor>::type
295 accumulateDim(const W &e);
296 template <typename W> typename std::enable_if< is_flattenable<W>::value>::type
297 accumulateDim(const W &v);
298 private:
299 const V &vector_;
300 std::vector<Scalar> flatVector_;
301 std::vector<size_t> dim_;
302 };
303
304 // Class to reconstruct a multidimensional std::vector
305 template <typename V>
307 {
308 public:
311 public:
312 Reconstruct(const std::vector<Scalar> &flatVector,
313 const std::vector<size_t> &dim);
314 const V & getVector(void) const { return vector_; }
315 const std::vector<Scalar> & getFlatVector(void) const { return flatVector_; }
316 const std::vector<size_t> & getDim(void) const { return dim_; }
317 private:
318 template <typename W> typename std::enable_if<!is_flattenable<W>::value && !is_flattenable<W>::isGridTensor>::type
319 fill(W &v);
320 template <typename W> typename std::enable_if<!is_flattenable<W>::value && is_flattenable<W>::isGridTensor>::type
321 fill(W &v);
322 template <typename W> typename std::enable_if< is_flattenable<W>::value>::type
323 fill(W &v);
324 template <typename W> typename std::enable_if< is_flattenable<W>::value && is_flattenable<W>::vecRank==1>::type
325 resize(W &v, const unsigned int dim);
326 template <typename W> typename std::enable_if< is_flattenable<W>::value && (is_flattenable<W>::vecRank>1)>::type
327 resize(W &v, const unsigned int dim);
328 template <typename W> typename std::enable_if<!is_flattenable<W>::isGridTensor>::type
329 checkInnermost(const W &e) {} // Innermost is a scalar - do nothing
330 template <typename W> typename std::enable_if< is_flattenable<W>::isGridTensor>::type
331 checkInnermost(const W &e);
332 private:
334 const std::vector<Scalar> &flatVector_;
335 std::vector<size_t> dim_;
336 size_t ind_{0};
337 unsigned int dimInd_{0};
338 };
339
340 // Flatten class template implementation
341 template <typename V>
342 template <typename W> typename std::enable_if<!is_flattenable<W>::value && !is_flattenable<W>::isGridTensor>::type
344 {
345 flatVector_.push_back(e);
346 }
347
348 template <typename V>
349 template <typename W> typename std::enable_if<!is_flattenable<W>::value && is_flattenable<W>::isGridTensor>::type
350 Flatten<V>::accumulate(const W &e)
351 {
352 for (const Scalar &x: e) {
353 flatVector_.push_back(x);
354 }
355 }
356
357 template <typename V>
358 template <typename W> typename std::enable_if<is_flattenable<W>::value>::type
359 Flatten<V>::accumulate(const W &v)
360 {
361 for (auto &e: v)
362 {
363 accumulate(e);
364 }
365 }
366
367 template <typename V>
368 template <typename W> typename std::enable_if<!is_flattenable<W>::value && is_flattenable<W>::isGridTensor>::type
369 Flatten<V>::accumulateDim(const W &e)
370 {
371 using Traits = GridTypeMapper<typename is_flattenable<W>::grid_type>;
372 for (int rank=0; rank < Traits::Rank; ++rank)
373 dim_.push_back(Traits::Dimension(rank));
374 }
375
376 template <typename V>
377 template <typename W> typename std::enable_if<is_flattenable<W>::value>::type
378 Flatten<V>::accumulateDim(const W &v)
379 {
380 dim_.push_back(v.size());
381 accumulateDim(v[0]);
382 }
383
384 template <typename V>
385 Flatten<V>::Flatten(const V &vector)
386 : vector_(vector)
387 {
389 std::size_t TotalSize{ dim_[0] };
390 for (int i = 1; i < dim_.size(); ++i) {
391 TotalSize *= dim_[i];
392 }
393 flatVector_.reserve(TotalSize);
395 }
396
397 // Reconstruct class template implementation
398 template <typename V>
399 template <typename W> typename std::enable_if<!is_flattenable<W>::value && !is_flattenable<W>::isGridTensor>::type
401 {
402 v = flatVector_[ind_++];
403 }
404
405 template <typename V>
406 template <typename W> typename std::enable_if<!is_flattenable<W>::value && is_flattenable<W>::isGridTensor>::type
408 {
409 for (auto &e: v)
410 {
411 e = flatVector_[ind_++];
412 }
413 }
414
415 template <typename V>
416 template <typename W> typename std::enable_if<is_flattenable<W>::value>::type
418 {
419 for (auto &e: v)
420 {
421 fill(e);
422 }
423 }
424
425 template <typename V>
426 template <typename W> typename std::enable_if<is_flattenable<W>::value && is_flattenable<W>::vecRank==1>::type
427 Reconstruct<V>::resize(W &v, const unsigned int dim)
428 {
429 v.resize(dim_[dim]);
430 }
431
432 template <typename V>
433 template <typename W> typename std::enable_if<is_flattenable<W>::value && (is_flattenable<W>::vecRank>1)>::type
434 Reconstruct<V>::resize(W &v, const unsigned int dim)
435 {
436 v.resize(dim_[dim]);
437 for (auto &e: v)
438 {
439 resize(e, dim + 1);
440 }
441 }
442
443 template <typename V>
444 template <typename W> typename std::enable_if<is_flattenable<W>::isGridTensor>::type
446 {
447 using Traits = GridTypeMapper<typename is_flattenable<W>::grid_type>;
448 const int gridRank{Traits::Rank};
449 const int dimRank{static_cast<int>(dim_.size())};
450 assert(dimRank >= gridRank && "Tensor rank too low for Grid tensor");
451 for (int i=0; i<gridRank; ++i) {
452 assert(dim_[dimRank - gridRank + i] == Traits::Dimension(i) && "Tensor dimension doesn't match Grid tensor");
453 }
454 dim_.resize(dimRank - gridRank);
455 }
456
457 template <typename V>
458 Reconstruct<V>::Reconstruct(const std::vector<Scalar> &flatVector,
459 const std::vector<size_t> &dim)
460 : flatVector_(flatVector)
461 , dim_(dim)
462 {
464 assert(dim_.size() == is_flattenable<V>::vecRank && "Tensor rank doesn't match nested std::vector rank");
465 resize(vector_, 0);
466 fill(vector_);
467 }
468
469 // Vector IO utilities ///////////////////////////////////////////////////////
470 // helper function to read space-separated values
471 template <typename T>
472 std::vector<T> strToVec(const std::string s)
473 {
474 std::istringstream sstr(s);
475 std::vector<T> v;
476
477 for(T buf; sstr >> buf;)
478 {
479 v.push_back(buf);
480 }
481
482 return v;
483 }
484
485 // output to streams for vectors
486 template < class T >
487 inline std::ostream & operator<<(std::ostream &os, const std::vector<T> &v)
488 {
489 os << "[";
490 for (unsigned int i = 0; i < v.size(); ++i)
491 {
492 os << v[i];
493 if (i < v.size() - 1)
494 {
495 os << " ";
496 }
497 }
498 os << "]";
499
500 return os;
501 }
502
503 // In general, scalar types are considered "flattenable" (regularly shaped)
504 template <typename T>
505 bool isRegularShapeHelper(const std::vector<T> &, std::vector<std::size_t> &, int, bool)
506 {
507 return true;
508 }
509
510 template <typename T>
511 bool isRegularShapeHelper(const std::vector<std::vector<T>> &v, std::vector<std::size_t> &Dims, int Depth, bool bFirst)
512 {
513 if( bFirst)
514 {
515 assert( Dims.size() == Depth && "Bug: Delete this message after testing" );
516 Dims.push_back(v[0].size());
517 if (!Dims[Depth])
518 return false;
519 }
520 else
521 {
522 assert( Dims.size() >= Depth + 1 && "Bug: Delete this message after testing" );
523 }
524 for (std::size_t i = 0; i < v.size(); ++i)
525 {
526 if (v[i].size() != Dims[Depth] || !isRegularShapeHelper(v[i], Dims, Depth + 1, bFirst && i==0))
527 {
528 return false;
529 }
530 }
531 return true;
532 }
533
534 template <typename T>
535 bool isRegularShape(const T &t) { return true; }
536
537 template <typename T>
538 bool isRegularShape(const std::vector<T> &v) { return !v.empty(); }
539
540 // Return non-zero if all dimensions of this std::vector<std::vector<T>> are regularly shaped
541 template <typename T>
542 bool isRegularShape(const std::vector<std::vector<T>> &v)
543 {
544 if (v.empty() || v[0].empty())
545 return false;
546 // Make sure all of my rows are the same size
547 std::vector<std::size_t> Dims;
548 Dims.reserve(is_flattenable<T>::vecRank);
549 Dims.push_back(v.size());
550 Dims.push_back(v[0].size());
551 for (std::size_t i = 0; i < Dims[0]; ++i)
552 {
553 if (v[i].size() != Dims[1] || !isRegularShapeHelper(v[i], Dims, 2, i==0))
554 {
555 return false;
556 }
557 }
558 return true;
559 }
560}
561
562// helper function to read space-separated values
563template <typename T>
564std::string vecToStr(const std::vector<T> &v)
565{
566 using Grid::operator<<;
567
568 std::ostringstream sstr;
569
570 sstr << v;
571
572 return sstr.str();
573}
574
575#endif
#define T2
#define T1
std::string vecToStr(const std::vector< T > &v)
const std::vector< size_t > & getDim(void) const
static constexpr bool isGridTensor
Flatten(const V &vector)
std::enable_if<!is_flattenable< W >::value &&!is_flattenable< W >::isGridTensor >::type accumulate(const W &e)
const std::vector< Scalar > & getFlatVector(void) const
const V & getVector(void) const
typename is_flattenable< V >::type Scalar
std::enable_if<!is_flattenable< W >::value &&!is_flattenable< W >::isGridTensor >::type accumulateDim(const W &e)
std::enable_if< is_flattenable< W >::value >::type accumulateDim(const W &v)
std::enable_if< is_flattenable< W >::value >::type accumulate(const W &v)
const V & vector_
std::enable_if<!is_flattenable< W >::value &&is_flattenable< W >::isGridTensor >::type accumulateDim(const W &e)
std::vector< size_t > dim_
std::enable_if<!is_flattenable< W >::value &&is_flattenable< W >::isGridTensor >::type accumulate(const W &e)
std::vector< Scalar > flatVector_
Reconstruct(const std::vector< Scalar > &flatVector, const std::vector< size_t > &dim)
std::enable_if< is_flattenable< W >::value &&is_flattenable< W >::vecRank==1 >::type resize(W &v, const unsigned int dim)
const std::vector< Scalar > & flatVector_
std::vector< size_t > dim_
std::enable_if<!is_flattenable< W >::isGridTensor >::type checkInnermost(const W &e)
const std::vector< Scalar > & getFlatVector(void) const
static constexpr bool isGridTensor
const std::vector< size_t > & getDim(void) const
typename is_flattenable< V >::type Scalar
const V & getVector(void) const
std::enable_if<!is_flattenable< W >::value &&is_flattenable< W >::isGridTensor >::type fill(W &v)
unsigned int dimInd_
std::enable_if<!is_flattenable< W >::value &&!is_flattenable< W >::isGridTensor >::type fill(W &v)
vtype _internal[N][N]
vtype _internal
vtype _internal[N]
bool isRegularShapeHelper(const std::vector< T > &, std::vector< std::size_t > &, int, bool)
bool isRegularShape(const T &t)
std::vector< T > strToVec(const std::string s)
std::istream & operator>>(std::istream &is, std::pair< T1, T2 > &buf)
Definition VectorUtils.h:41
void tensorDim(std::vector< size_t > &dim, const T &t, const bool wipe=true)
TensorToVec< T >::type tensorToVec(const T &t)
void vecToTensor(T &t, const typename TensorToVec< T >::type &v)
std::ostream & operator<<(std::ostream &os, const std::pair< T1, T2 > &p)
Definition VectorUtils.h:80
std::vector< typename NestedStdVector< T, Rank - 1 >::type > type
Definition VectorUtils.h:89
std::vector< std::vector< typename TensorToVec< T >::type > > type
TensorToVec< T >::type type
std::vector< typename TensorToVec< T >::type > type
static constexpr bool isGridTensor
static constexpr bool children_flattenable
static constexpr int vecRank