Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RTensor.hxx
Go to the documentation of this file.
1#ifndef TMVA_RTENSOR
2#define TMVA_RTENSOR
3
4#include <vector>
5#include <cstddef> // std::size_t
6#include <cstdint>
7#include <stdexcept> // std::runtime_error
8#include <sstream> // std::stringstream
9#include <memory> // std::shared_ptr
10#include <type_traits> // std::is_convertible
11#include <algorithm> // std::reverse
12#include <iterator> // std::random_access_iterator_tag
13
14namespace TMVA {
15namespace Experimental {
16
17/// Memory layout type
18enum class MemoryLayout : uint8_t {
19 RowMajor = 0x01,
20 ColumnMajor = 0x02
21};
22
23namespace Internal {
24
25/// \brief Get size of tensor from shape vector
26/// \param[in] shape Shape vector
27/// \return Size of contiguous memory
28template <typename T>
29inline std::size_t GetSizeFromShape(const T &shape)
30{
31 if (shape.size() == 0)
32 return 0;
33 std::size_t size = 1;
34 for (auto &s : shape)
35 size *= s;
36 return size;
37}
38
39/// \brief Compute strides from shape vector.
40/// \param[in] shape Shape vector
41/// \param[in] layout Memory layout
42/// \return Size of contiguous memory
43///
44/// This information is needed for the multi-dimensional indexing. See here:
45/// https://en.wikipedia.org/wiki/Row-_and_column-major_order
46/// https://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.strides.html
47template <typename T>
48inline std::vector<std::size_t> ComputeStridesFromShape(const T &shape, MemoryLayout layout)
49{
50 const auto size = shape.size();
51 T strides(size);
52 if (layout == MemoryLayout::RowMajor) {
53 for (std::size_t i = 0; i < size; i++) {
54 if (i == 0) {
55 strides[size - 1 - i] = 1;
56 } else {
57 strides[size - 1 - i] = strides[size - 1 - i + 1] * shape[size - 1 - i + 1];
58 }
59 }
60 } else if (layout == MemoryLayout::ColumnMajor) {
61 for (std::size_t i = 0; i < size; i++) {
62 if (i == 0) {
63 strides[i] = 1;
64 } else {
65 strides[i] = strides[i - 1] * shape[i - 1];
66 }
67 }
68 } else {
69 std::stringstream ss;
70 ss << "Memory layout type is not valid for calculating strides.";
71 throw std::runtime_error(ss.str());
72 }
73 return strides;
74}
75
76/// \brief Compute indices from global index
77/// \param[in] shape Shape vector
78/// \param[in] idx Global index
79/// \param[in] layout Memory layout
80/// \return Indice vector
81template <typename T>
82inline T ComputeIndicesFromGlobalIndex(const T& shape, MemoryLayout layout, const typename T::value_type idx)
83{
84 const auto size = shape.size();
85 auto strides = ComputeStridesFromShape(shape, layout);
86 T indices(size);
87 auto r = idx;
88 for (std::size_t i = 0; i < size; i++) {
89 indices[i] = int(r / strides[i]);
90 r = r % strides[i];
91 }
92 return indices;
93}
94
95/// \brief Compute global index from indices
96/// \param[in] strides Strides vector
97/// \param[in] idx Indice vector
98/// \return Global index
99template <typename U, typename V>
100inline std::size_t ComputeGlobalIndex(const U& strides, const V& idx)
101{
102 std::size_t globalIndex = 0;
103 const auto size = idx.size();
104 for (std::size_t i = 0; i < size; i++) {
105 globalIndex += strides[size - 1 - i] * idx[size - 1 - i];
106 }
107 return globalIndex;
108}
109
110/// \brief Type checking for all types of a parameter pack, e.g., used in combination with std::is_convertible
111template <class... Ts>
112struct and_types : std::true_type {
113};
114
115template <class T0, class... Ts>
116struct and_types<T0, Ts...> : std::integral_constant<bool, T0() && and_types<Ts...>()> {
117};
118
119/// \brief Copy slice of a tensor recursively from here to there
120/// \param[in] here Source tensor
121/// \param[in] there Target tensor (slice of source tensor)
122/// \param[in] mins Minimum of indices for each dimension
123/// \param[in] maxs Maximum of indices for each dimension
124/// \param[in] idx Current indices
125/// \param[in] active Active index needed to stop the recursion
126///
127/// Copy the content of a slice of a tensor from source to target. This is done
128/// by recursively iterating over the ranges of the slice for each dimension.
129template <typename T>
130void RecursiveCopy(const T &here, T &there,
131 const std::vector<std::size_t> &mins, const std::vector<std::size_t> &maxs,
132 std::vector<std::size_t> idx, std::size_t active)
133{
134 const auto size = idx.size();
135 for (std::size_t i = mins[active]; i < maxs[active]; i++) {
136 idx[active] = i;
137 if (active == size - 1) {
138 auto idxThere = idx;
139 for (std::size_t j = 0; j < size; j++) {
140 idxThere[j] -= mins[j];
141 }
142 there(idxThere) = here(idx);
143 } else {
144 Internal::RecursiveCopy(here, there, mins, maxs, idx, active + 1);
145 }
146 }
147}
148
149} // namespace TMVA::Experimental::Internal
150
151/// \class TMVA::Experimental::RTensor
152/// \brief RTensor is a container with contiguous memory and shape information.
153/// \tparam T Data-type of the tensor
154///
155/// An RTensor is a vector-like container, which has additional shape information.
156/// The elements of the multi-dimensional container can be accessed by their
157/// indices in a coherent way without taking care about the one-dimensional memory
158/// layout of the contiguous storage. This also allows to manipulate the shape
159/// of the container without moving the actual elements in memory. Another feature
160/// is that an RTensor can own the underlying contiguous memory but can also represent
161/// only a view on existing data without owning it.
162template <typename V, typename C = std::vector<V>>
163class RTensor {
164public:
165 // Typedefs
166 using Value_t = V;
167 using Shape_t = std::vector<std::size_t>;
169 using Slice_t = std::vector<Shape_t>;
170 using Container_t = C;
171
172private:
175 std::size_t fSize;
178 std::shared_ptr<Container_t> fContainer;
179
180protected:
181 void ReshapeInplace(const Shape_t &shape);
182
183public:
184 // Constructors
185
186 /// \brief Construct a tensor as view on data
187 /// \param[in] data Pointer to data contiguous in memory
188 /// \param[in] shape Shape vector
189 /// \param[in] layout Memory layout
190 RTensor(Value_t *data, Shape_t shape, MemoryLayout layout = MemoryLayout::RowMajor)
191 : fShape(shape), fLayout(layout), fData(data), fContainer(nullptr)
192 {
195 }
196
197 /// \brief Construct a tensor as view on data
198 /// \param[in] data Pointer to data contiguous in memory
199 /// \param[in] shape Shape vector
200 /// \param[in] strides Strides vector
201 /// \param[in] layout Memory layout
202 RTensor(Value_t *data, Shape_t shape, Shape_t strides, MemoryLayout layout = MemoryLayout::RowMajor)
203 : fShape(shape), fStrides(strides), fLayout(layout), fData(data), fContainer(nullptr)
204 {
206 }
207
208 /// \brief Construct a tensor owning externally provided data
209 /// \param[in] container Shared pointer to data container
210 /// \param[in] shape Shape vector
211 /// \param[in] layout Memory layout
212 RTensor(std::shared_ptr<Container_t> container, Shape_t shape,
213 MemoryLayout layout = MemoryLayout::RowMajor)
215 {
218 fData = std::data(*fContainer);
219 }
220
221 /// \brief Construct a tensor owning data initialized with new container
222 /// \param[in] shape Shape vector
223 /// \param[in] layout Memory layout
224 RTensor(Shape_t shape, MemoryLayout layout = MemoryLayout::RowMajor)
225 : fShape(shape), fLayout(layout)
226 {
227 // TODO: Document how data pointer is determined using STL iterator interface.
228 // TODO: Sanitize given container type with type traits
231 fContainer = std::make_shared<Container_t>(fSize);
232 fData = std::data(*fContainer);
233 }
234
235 // Access elements
237 const Value_t &operator() (const Index_t &idx) const;
238 template <typename... Idx> Value_t &operator()(Idx... idx);
239 template <typename... Idx> const Value_t &operator() (Idx... idx) const;
240
241 // Access properties
242 std::size_t GetSize() const { return fSize; }
243 const Shape_t &GetShape() const { return fShape; }
244 const Shape_t &GetStrides() const { return fStrides; }
245 Value_t *GetData() { return fData; }
246 const Value_t *GetData() const { return fData; }
247 std::shared_ptr<Container_t> GetContainer() { return fContainer; }
248 const std::shared_ptr<Container_t> GetContainer() const { return fContainer; }
250 bool IsView() const { return fContainer == nullptr; }
251 bool IsOwner() const { return !IsView(); }
252
253 // Copy
254 RTensor<Value_t, Container_t> Copy(MemoryLayout layout = MemoryLayout::RowMajor) const;
255
256 // Transformations
263
264 // Iterator class
265 class Iterator {
266 private:
268 Index_t::value_type fGlobalIndex;
269 public:
270 using iterator_category = std::random_access_iterator_tag;
272 using difference_type = std::ptrdiff_t;
273 using pointer = Value_t *;
275
276 Iterator(RTensor<Value_t, Container_t>& x, typename Index_t::value_type idx) : fTensor(x), fGlobalIndex(idx) {}
277 Iterator& operator++() { fGlobalIndex++; return *this; }
278 Iterator operator++(int) { auto tmp = *this; operator++(); return tmp; }
279 Iterator& operator--() { fGlobalIndex--; return *this; }
280 Iterator operator--(int) { auto tmp = *this; operator--(); return tmp; }
283 difference_type operator-(const Iterator& rhs) { return fGlobalIndex - rhs.GetGlobalIndex(); }
291 bool operator==(const Iterator& rhs) const
292 {
293 if (fGlobalIndex == rhs.GetGlobalIndex()) return true;
294 return false;
295 }
296 bool operator!=(const Iterator& rhs) const { return !operator==(rhs); };
297 bool operator>(const Iterator& rhs) const { return fGlobalIndex > rhs.GetGlobalIndex(); }
298 bool operator<(const Iterator& rhs) const { return fGlobalIndex < rhs.GetGlobalIndex(); }
299 bool operator>=(const Iterator& rhs) const { return fGlobalIndex >= rhs.GetGlobalIndex(); }
300 bool operator<=(const Iterator& rhs) const { return fGlobalIndex <= rhs.GetGlobalIndex(); }
301 typename Index_t::value_type GetGlobalIndex() const { return fGlobalIndex; };
302 };
303
304 // Iterator interface
305 // TODO: Document that the iterator always iterates following the physical memory layout.
307 return Iterator(*this, 0);
308 }
310 return Iterator(*this, fSize);
311 }
312};
313
314/// \brief Reshape tensor in place
315/// \param[in] shape Shape vector
316/// Reshape tensor without changing the overall size
317template <typename Value_t, typename Container_t>
319{
320 const auto size = Internal::GetSizeFromShape(shape);
321 if (size != fSize) {
322 std::stringstream ss;
323 ss << "Cannot reshape tensor with size " << fSize << " into shape { ";
324 for (std::size_t i = 0; i < shape.size(); i++) {
325 if (i != shape.size() - 1) {
326 ss << shape[i] << ", ";
327 } else {
328 ss << shape[i] << " }.";
329 }
330 }
331 throw std::runtime_error(ss.str());
332 }
333
334 // Compute new strides from shape
335 auto strides = Internal::ComputeStridesFromShape(shape, fLayout);
336 fShape = shape;
337 fStrides = strides;
338}
339
340
341/// \brief Access elements
342/// \param[in] idx Index vector
343/// \return Reference to element
344template <typename Value_t, typename Container_t>
346{
347 const auto globalIndex = Internal::ComputeGlobalIndex(fStrides, idx);
348 return fData[globalIndex];
349}
350
351/// \brief Access elements
352/// \param[in] idx Index vector
353/// \return Reference to element
354template <typename Value_t, typename Container_t>
356{
357 const auto globalIndex = Internal::ComputeGlobalIndex(fStrides, idx);
358 return fData[globalIndex];
359}
360
361/// \brief Access elements
362/// \param[in] idx Indices
363/// \return Reference to element
364template <typename Value_t, typename Container_t>
365template <typename... Idx>
367{
369 "Indices are not convertible to std::size_t.");
370 return operator()({static_cast<std::size_t>(idx)...});
371}
372
373/// \brief Access elements
374/// \param[in] idx Indices
375/// \return Reference to element
376template <typename Value_t, typename Container_t>
377template <typename... Idx>
379{
381 "Indices are not convertible to std::size_t.");
382 return operator()({static_cast<std::size_t>(idx)...});
383}
384
385/// \brief Transpose
386/// \returns New RTensor
387/// The tensor is transposed by inverting the associated memory layout from row-
388/// major to column-major and vice versa. Therefore, the underlying data is not
389/// touched.
390template <typename Value_t, typename Container_t>
392{
394 // Transpose by inverting memory layout
395 if (fLayout == MemoryLayout::RowMajor) {
396 layout = MemoryLayout::ColumnMajor;
397 } else if (fLayout == MemoryLayout::ColumnMajor) {
398 layout = MemoryLayout::RowMajor;
399 } else {
400 throw std::runtime_error("Memory layout is not known.");
401 }
402
403 // Create copy of container
404 RTensor<Value_t, Container_t> x(fData, fShape, fStrides, layout);
405
406 // Reverse shape
407 std::reverse(x.fShape.begin(), x.fShape.end());
408
409 // Reverse strides
410 std::reverse(x.fStrides.begin(), x.fStrides.end());
411
412 return x;
413}
414
415/// \brief Squeeze dimensions
416/// \returns New RTensor
417/// Squeeze removes the dimensions of size one from the shape.
418template <typename Value_t, typename Container_t>
420{
421 // Remove dimensions of one and associated strides
422 Shape_t shape;
423 Shape_t strides;
424 for (std::size_t i = 0; i < fShape.size(); i++) {
425 if (fShape[i] != 1) {
426 shape.emplace_back(fShape[i]);
427 strides.emplace_back(fStrides[i]);
428 }
429 }
430
431 // If all dimensions are 1, we need to keep one.
432 // This does not apply if the inital shape is already empty. Then, return
433 // the empty shape.
434 if (shape.size() == 0 && fShape.size() != 0) {
435 shape.emplace_back(1);
436 strides.emplace_back(1);
437 }
438
439 // Create copy, attach new shape and strides and return
441 x.fShape = shape;
442 x.fStrides = strides;
443 return x;
444}
445
446/// \brief Expand dimensions
447/// \param[in] idx Index in shape vector where dimension is added
448/// \returns New RTensor
449/// Inserts a dimension of one into the shape.
450template <typename Value_t, typename Container_t>
452{
453 // Compose shape vector with additional dimensions and adjust strides
454 const int len = fShape.size();
455 auto shape = fShape;
456 auto strides = fStrides;
457 if (idx < 0) {
458 idx = len + 1 + idx;
459 }
460 if (idx < 0) {
461 throw std::runtime_error("Given negative index is invalid.");
462 }
463 else if (idx > len) {
464 throw std::runtime_error("Given index is invalid.");
465 }
466 shape.insert(shape.begin() + idx, 1);
467 strides = Internal::ComputeStridesFromShape(shape, fLayout);
468
469 // Create view copy, attach new shape and strides and return
471 x.fShape = shape;
472 x.fStrides = strides;
473 return x;
474}
475
476/// \brief Reshape tensor
477/// \param[in] shape Shape vector
478/// \returns New RTensor
479/// Reshape tensor without changing the overall size
480template <typename Value_t, typename Container_t>
482{
483 // Create copy, replace and return
485 x.ReshapeInplace(shape);
486 return x;
487}
488
489/// \brief Resize tensor
490/// \param[in] shape Shape vector
491/// \returns New RTensor
492/// Resize tensor into new shape
493template <typename Value_t, typename Container_t>
495{
496 // Create new tensor with the specified shape
497 RTensor <Value_t, Container_t> x(shape, fLayout);
498
499 // Copying contents from previous tensor
500 size_t n = (x.GetSize()>fSize) ? fSize : x.GetSize();
501 std::copy(this->GetData(), this->GetData() + n, x.GetData() );
502
503 return x;
504}
505
506/// \brief Create a slice of the tensor
507/// \param[in] slice Slice vector
508/// \returns New RTensor
509/// A slice is a subset of the tensor defined by a vector of pairs of indices.
510template <typename Value_t, typename Container_t>
512{
513 // Sanitize size of slice
514 const auto sliceSize = slice.size();
515 const auto shapeSize = fShape.size();
516 if (sliceSize != shapeSize) {
517 std::stringstream ss;
518 ss << "Size of slice (" << sliceSize << ") is unequal number of dimensions (" << shapeSize << ").";
519 throw std::runtime_error(ss.str());
520 }
521
522 // Sanitize slice indices
523 // TODO: Sanitize slice indices
524 /*
525 for (std::size_t i = 0; i < sliceSize; i++) {
526 }
527 */
528
529 // Convert -1 in slice to proper pair of indices
530 // TODO
531
532 // Recompute shape and size
533 Shape_t shape(sliceSize);
534 for (std::size_t i = 0; i < sliceSize; i++) {
535 shape[i] = slice[i][1] - slice[i][0];
536 }
537 auto size = Internal::GetSizeFromShape(shape);
538
539 // Determine first element contributing to the slice and get the data pointer
540 Value_t *data;
541 Shape_t idx(sliceSize);
542 for (std::size_t i = 0; i < sliceSize; i++) {
543 idx[i] = slice[i][0];
544 }
545 data = &operator()(idx);
546
547 // Create copy and modify properties
549 x.fData = data;
550 x.fShape = shape;
551 x.fSize = size;
552
553 // Squeeze tensor and return
554 return x.Squeeze();
555}
556
557/// Copy RTensor to new object
558/// \param[in] layout Memory layout of the new RTensor
559/// \returns New RTensor
560/// The operation copies all elements of the current RTensor to a new RTensor
561/// with the given layout contiguous in memory. Note that this copies by default
562/// to a row major memory layout.
563template <typename Value_t, typename Container_t>
565{
566 // Create new tensor with zeros owning the memory
568
569 // Copy over the elements from this tensor
570 const auto mins = Shape_t(fShape.size());
571 const auto maxs = fShape;
572 auto idx = mins;
573 Internal::RecursiveCopy(*this, r, mins, maxs, idx, 0);
574
575 return r;
576}
577
578/// \brief Pretty printing
579/// \param[in] os Output stream
580/// \param[in] x RTensor
581/// \return Modified output stream
582template <typename T>
583std::ostream &operator<<(std::ostream &os, RTensor<T> &x)
584{
585 const auto shapeSize = x.GetShape().size();
586 if (shapeSize == 1) {
587 os << "{ ";
588 const auto size = x.GetSize();
589 for (std::size_t i = 0; i < size; i++) {
590 os << x({i});
591 if (i != size - 1)
592 os << ", ";
593 }
594 os << " }";
595 } else if (shapeSize == 2) {
596 os << "{";
597 const auto shape = x.GetShape();
598 for (std::size_t i = 0; i < shape[0]; i++) {
599 os << " { ";
600 for (std::size_t j = 0; j < shape[1]; j++) {
601 os << x({i, j});
602 if (j < shape[1] - 1) {
603 os << ", ";
604 } else {
605 os << " ";
606 }
607 }
608 os << "}";
609 }
610 os << " }";
611 } else {
612 os << "{ printing not yet implemented for this rank }";
613 }
614 return os;
615}
616
617} // namespace TMVA::Experimental
618} // namespace TMVA
619
620namespace cling {
621template <typename T>
622std::string printValue(TMVA::Experimental::RTensor<T> *x)
623{
624 std::stringstream ss;
625 ss << *x;
626 return ss.str();
627}
628} // namespace cling
629
630#endif // TMVA_RTENSOR
dims_t fShape
dim_t fSize
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void data
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t r
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t UChar_t len
TRObject operator()(const T1 &t1) const
bool operator>=(const Iterator &rhs) const
Definition RTensor.hxx:299
bool operator==(const Iterator &rhs) const
Definition RTensor.hxx:291
std::random_access_iterator_tag iterator_category
Definition RTensor.hxx:270
Iterator(RTensor< Value_t, Container_t > &x, typename Index_t::value_type idx)
Definition RTensor.hxx:276
bool operator!=(const Iterator &rhs) const
Definition RTensor.hxx:296
difference_type operator-(const Iterator &rhs)
Definition RTensor.hxx:283
Iterator operator+(difference_type rhs) const
Definition RTensor.hxx:281
bool operator<(const Iterator &rhs) const
Definition RTensor.hxx:298
Iterator & operator+=(difference_type rhs)
Definition RTensor.hxx:284
Iterator & operator-=(difference_type rhs)
Definition RTensor.hxx:285
RTensor< Value_t, Container_t > & fTensor
Definition RTensor.hxx:267
bool operator>(const Iterator &rhs) const
Definition RTensor.hxx:297
Iterator operator-(difference_type rhs) const
Definition RTensor.hxx:282
Index_t::value_type GetGlobalIndex() const
Definition RTensor.hxx:301
bool operator<=(const Iterator &rhs) const
Definition RTensor.hxx:300
RTensor is a container with contiguous memory and shape information.
Definition RTensor.hxx:163
void ReshapeInplace(const Shape_t &shape)
Reshape tensor in place.
Definition RTensor.hxx:318
RTensor< Value_t, Container_t > Squeeze() const
Squeeze dimensions.
Definition RTensor.hxx:419
const std::shared_ptr< Container_t > GetContainer() const
Definition RTensor.hxx:248
Value_t & operator()(const Index_t &idx)
Access elements.
Definition RTensor.hxx:345
RTensor(Shape_t shape, MemoryLayout layout=MemoryLayout::RowMajor)
Construct a tensor owning data initialized with new container.
Definition RTensor.hxx:224
MemoryLayout GetMemoryLayout() const
Definition RTensor.hxx:249
Iterator end() noexcept
Definition RTensor.hxx:309
std::vector< Shape_t > Slice_t
Definition RTensor.hxx:169
RTensor(Value_t *data, Shape_t shape, Shape_t strides, MemoryLayout layout=MemoryLayout::RowMajor)
Construct a tensor as view on data.
Definition RTensor.hxx:202
RTensor< Value_t, Container_t > ExpandDims(int idx) const
Expand dimensions.
Definition RTensor.hxx:451
RTensor< Value_t, Container_t > Transpose() const
Transpose.
Definition RTensor.hxx:391
std::shared_ptr< Container_t > GetContainer()
Definition RTensor.hxx:247
Value_t & operator()(Idx... idx)
Access elements.
Definition RTensor.hxx:366
std::shared_ptr< Container_t > fContainer
Definition RTensor.hxx:178
RTensor(std::shared_ptr< Container_t > container, Shape_t shape, MemoryLayout layout=MemoryLayout::RowMajor)
Construct a tensor owning externally provided data.
Definition RTensor.hxx:212
RTensor< Value_t, Container_t > Resize(const Shape_t &shape)
Resize tensor.
Definition RTensor.hxx:494
RTensor< Value_t, Container_t > Copy(MemoryLayout layout=MemoryLayout::RowMajor) const
Copy RTensor to new object.
Definition RTensor.hxx:564
const Shape_t & GetStrides() const
Definition RTensor.hxx:244
std::size_t GetSize() const
Definition RTensor.hxx:242
RTensor< Value_t, Container_t > Reshape(const Shape_t &shape) const
Reshape tensor.
Definition RTensor.hxx:481
RTensor(Value_t *data, Shape_t shape, MemoryLayout layout=MemoryLayout::RowMajor)
Construct a tensor as view on data.
Definition RTensor.hxx:190
RTensor< Value_t, Container_t > Slice(const Slice_t &slice)
Create a slice of the tensor.
Definition RTensor.hxx:511
const Value_t * GetData() const
Definition RTensor.hxx:246
Iterator begin() noexcept
Definition RTensor.hxx:306
const Shape_t & GetShape() const
Definition RTensor.hxx:243
std::vector< std::size_t > Shape_t
Definition RTensor.hxx:167
Double_t x[n]
Definition legend1.C:17
const Int_t n
Definition legend1.C:16
void RecursiveCopy(const T &here, T &there, const std::vector< std::size_t > &mins, const std::vector< std::size_t > &maxs, std::vector< std::size_t > idx, std::size_t active)
Copy slice of a tensor recursively from here to there.
Definition RTensor.hxx:130
std::vector< std::size_t > ComputeStridesFromShape(const T &shape, MemoryLayout layout)
Compute strides from shape vector.
Definition RTensor.hxx:48
T ComputeIndicesFromGlobalIndex(const T &shape, MemoryLayout layout, const typename T::value_type idx)
Compute indices from global index.
Definition RTensor.hxx:82
std::size_t GetSizeFromShape(const T &shape)
Get size of tensor from shape vector.
Definition RTensor.hxx:29
std::size_t ComputeGlobalIndex(const U &strides, const V &idx)
Compute global index from indices.
Definition RTensor.hxx:100
MemoryLayout
Memory layout type (copy from RTensor.hxx)
Definition CudaTensor.h:47
std::ostream & operator<<(std::ostream &os, RTensor< T > &x)
Pretty printing.
Definition RTensor.hxx:583
create variable transformations
Type checking for all types of a parameter pack, e.g., used in combination with std::is_convertible.
Definition RTensor.hxx:112