AARE
Data analysis library for PSI hybrid detectors
Loading...
Searching...
No Matches
NDArray.hpp
Go to the documentation of this file.
1#pragma once
2/*
3Container holding image data, or a time series of image data in contigious
4memory.
5
6
7TODO! Add expression templates for operators
8
9*/
10#include "aare/core/NDView.hpp"
11
12#include <algorithm>
13#include <array>
14#include <cmath>
15#include <fmt/format.h>
16#include <fstream>
17#include <iomanip>
18#include <iostream>
19#include <numeric>
20
21namespace aare {
22
23template <typename T, ssize_t Ndim = 2> class NDArray {
24 public:
25 NDArray() : shape_(), strides_(c_strides<Ndim>(shape_)), size_(0), data_(nullptr){};
26
27 explicit NDArray(std::array<ssize_t, Ndim> shape)
29 size_(std::accumulate(shape_.begin(), shape_.end(), 1, std::multiplies<ssize_t>())), data_(new T[size_]){};
30
31 NDArray(std::array<ssize_t, Ndim> shape, T value) : NDArray(shape) { this->operator=(value); }
32
33 /* When constructing from a NDView we need to copy the data since
34 NDArray expect to own its data, and span is just a view*/
36 std::copy(span.begin(), span.end(), begin());
37 // fmt::print("NDArray(NDView<T, Ndim> span)\n");
38 }
39
40 // Move constructor
42 : shape_(other.shape_), strides_(c_strides<Ndim>(shape_)), size_(other.size_), data_(nullptr) {
43 data_ = other.data_;
44 other.reset();
45 // fmt::print("NDArray(NDArray &&other)\n");
46 }
47
48 // Copy constructor
49 NDArray(const NDArray &other)
50 : shape_(other.shape_), strides_(c_strides<Ndim>(shape_)), size_(other.size_), data_(new T[size_]) {
51 std::copy(other.data_, other.data_ + size_, data_);
52 // fmt::print("NDArray(const NDArray &other)\n");
53 }
54
55 ~NDArray() { delete[] data_; }
56
57 auto begin() { return data_; }
58 auto end() { return data_ + size_; }
59
60 using value_type = T;
61
62 NDArray &operator=(NDArray &&other); // Move assign
63 NDArray &operator=(const NDArray &other); // Copy assign
64
65 NDArray operator+(const NDArray &other);
66 NDArray &operator+=(const NDArray &other);
67 NDArray operator-(const NDArray &other);
68 NDArray &operator-=(const NDArray &other);
69 NDArray operator*(const NDArray &other);
70 NDArray &operator*=(const NDArray &other);
71 NDArray operator/(const NDArray &other);
72 // NDArray& operator/=(const NDArray& other);
73 template <typename V> NDArray &operator/=(const NDArray<V, Ndim> &other) {
74 // check shape
75 if (shape_ == other.shape()) {
76 for (int i = 0; i < size_; ++i) {
77 data_[i] /= other(i);
78 }
79 return *this;
80 } else {
81 throw(std::runtime_error("Shape of NDArray must match"));
82 }
83 }
84
86
87 bool operator==(const NDArray &other) const;
88 bool operator!=(const NDArray &other) const;
89
90 NDArray &operator=(const T &);
91 NDArray &operator+=(const T &);
92 NDArray operator+(const T &);
93 NDArray &operator-=(const T &);
94 NDArray operator-(const T &);
95 NDArray &operator*=(const T &);
96 NDArray operator*(const T &);
97 NDArray &operator/=(const T &);
98 NDArray operator/(const T &);
99
100 NDArray &operator&=(const T &);
101
102 void sqrt() {
103 for (int i = 0; i < size_; ++i) {
104 data_[i] = std::sqrt(data_[i]);
105 }
106 }
107
108 NDArray &operator++(); // pre inc
109
110 template <typename... Ix> typename std::enable_if<sizeof...(Ix) == Ndim, T &>::type operator()(Ix... index) {
111 return data_[element_offset(strides_, index...)];
112 }
113
114 template <typename... Ix> typename std::enable_if<sizeof...(Ix) == Ndim, T &>::type operator()(Ix... index) const {
115 return data_[element_offset(strides_, index...)];
116 }
117
118 template <typename... Ix> typename std::enable_if<sizeof...(Ix) == Ndim, T>::type value(Ix... index) {
119 return data_[element_offset(strides_, index...)];
120 }
121
122 T &operator()(int i) { return data_[i]; }
123 const T &operator()(int i) const { return data_[i]; }
124
125 T *data() { return data_; }
126 std::byte *buffer() { return reinterpret_cast<std::byte *>(data_); }
127 ssize_t size() const { return size_; }
128 size_t total_bytes() const { return size_ * sizeof(T); }
129 std::array<ssize_t, Ndim> shape() const noexcept { return shape_; }
130 ssize_t shape(ssize_t i) const noexcept { return shape_[i]; }
131 std::array<ssize_t, Ndim> strides() const noexcept { return strides_; }
132 std::array<ssize_t, Ndim> byte_strides() const noexcept {
133 auto byte_strides = strides_;
134 for (auto &val : byte_strides)
135 val *= sizeof(T);
136 return byte_strides;
137 // return strides_;
138 }
139
141
142 void Print();
143 void Print_all();
145
146 void reset() {
147 data_ = nullptr;
148 size_ = 0;
149 std::fill(shape_.begin(), shape_.end(), 0);
150 std::fill(strides_.begin(), strides_.end(), 0);
151 }
152
153 private:
154 std::array<ssize_t, Ndim> shape_;
155 std::array<ssize_t, Ndim> strides_;
156 ssize_t size_;
158};
159
160// Move assign
161template <typename T, ssize_t Ndim> NDArray<T, Ndim> &NDArray<T, Ndim>::operator=(NDArray<T, Ndim> &&other) {
162 if (this != &other) {
163 delete[] data_;
164 data_ = other.data_;
165 shape_ = other.shape_;
166 size_ = other.size_;
167 strides_ = other.strides_;
168 other.reset();
169 }
170 return *this;
171}
172
173template <typename T, ssize_t Ndim> NDArray<T, Ndim> NDArray<T, Ndim>::operator+(const NDArray &other) {
174 NDArray result(*this);
175 result += other;
176 return result;
177}
178template <typename T, ssize_t Ndim> NDArray<T, Ndim> &NDArray<T, Ndim>::operator+=(const NDArray<T, Ndim> &other) {
179 // check shape
180 if (shape_ == other.shape_) {
181 for (int i = 0; i < size_; ++i) {
182 data_[i] += other.data_[i];
183 }
184 return *this;
185 } else {
186 throw(std::runtime_error("Shape of ImageDatas must match"));
187 }
188}
189
190template <typename T, ssize_t Ndim> NDArray<T, Ndim> NDArray<T, Ndim>::operator-(const NDArray &other) {
191 NDArray result{*this};
192 result -= other;
193 return result;
194}
195
196template <typename T, ssize_t Ndim> NDArray<T, Ndim> &NDArray<T, Ndim>::operator-=(const NDArray<T, Ndim> &other) {
197 // check shape
198 if (shape_ == other.shape_) {
199 for (int i = 0; i < size_; ++i) {
200 data_[i] -= other.data_[i];
201 }
202 return *this;
203 } else {
204 throw(std::runtime_error("Shape of ImageDatas must match"));
205 }
206}
207template <typename T, ssize_t Ndim> NDArray<T, Ndim> NDArray<T, Ndim>::operator*(const NDArray &other) {
208 NDArray result = *this;
209 result *= other;
210 return result;
211}
212
213template <typename T, ssize_t Ndim> NDArray<T, Ndim> &NDArray<T, Ndim>::operator*=(const NDArray<T, Ndim> &other) {
214 // check shape
215 if (shape_ == other.shape_) {
216 for (int i = 0; i < size_; ++i) {
217 data_[i] *= other.data_[i];
218 }
219 return *this;
220 } else {
221 throw(std::runtime_error("Shape of ImageDatas must match"));
222 }
223}
224
225template <typename T, ssize_t Ndim> NDArray<T, Ndim> NDArray<T, Ndim>::operator/(const NDArray &other) {
226 NDArray result = *this;
227 result /= other;
228 return result;
229}
230
231template <typename T, ssize_t Ndim> NDArray<T, Ndim> &NDArray<T, Ndim>::operator&=(const T &mask) {
232 for (auto it = begin(); it != end(); ++it)
233 *it &= mask;
234 return *this;
235}
236
237// template <typename T, ssize_t Ndim>
238// NDArray<T, Ndim>& NDArray<T, Ndim>::operator/=(const NDArray<T, Ndim>&
239// other)
240// {
241// //check shape
242// if (shape_ == other.shape_) {
243// for (int i = 0; i < size_; ++i) {
244// data_[i] /= other.data_[i];
245// }
246// return *this;
247// } else {
248// throw(std::runtime_error("Shape of ImageDatas must match"));
249// }
250// }
251
252template <typename T, ssize_t Ndim> NDArray<bool, Ndim> NDArray<T, Ndim>::operator>(const NDArray &other) {
253 if (shape_ == other.shape_) {
254 NDArray<bool> result{shape_};
255 for (int i = 0; i < size_; ++i) {
256 result(i) = (data_[i] > other.data_[i]);
257 }
258 return result;
259 } else {
260 throw(std::runtime_error("Shape of ImageDatas must match"));
261 }
262}
263
264template <typename T, ssize_t Ndim> NDArray<T, Ndim> &NDArray<T, Ndim>::operator=(const NDArray<T, Ndim> &other) {
265 if (this != &other) {
266 delete[] data_;
267 shape_ = other.shape_;
268 strides_ = other.strides_;
269 size_ = other.size_;
270 data_ = new T[size_];
271 std::copy(other.data_, other.data_ + size_, data_);
272 }
273 return *this;
274}
275
276template <typename T, ssize_t Ndim> bool NDArray<T, Ndim>::operator==(const NDArray<T, Ndim> &other) const {
277 if (shape_ != other.shape_)
278 return false;
279
280 for (int i = 0; i != size_; ++i)
281 if (data_[i] != other.data_[i])
282 return false;
283
284 return true;
285}
286
287template <typename T, ssize_t Ndim> bool NDArray<T, Ndim>::operator!=(const NDArray<T, Ndim> &other) const {
288 return !((*this) == other);
289}
290template <typename T, ssize_t Ndim> NDArray<T, Ndim> &NDArray<T, Ndim>::operator++() {
291 for (int i = 0; i < size_; ++i)
292 data_[i] += 1;
293 return *this;
294}
295template <typename T, ssize_t Ndim> NDArray<T, Ndim> &NDArray<T, Ndim>::operator=(const T &value) {
296 std::fill_n(data_, size_, value);
297 return *this;
298}
299
300template <typename T, ssize_t Ndim> NDArray<T, Ndim> &NDArray<T, Ndim>::operator+=(const T &value) {
301 for (int i = 0; i < size_; ++i)
302 data_[i] += value;
303 return *this;
304}
305
306template <typename T, ssize_t Ndim> NDArray<T, Ndim> NDArray<T, Ndim>::operator+(const T &value) {
307 NDArray result = *this;
308 result += value;
309 return result;
310}
311template <typename T, ssize_t Ndim> NDArray<T, Ndim> &NDArray<T, Ndim>::operator-=(const T &value) {
312 for (int i = 0; i < size_; ++i)
313 data_[i] -= value;
314 return *this;
315}
316template <typename T, ssize_t Ndim> NDArray<T, Ndim> NDArray<T, Ndim>::operator-(const T &value) {
317 NDArray result = *this;
318 result -= value;
319 return result;
320}
321
322template <typename T, ssize_t Ndim> NDArray<T, Ndim> &NDArray<T, Ndim>::operator/=(const T &value) {
323 for (int i = 0; i < size_; ++i)
324 data_[i] /= value;
325 return *this;
326}
327template <typename T, ssize_t Ndim> NDArray<T, Ndim> NDArray<T, Ndim>::operator/(const T &value) {
328 NDArray result = *this;
329 result /= value;
330 return result;
331}
332template <typename T, ssize_t Ndim> NDArray<T, Ndim> &NDArray<T, Ndim>::operator*=(const T &value) {
333 for (int i = 0; i < size_; ++i)
334 data_[i] *= value;
335 return *this;
336}
337template <typename T, ssize_t Ndim> NDArray<T, Ndim> NDArray<T, Ndim>::operator*(const T &value) {
338 NDArray result = *this;
339 result *= value;
340 return result;
341}
342template <typename T, ssize_t Ndim> void NDArray<T, Ndim>::Print() {
343 if (shape_[0] < 20 && shape_[1] < 20)
344 Print_all();
345 else
346 Print_some();
347}
348template <typename T, ssize_t Ndim> void NDArray<T, Ndim>::Print_all() {
349 for (auto row = 0; row < shape_[0]; ++row) {
350 for (auto col = 0; col < shape_[1]; ++col) {
351 std::cout << std::setw(3);
352 std::cout << (*this)(row, col) << " ";
353 }
354 std::cout << "\n";
355 }
356}
357template <typename T, ssize_t Ndim> void NDArray<T, Ndim>::Print_some() {
358 for (auto row = 0; row < 5; ++row) {
359 for (auto col = 0; col < 5; ++col) {
360 std::cout << std::setw(7);
361 std::cout << (*this)(row, col) << " ";
362 }
363 std::cout << "\n";
364 }
365}
366
367template <typename T, ssize_t Ndim> void save(NDArray<T, Ndim> &img, std::string pathname) {
368 std::ofstream f;
369 f.open(pathname, std::ios::binary);
370 f.write(img.buffer(), img.size() * sizeof(T));
371 f.close();
372}
373
374template <typename T, ssize_t Ndim>
375NDArray<T, Ndim> load(const std::string &pathname, std::array<ssize_t, Ndim> shape) {
376 NDArray<T, Ndim> img{shape};
377 std::ifstream f;
378 f.open(pathname, std::ios::binary);
379 f.read(img.buffer(), img.size() * sizeof(T));
380 f.close();
381 return img;
382}
383
384} // namespace aare
Definition NDArray.hpp:23
NDArray & operator++()
Definition NDArray.hpp:290
NDArray(NDView< T, Ndim > span)
Definition NDArray.hpp:35
T value_type
Definition NDArray.hpp:60
NDArray & operator=(NDArray &&other)
Definition NDArray.hpp:161
std::array< ssize_t, Ndim > strides() const noexcept
Definition NDArray.hpp:131
NDArray(const NDArray &other)
Definition NDArray.hpp:49
NDArray & operator+=(const NDArray &other)
Definition NDArray.hpp:178
NDArray & operator/=(const NDArray< V, Ndim > &other)
Definition NDArray.hpp:73
std::array< ssize_t, Ndim > byte_strides() const noexcept
Definition NDArray.hpp:132
NDArray operator*(const T &)
Definition NDArray.hpp:337
NDArray(std::array< ssize_t, Ndim > shape)
Definition NDArray.hpp:27
auto begin()
Definition NDArray.hpp:57
NDArray()
Definition NDArray.hpp:25
std::array< ssize_t, Ndim > strides_
Definition NDArray.hpp:155
NDArray & operator*=(const NDArray &other)
Definition NDArray.hpp:213
NDArray< bool, Ndim > operator>(const NDArray &other)
Definition NDArray.hpp:252
NDArray operator/(const NDArray &other)
Definition NDArray.hpp:225
void Print_some()
Definition NDArray.hpp:357
NDArray & operator=(const T &)
Definition NDArray.hpp:295
NDArray(std::array< ssize_t, Ndim > shape, T value)
Definition NDArray.hpp:31
void Print_all()
Definition NDArray.hpp:348
NDArray operator/(const T &)
Definition NDArray.hpp:327
std::array< ssize_t, Ndim > shape() const noexcept
Definition NDArray.hpp:129
~NDArray()
Definition NDArray.hpp:55
NDArray & operator=(const NDArray &other)
Definition NDArray.hpp:264
T * data()
Definition NDArray.hpp:125
NDArray(NDArray &&other)
Definition NDArray.hpp:41
NDArray operator+(const T &)
Definition NDArray.hpp:306
NDArray & operator/=(const T &)
Definition NDArray.hpp:322
ssize_t size() const
Definition NDArray.hpp:127
T & operator()(int i)
Definition NDArray.hpp:122
bool operator!=(const NDArray &other) const
Definition NDArray.hpp:287
void reset()
Definition NDArray.hpp:146
NDArray & operator+=(const T &)
Definition NDArray.hpp:300
NDArray operator-(const NDArray &other)
Definition NDArray.hpp:190
NDArray & operator-=(const NDArray &other)
Definition NDArray.hpp:196
NDArray & operator&=(const T &)
Definition NDArray.hpp:231
size_t total_bytes() const
Definition NDArray.hpp:128
NDView< T, Ndim > span() const
Definition NDArray.hpp:140
ssize_t size_
Definition NDArray.hpp:156
bool operator==(const NDArray &other) const
Definition NDArray.hpp:276
T * data_
Definition NDArray.hpp:157
void Print()
Definition NDArray.hpp:342
NDArray & operator-=(const T &)
Definition NDArray.hpp:311
std::enable_if< sizeof...(Ix)==Ndim, T >::type value(Ix... index)
Definition NDArray.hpp:118
const T & operator()(int i) const
Definition NDArray.hpp:123
NDArray operator*(const NDArray &other)
Definition NDArray.hpp:207
NDArray operator-(const T &)
Definition NDArray.hpp:316
auto end()
Definition NDArray.hpp:58
std::array< ssize_t, Ndim > shape_
Definition NDArray.hpp:154
std::byte * buffer()
Definition NDArray.hpp:126
void sqrt()
Definition NDArray.hpp:102
ssize_t shape(ssize_t i) const noexcept
Definition NDArray.hpp:130
NDArray operator+(const NDArray &other)
Definition NDArray.hpp:173
NDArray & operator*=(const T &)
Definition NDArray.hpp:332
Definition NDView.hpp:46
Frame class to represent a single frame of data model class should be able to work with streams comin...
Definition CircularFifo.hpp:11
NDArray< T, Ndim > load(const std::string &pathname, std::array< ssize_t, Ndim > shape)
Definition NDArray.hpp:375
ssize_t element_offset(const Strides &)
Definition NDView.hpp:23
std::array< ssize_t, Ndim > c_strides(const std::array< ssize_t, Ndim > &shape)
Definition NDView.hpp:30
void save(NDArray< T, Ndim > &img, std::string pathname)
Definition NDArray.hpp:367