QMCPACK
OhmmsVector.h
Go to the documentation of this file.
1 //////////////////////////////////////////////////////////////////////////////////////
2 // This file is distributed under the University of Illinois/NCSA Open Source License.
3 // See LICENSE file in top directory for details.
4 //
5 // Copyright (c) 2021 QMCPACK developers.
6 //
7 // File developed by: Jeongnim Kim, jeongnim.kim@intel.com, Intel Corp.
8 // Ye Luo, yeluo@anl.gov, Argonne National Laboratory
9 // Peter Doak, doakpw@ornl.gov, Oak Ridge National Laboratory
10 //
11 // File created by: Jeongnim Kim, jeongnim.kim@intel.com, Intel Corp.
12 //////////////////////////////////////////////////////////////////////////////////////
13 
14 /** @file
15  *
16  * Declaraton of Vector<T,Alloc>
17  * Manage memory through Alloc directly and allow referencing an existing memory.
18  */
19 
20 #ifndef OHMMS_NEW_VECTOR_H
21 #define OHMMS_NEW_VECTOR_H
22 #include <algorithm>
23 #include <vector>
24 #include <iostream>
25 #include <type_traits>
26 #include <stdexcept>
27 #include "PETE/PETE.h"
28 #include "allocator_traits.hpp"
29 
30 namespace qmcplusplus
31 {
32 template<class T, typename Alloc = std::allocator<T>>
33 class Vector
34 {
35 public:
36  using Type_t = T;
37  using value_type = T;
38  using iterator = T*;
39  using const_iterator = const T*;
40  using size_type = typename Alloc::size_type;
41  using pointer = typename Alloc::pointer;
42  using const_pointer = typename Alloc::const_pointer;
44 
45  /** constructor with size n*/
46  explicit inline Vector(size_type n = 0, Type_t val = Type_t()) : nLocal(n)
47  {
48  if (n)
49  {
50  resize_impl(n);
52  }
53  }
54 
55  /** constructor with an initialized ref */
56  explicit inline Vector(T* ref, size_type n) : nLocal(n), X(ref) {}
57 
58  /** copy constructor */
59  Vector(const Vector& rhs) : nLocal(rhs.nLocal)
60  {
61  if (nLocal)
62  {
63  resize_impl(rhs.size());
64  construct_copy_elements(rhs.data(), rhs.size(), X);
65  }
66  }
67 
68  /** This allows construction of a Vector on another containers owned memory that is using a dualspace allocator.
69  * It can be any span of that memory.
70  * You're going to get a bunch of compile errors if the Container in questions is not using a the QMCPACK
71  * realspace dualspace allocator "interface"
72  */
73  template<typename CONTAINER>
74  Vector(const CONTAINER& from, T* ref, size_type n) : nLocal(n), X(ref)
75  {
76  qmc_allocator_traits<Alloc>::attachReference(from.mAllocator, mAllocator, ref - from.data());
77  }
78 
79  /** Initializer list constructor that can deal with both POD
80  * and nontrivial nested elements with move assignment operators.
81  */
82  template<typename Allocator = Alloc, typename = IsHostSafe<Allocator>>
83  Vector(std::initializer_list<T> ts)
84  {
85  if (ts.size())
86  {
87  resize_impl(ts.size());
88  construct_copy_elements(std::data(ts), ts.size(), X);
89  }
90  }
91 
92  // default assignment operator
93  inline Vector& operator=(const Vector& rhs)
94  {
95  if (this == &rhs)
96  return *this;
97  if (nLocal != rhs.nLocal)
98  resize(rhs.nLocal);
100  std::copy_n(rhs.data(), nLocal, X);
101  else
103  return *this;
104  }
105 
106  // assignment operator from anther Vector class
107  template<typename T1, typename C1, typename Allocator = Alloc, typename = IsHostSafe<Allocator>>
108  inline Vector& operator=(const Vector<T1, C1>& rhs)
109  {
110  if (std::is_convertible<T1, T>::value)
111  {
112  if (nLocal != rhs.nLocal)
113  resize(rhs.nLocal);
114  std::copy_n(rhs.data(), nLocal, X);
115  }
116  return *this;
117  }
118 
119  // assigment operator to enable PETE
120  template<class RHS, typename Allocator = Alloc, typename = IsHostSafe<Allocator>>
121  inline Vector& operator=(const RHS& rhs)
122  {
123  assign(*this, rhs);
124  return *this;
125  }
126 
127  //! Destructor
128  virtual ~Vector() { free(); }
129 
130  // Attach to pre-allocated memory
131  inline void attachReference(T* ref, size_type n)
132  {
133  if (nAllocated)
134  {
135  free();
136  // std::cerr << "Allocated OhmmsVector attachReference called.\n" << std::endl;
137  // Nice idea but "default" constructed WFC elements in the batched driver make this a mess.
138  //throw std::runtime_error("Pointer attaching is not allowed on Vector with allocated memory.");
139  }
140  nLocal = n;
141  nAllocated = 0;
142  X = ref;
143  }
144 
145  /** Attach to pre-allocated memory and propagate the allocator of the owning container.
146  * Required for sane access to dual space memory
147  */
148  template<typename CONTAINER>
149  inline void attachReference(const CONTAINER& other, T* ref, size_type n)
150  {
151  if (nAllocated)
152  {
153  free();
154  }
155  nLocal = n;
156  nAllocated = 0;
157  X = ref;
158  qmc_allocator_traits<Alloc>::attachReference(other.mAllocator, mAllocator, ref - other.data());
159  }
160 
161  //! return the current size
162  inline size_type size() const { return nLocal; }
163 
164  /// Resize the container. For performance consideration, previous data may or may not get kept.
165  /// Please avoid relying on previous data after resizing.
166  inline void resize(size_type n, Type_t val = Type_t())
167  {
168  static_assert(std::is_same<value_type, typename Alloc::value_type>::value,
169  "Vector and Alloc data types must agree!");
170  if (nLocal > nAllocated)
171  throw std::runtime_error("Resize not allowed on Vector constructed by initialized memory.");
172 
173  if (n > nAllocated)
174  {
175  if (nLocal)
177  resize_impl(n);
178  construct_fill_elements(X, n, val);
179  }
180  else
181  {
182  if (n > nLocal)
184  if (n < nLocal)
185  destroy_elements(X + n, nLocal - n);
186  nLocal = n;
187  }
188  }
189 
190  ///clear
191  inline void clear() { nLocal = 0; }
192 
194 
195  ///free
196  inline void free()
197  {
198  if (nAllocated)
199  {
200  if (nLocal)
202  mAllocator.deallocate(X, nAllocated);
203  }
204  nLocal = 0;
205  nAllocated = 0;
206  X = nullptr;
207  }
208 
209  // Get and Set Operations
210  template<typename Allocator = Alloc, typename = IsHostSafe<Allocator>>
212  {
213  return X[i];
214  }
215 
216  template<typename Allocator = Alloc, typename = IsHostSafe<Allocator>>
217  inline const Type_t& operator[](size_type i) const
218  {
219  return X[i];
220  }
221 
222  //inline Type_t& operator()(size_type i)
223  //{
224  // return X[i];
225  //}
226 
227  //inline Type_t operator()( size_type i) const
228  //{
229  // return X[i];
230  //}
231 
232  inline iterator begin() { return X; }
233  inline const_iterator begin() const { return X; }
234 
235  inline iterator end() { return X + nLocal; }
236  inline const_iterator end() const { return X + nLocal; }
237 
238  inline pointer data() { return X; }
239  inline const_pointer data() const { return X; }
240 
241  /** Return the device_ptr matching X if this is a vector attached or
242  * owning dual space memory.
243  */
244  template<typename Allocator = Alloc, typename = IsDualSpace<Allocator>>
246  {
247  return mAllocator.get_device_ptr();
248  }
249  template<typename Allocator = Alloc, typename = IsDualSpace<Allocator>>
250  inline const_pointer device_data() const
251  {
252  return mAllocator.get_device_ptr();
253  }
254 
255  inline pointer first_address() { return X; }
256  inline const_pointer first_address() const { return X; }
257 
258  inline pointer last_address() { return X + nLocal; }
259  inline const_pointer last_address() const { return X + nLocal; }
260 
261  // Abstract Dual Space Transfers
262  template<typename Allocator = Alloc, typename = IsDualSpace<Allocator>>
263  void updateTo(size_type size = 0, std::ptrdiff_t offset = 0)
264  {
265  if (size == 0)
267  else
269  }
270 
271  template<typename Allocator = Alloc, typename = IsDualSpace<Allocator>>
272  void updateFrom(size_type size = 0, std::ptrdiff_t offset = 0)
273  {
274  if (size == 0)
276  else
278  }
279 
280 private:
281  ///size
283  ///The number of allocated
285  ///pointer to the data accessed through this object
286  T* X = nullptr;
287  ///allocator
288  Alloc mAllocator;
289 
290  ///a dumb resize, always free existing memory and resize to n. n must be protected positive
291  inline void resize_impl(size_type n)
292  {
293  if (nAllocated)
294  {
295  mAllocator.deallocate(X, nAllocated);
296  }
297  X = mAllocator.allocate(n);
298  nLocal = n;
299  nAllocated = n;
300  }
301 
302  inline static void construct_fill_elements(Type_t* ptr, size_type n_elements, const Type_t& val)
303  {
304  if constexpr (std::is_trivial<T>::value)
305  qmc_allocator_traits<Alloc>::fill_n(ptr, n_elements, val);
307  for (size_type i = 0; i < n_elements; i++)
308  new (ptr + i) Type_t(val);
309  }
310 
311  inline static void construct_copy_elements(const Type_t* from, size_type n_elements, Type_t* to)
312  {
314  {
315  if constexpr (std::is_trivial<T>::value)
316  std::copy_n(from, n_elements, to);
317  else
318  for (size_type i = 0; i < n_elements; i++)
319  new (to + i) Type_t(*(from + i));
320  }
321  }
322 
323  inline void static destroy_elements(Type_t* ptr, size_type n_elements)
324  {
325  if constexpr (!std::is_trivial<T>::value && qmc_allocator_traits<Alloc>::is_host_accessible)
326  for (size_type i = 0; i < n_elements; i++)
327  (ptr + i)->~Type_t();
328  }
329 };
330 
331 } // namespace qmcplusplus
332 
334 
335 namespace qmcplusplus
336 {
337 //-----------------------------------------------------------------------------
338 // We need to specialize CreateLeaf<T> for our class, so that operators
339 // know what to stick in the leaves of the expression tree.
340 //-----------------------------------------------------------------------------
341 template<class T, class C>
342 struct CreateLeaf<Vector<T, C>>
343 {
345  inline static Leaf_t make(const Vector<T, C>& a) { return Leaf_t(a); }
346 };
347 
348 //-----------------------------------------------------------------------------
349 // We need to write a functor that is capable of comparing the size of
350 // the vector with a stored value. Then, we supply LeafFunctor specializations
351 // for Scalar<T> and STL vector leaves.
352 //-----------------------------------------------------------------------------
353 class SizeLeaf
354 {
355 public:
356  SizeLeaf(int s) : size_m(s) {}
357  SizeLeaf(const SizeLeaf& model) : size_m(model.size_m) {}
358  bool operator()(int s) const { return size_m == s; }
359 
360 private:
361  int size_m;
362 };
363 
364 template<class T>
366 {
367  using Type_t = bool;
368  inline static bool apply(const Scalar<T>&, const SizeLeaf&)
369  {
370  // Scalars always conform.
371  return true;
372  }
373 };
374 
375 template<class T, class C>
377 {
378  using Type_t = bool;
379  inline static bool apply(const Vector<T, C>& v, const SizeLeaf& s) { return s(v.size()); }
380 };
381 
382 //-----------------------------------------------------------------------------
383 // EvalLeaf1 is used to evaluate expression with vectors.
384 // (It's already defined for Scalar values.)
385 //-----------------------------------------------------------------------------
386 
387 template<class T, class C>
389 {
390  using Type_t = T;
391  inline static Type_t apply(const Vector<T, C>& vec, const EvalLeaf1& f) { return vec[f.val1()]; }
392 };
393 
394 //////////////////////////////////////////////////////////////////////////////////
395 // LOOP is done by evaluate function
396 //////////////////////////////////////////////////////////////////////////////////
397 template<class T, class C, class Op, class RHS>
398 inline void evaluate(Vector<T, C>& lhs, const Op& op, const Expression<RHS>& rhs)
399 {
400  if (forEach(rhs, SizeLeaf(lhs.size()), AndCombine()))
401  {
402  // We get here if the vectors on the RHS are the same size as those on
403  // the LHS.
404  for (int i = 0; i < lhs.size(); ++i)
405  {
406  // The actual assignment operation is performed here.
407  // PETE operator tags all define operator() to perform the operation.
408  // (In this case op performs an assignment.) forEach is used
409  // to compute the rhs value. EvalLeaf1 gets the
410  // values at each node using random access, and the tag
411  // OpCombine tells forEach to use the operator tags in the expression
412  // to combine values together.
413  op(lhs[i], forEach(rhs, EvalLeaf1(i), OpCombine()));
414  }
415  }
416  else
417  {
418  throw std::runtime_error("Error in evaluate: LHS and RHS don't conform in OhmmsVector.");
419  }
420 }
421 
422 template<class T, class Alloc>
423 bool operator==(const Vector<T, Alloc>& lhs, const Vector<T, Alloc>& rhs)
424 {
425  static_assert(qmc_allocator_traits<Alloc>::is_host_accessible, "operator== requires host accessible Vector.");
426  if (lhs.size() == rhs.size())
427  {
428  for (int i = 0; i < rhs.size(); i++)
429  if (lhs[i] != rhs[i])
430  return false;
431  return true;
432  }
433  else
434  return false;
435 }
436 
437 template<class T, class Alloc>
438 bool operator!=(const Vector<T, Alloc>& lhs, const Vector<T, Alloc>& rhs)
439 {
440  static_assert(qmc_allocator_traits<Alloc>::is_host_accessible, "operator== requires host accessible Vector.");
441  return !(lhs == rhs);
442 }
443 
444 // I/O
445 template<class T, class Alloc>
446 std::ostream& operator<<(std::ostream& out, const Vector<T, Alloc>& rhs)
447 {
448  static_assert(qmc_allocator_traits<Alloc>::is_host_accessible, "operator<< requires host accessible Vector.");
449  for (int i = 0; i < rhs.size(); i++)
450  out << rhs[i] << std::endl;
451  return out;
452 }
453 
454 template<class T, class Alloc>
455 std::istream& operator>>(std::istream& is, Vector<T, Alloc>& rhs)
456 {
457  static_assert(qmc_allocator_traits<Alloc>::is_host_accessible, "operator>> requires host accessible Vector.");
458  //printTinyVector<TinyVector<T,D> >::print(out,rhs);
459  for (int i = 0; i < rhs.size(); i++)
460  is >> rhs[i];
461  return is;
462 }
463 
464 } // namespace qmcplusplus
465 
466 #endif // OHMMS_PARTICLEATTRIB_PEPE_H
void resize(size_type n, Type_t val=Type_t())
Resize the container.
Definition: OhmmsVector.h:166
static Type_t apply(const Vector< T, C > &vec, const EvalLeaf1 &f)
Definition: OhmmsVector.h:391
static bool apply(const Scalar< T > &, const SizeLeaf &)
Definition: OhmmsVector.h:368
helper functions for EinsplineSetBuilder
Definition: Configuration.h:43
const_pointer device_data() const
Definition: OhmmsVector.h:250
static void updateTo(Allocator &a, value_type *host_ptr, size_t n, size_t offset=0)
Vector & operator=(const RHS &rhs)
Definition: OhmmsVector.h:121
static void construct_copy_elements(const Type_t *from, size_type n_elements, Type_t *to)
Definition: OhmmsVector.h:311
const_pointer first_address() const
Definition: OhmmsVector.h:256
Type_t & operator[](size_type i)
Definition: OhmmsVector.h:211
Definition: Scalar.h:49
ForEach< Expr, FTag, CTag >::Type_t forEach(const Expr &e, const FTag &f, const CTag &c)
Definition: ForEach.h:87
const_iterator begin() const
Definition: OhmmsVector.h:233
pointer device_data()
Return the device_ptr matching X if this is a vector attached or owning dual space memory...
Definition: OhmmsVector.h:245
void updateFrom(size_type size=0, std::ptrdiff_t offset=0)
Definition: OhmmsVector.h:272
Vector(size_type n=0, Type_t val=Type_t())
constructor with size n
Definition: OhmmsVector.h:46
bool operator==(const Matrix< T, Alloc > &lhs, const Matrix< T, Alloc > &rhs)
Definition: OhmmsMatrix.h:388
typename std::allocator< T > ::const_pointer const_pointer
Definition: OhmmsVector.h:42
const_pointer data() const
Definition: OhmmsVector.h:239
void free()
free
Definition: OhmmsVector.h:196
static void attachReference(Allocator &from, Allocator &to, std::ptrdiff_t ptr_offset)
So we can write generic tests that work with all QMCPACK allocators.
Vector(T *ref, size_type n)
constructor with an initialized ref
Definition: OhmmsVector.h:56
Vector(const CONTAINER &from, T *ref, size_type n)
This allows construction of a Vector on another containers owned memory that is using a dualspace all...
Definition: OhmmsVector.h:74
void attachReference(const CONTAINER &other, T *ref, size_type n)
Attach to pre-allocated memory and propagate the allocator of the owning container.
Definition: OhmmsVector.h:149
bool operator()(int s) const
Definition: OhmmsVector.h:358
static Leaf_t make(const Vector< T, C > &a)
Definition: OhmmsVector.h:345
int val1() const
Definition: Functors.h:98
void attachReference(T *ref, size_type n)
Definition: OhmmsVector.h:131
size_type size() const
return the current size
Definition: OhmmsVector.h:162
Matrix< T1, C1 > & assign(Matrix< T1, C1 > &lhs, const RHS &rhs)
pointer last_address()
Definition: OhmmsVector.h:258
static void destroy_elements(Type_t *ptr, size_type n_elements)
Definition: OhmmsVector.h:323
template class analogous to std::allocator_traits.
Vector & operator=(const Vector &rhs)
Definition: OhmmsVector.h:93
static void updateFrom(Allocator &a, value_type *host_ptr, size_t n, size_t offset=0)
const_iterator end() const
Definition: OhmmsVector.h:236
static void construct_fill_elements(Type_t *ptr, size_type n_elements, const Type_t &val)
Definition: OhmmsVector.h:302
sycl::event copy_n(sycl::queue &aq, const T1 *restrict VA, size_t array_size, T2 *restrict VC, const std::vector< sycl::event > &events)
Definition: syclBLAS.cpp:548
void clear()
clear
Definition: OhmmsVector.h:191
Vector(std::initializer_list< T > ts)
Initializer list constructor that can deal with both POD and nontrivial nested elements with move ass...
Definition: OhmmsVector.h:83
Vector & operator=(const Vector< T1, C1 > &rhs)
Definition: OhmmsVector.h:108
void evaluate(Matrix< T, Alloc > &lhs, const Op &op, const Expression< RHS > &rhs)
Definition: OhmmsMatrix.h:514
static bool apply(const Vector< T, C > &v, const SizeLeaf &s)
Definition: OhmmsVector.h:379
void updateTo(size_type size=0, std::ptrdiff_t offset=0)
Definition: OhmmsVector.h:263
void resize_impl(size_type n)
a dumb resize, always free existing memory and resize to n. n must be protected positive ...
Definition: OhmmsVector.h:291
SizeLeaf(const SizeLeaf &model)
Definition: OhmmsVector.h:357
const_pointer last_address() const
Definition: OhmmsVector.h:259
typename std::allocator< T > ::pointer pointer
Definition: OhmmsVector.h:41
Vector(const Vector &rhs)
copy constructor
Definition: OhmmsVector.h:59
std::istream & operator>>(std::istream &is, Matrix< T, Alloc > &rhs)
Definition: OhmmsMatrix.h:427
size_type nLocal
size
Definition: OhmmsVector.h:282
typename Alloc::size_type size_type
Definition: OhmmsVector.h:40
static void fill_n(value_type *ptr, size_t n, const value_type &value)
size_type nAllocated
The number of allocated.
Definition: OhmmsVector.h:284
bool operator!=(const Matrix< T, Alloc > &lhs, const Matrix< T, Alloc > &rhs)
Definition: OhmmsMatrix.h:403
T * X
pointer to the data accessed through this object
Definition: OhmmsVector.h:286
pointer first_address()
Definition: OhmmsVector.h:255
const Type_t & operator[](size_type i) const
Definition: OhmmsVector.h:217
virtual ~Vector()
Destructor.
Definition: OhmmsVector.h:128
Alloc mAllocator
allocator
Definition: OhmmsVector.h:288