Alexandria  2.14.1
Please provide a description of the project.
NdArray.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2012-2020 Euclid Science Ground Segment
3  *
4  * This library is free software; you can redistribute it and/or modify it under
5  * the terms of the GNU Lesser General Public License as published by the Free
6  * Software Foundation; either version 3.0 of the License, or (at your option)
7  * any later version.
8  *
9  * This library is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11  * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12  * details.
13  *
14  * You should have received a copy of the GNU Lesser General Public License
15  * along with this library; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18 
25 #ifndef ALEXANDRIA_MATRIX_H
26 #define ALEXANDRIA_MATRIX_H
27 
28 #include <iostream>
29 #include <numeric>
30 #include <stdexcept>
31 #include <vector>
32 #include <cassert>
33 
34 namespace Euclid {
35 namespace NdArray {
36 
44 template<typename T, template<class...> class Container = std::vector>
45 class NdArray {
46 public:
47  typedef typename Container<T>::iterator iterator;
48  typedef typename Container<T>::const_iterator const_iterator;
50 
54  virtual ~NdArray() = default;
55 
65 
66  size_t acc = 1;
67  for (int i = m_stride_size.size() - 1; i >= 0; --i) {
68  m_stride_size[i] = acc;
69  acc *= m_shape[i];
70  }
71  }
72 
83  NdArray(const std::vector<size_t> &shape, const Container<T> &data) : m_shape{shape}, m_container{data} {
84  size_t expected_size = std::accumulate(m_shape.begin(), m_shape.end(), 1, std::multiplies<size_t>());
85  if (expected_size != m_container.size()) {
86  throw std::invalid_argument("Data size does not match the shape");
87  }
88 
90 
91  size_t acc = 1;
92  for (int i = m_stride_size.size() - 1; i >= 0; --i) {
93  m_stride_size[i] = acc;
94  acc *= m_shape[i];
95  }
96  }
97 
111  size_t expected_size = std::accumulate(m_shape.begin(), m_shape.end(), 1, std::multiplies<size_t>());
112  if (expected_size != m_container.size()) {
113  throw std::invalid_argument("Data size does not match the shape");
114  }
115 
117 
118  size_t acc = 1;
119  for (int i = m_stride_size.size() - 1; i >= 0; --i) {
120  m_stride_size[i] = acc;
121  acc *= m_shape[i];
122  }
123  }
124 
132 
136  NdArray(const self_type&) = default;
137 
141  NdArray(self_type&&) = default;
142 
146  NdArray& operator = (const NdArray&) = default;
147 
153  const std::vector<size_t> shape() const {
154  return m_shape;
155  }
156 
164  T &at(const std::vector<size_t> &coords) {
165  auto offset = getOffset(coords);
166  return m_container[offset];
167  };
168 
176  const T &at(const std::vector<size_t> &coords) const {
177  auto offset = getOffset(coords);
178  return m_container[offset];
179  };
180 
191  template <typename ...D>
192  T &at(size_t i, D... rest) {
193  std::vector<size_t> acc{i};
194  return at_helper(acc, rest...);
195  }
196 
207  template <typename ...D>
208  const T &at(size_t i, D... rest) const {
209  std::vector<size_t> acc{i};
210  return at_helper(acc, rest...);
211  }
212 
218  return m_container.begin();
219  }
220 
226  return m_container.end();
227  }
228 
234  return m_container.begin();
235  }
236 
241  const_iterator end() const {
242  return m_container.end();
243  }
244 
248  const Container<T>& data() const {
249  return m_container;
250  }
251 
255  size_t size() const {
256  return m_container.size();
257  }
258 
262  bool operator == (const self_type& b) const {
263  return shape() == b.shape() && data() == b.data();
264  }
265 
269  bool operator != (const self_type& b) const {
270  return shape() != b.shape() || data() != b.data();
271  }
272 
273 private:
275  Container<T> m_container;
276 
282  size_t getOffset(const std::vector<size_t> &coords) const {
283  if (coords.size() != m_shape.size()) {
284  throw std::out_of_range(
285  "Invalid number of coordinates, got " + std::to_string(coords.size()) + ", expected " + std::to_string(m_shape.size())
286  );
287  }
288 
289  size_t offset = 0;
290  for (size_t i = 0; i < coords.size(); ++i) {
291  if (coords[i] >= m_shape[i]) {
292  throw std::out_of_range(
293  std::to_string(coords[i]) + " >= " + std::to_string(m_shape[i]) + " for axis " + std::to_string(i)
294  );
295  }
296  offset += coords[i] * m_stride_size[i];
297  }
298 
299  assert(offset < m_container.size());
300  return offset;
301  };
302 
306  template <typename ...D>
307  T &at_helper(std::vector<size_t> &acc, size_t i, D... rest) {
308  acc.push_back(i);
309  return at_helper(acc, rest...);
310  }
311 
316  return at(acc);
317  }
318 
322  template <typename ...D>
323  const T &at_helper(std::vector<size_t> &acc, size_t i, D... rest) const {
324  acc.push_back(i);
325  return at_helper(acc, rest...);
326  }
327 
331  const T &at_helper(std::vector<size_t> &acc) const {
332  return at(acc);
333  }
334 };
335 
339 template<typename T, template<class...> class Container>
341  size_t i;
342  auto shape = ndarray.shape();
343 
344  if (ndarray.size()) {
345  out << "<";
346  for (i = 0; i < shape.size() - 1; ++i) {
347  out << shape[i] << ",";
348  }
349  out << shape[i] << ">";
350  for (i = 0; i < ndarray.size() - 1; ++i) {
351  out << ndarray.data()[i] << ",";
352  }
353  out << ndarray.data()[i];
354  }
355  return out;
356 }
357 
358 } // end NdArray
359 } // end Euclid
360 
361 #endif // ALEXANDRIA_MATRIX_H
T & at_helper(std::vector< size_t > &acc)
Definition: NdArray.h:315
bool operator!=(const self_type &b) const
Definition: NdArray.h:269
const T & at(size_t i, D... rest) const
Definition: NdArray.h:208
Container< T > m_container
Definition: NdArray.h:275
const T & at_helper(std::vector< size_t > &acc) const
Definition: NdArray.h:331
T to_string(T... args)
STL namespace.
T end(T... args)
T & at(const std::vector< size_t > &coords)
Definition: NdArray.h:164
T resize(T... args)
size_t size() const
Definition: NdArray.h:255
T & at_helper(std::vector< size_t > &acc, size_t i, D... rest)
Definition: NdArray.h:307
NdArray & operator=(const NdArray &)=default
std::vector< size_t > m_stride_size
Definition: NdArray.h:274
T push_back(T... args)
T & at(size_t i, D... rest)
Definition: NdArray.h:192
const Container< T > & data() const
Definition: NdArray.h:248
NdArray(const std::vector< size_t > &shape)
Definition: NdArray.h:62
const std::vector< size_t > shape() const
Definition: NdArray.h:153
std::vector< size_t > m_shape
Definition: NdArray.h:274
size_t getOffset(const std::vector< size_t > &coords) const
Definition: NdArray.h:282
NdArray(const std::vector< size_t > &shape, Container< T > &&data)
Definition: NdArray.h:110
const T & at(const std::vector< size_t > &coords) const
Definition: NdArray.h:176
std::ostream & operator<<(std::ostream &out, const NdArray< T, Container > &ndarray)
Definition: NdArray.h:340
T move(T... args)
T size(T... args)
NdArray(const std::vector< size_t > &shape, const Container< T > &data)
Definition: NdArray.h:83
const T & at_helper(std::vector< size_t > &acc, size_t i, D... rest) const
Definition: NdArray.h:323
STL class.
T begin(T... args)
virtual ~NdArray()=default
bool operator==(const self_type &b) const
Definition: NdArray.h:262
const_iterator end() const
Definition: NdArray.h:241
NdArray< T, Container > self_type
Definition: NdArray.h:49
T accumulate(T... args)
Container< T >::iterator iterator
Definition: NdArray.h:47
STL class.
Container< T >::const_iterator const_iterator
Definition: NdArray.h:48
const_iterator begin() const
Definition: NdArray.h:233
NdArray(const std::initializer_list< size_t > &shape)
Definition: NdArray.h:131