NumCpp  2.11.0
A Templatized Header Only C++ Implementation of the Python NumPy Library
NdArrayCore.hpp
Go to the documentation of this file.
1 #pragma once
29 
30 #include <array>
31 #include <cmath>
32 #include <deque>
33 #include <filesystem>
34 #include <forward_list>
35 #include <fstream>
36 #include <initializer_list>
37 #include <iostream>
38 #include <iterator>
39 #include <list>
40 #include <memory>
41 #include <numeric>
42 #include <set>
43 #include <string>
44 #include <type_traits>
45 #include <utility>
46 #include <vector>
47 
56 #include "NumCpp/Core/Shape.hpp"
57 #include "NumCpp/Core/Slice.hpp"
58 #include "NumCpp/Core/Types.hpp"
62 #include "NumCpp/Utils/num2str.hpp"
63 #include "NumCpp/Utils/power.hpp"
64 #include "NumCpp/Utils/sqr.hpp"
66 
67 namespace nc
68 {
69  namespace type_traits
70  {
71  //============================================================================
72  // Class Description:
75  template<typename>
76  struct is_ndarray_int : std::false_type
77  {
78  };
79 
80  //============================================================================
81  // Class Description:
84 
85  template<typename dtype, typename Allocator>
86  struct is_ndarray_int<NdArray<dtype, Allocator>>
87  {
88  static constexpr bool value = std::is_integral_v<dtype>;
89  };
90 
91  //============================================================================
92  // Class Description:
95  template<typename T>
97 
98  //============================================================================
99  // Class Description:
102  template<typename>
103  struct is_ndarray_signed_int : std::false_type
104  {
105  };
106 
107  //============================================================================
108  // Class Description:
111 
112  template<typename dtype, typename Allocator>
113  struct is_ndarray_signed_int<NdArray<dtype, Allocator>>
114  {
115  static constexpr bool value = std::is_signed_v<dtype>;
116  };
117 
118  //============================================================================
119  // Class Description:
122  template<typename T>
124 
125  //============================================================================
126  // Class Description:
129  template<typename T>
130  using ndarray_int_concept = std::enable_if_t<is_ndarray_int_v<T>, int>;
131  } // namespace type_traits
132 
133  //================================================================================
134  // Class Description:
136  template<typename dtype, class Allocator = std::allocator<dtype>>
137  class NdArray
138  {
139  private:
140  STATIC_ASSERT_VALID_DTYPE(dtype);
141  static_assert(std::is_same_v<dtype, typename Allocator::value_type>,
142  "value_type and Allocator::value_type must match");
143 
144  using AllocType = typename std::allocator_traits<Allocator>::template rebind_alloc<dtype>;
145  using AllocTraits = std::allocator_traits<AllocType>;
146 
147  public:
149  using value_type = dtype;
150  using allocator_type = Allocator;
151  using pointer = typename AllocTraits::pointer;
152  using const_pointer = typename AllocTraits::const_pointer;
153  using reference = dtype&;
154  using const_reference = const dtype&;
155  using size_type = uint32;
156  using index_type = int32;
157  using difference_type = typename AllocTraits::difference_type;
158 
161  using reverse_iterator = std::reverse_iterator<iterator>;
162  using const_reverse_iterator = std::reverse_iterator<const_iterator>;
163 
166  using reverse_column_iterator = std::reverse_iterator<column_iterator>;
167  using const_reverse_column_iterator = std::reverse_iterator<const_column_iterator>;
168 
169  //============================================================================
170  // Method Description:
173  NdArray() = default;
174 
175  //============================================================================
176  // Method Description:
181  explicit NdArray(size_type inSquareSize) :
182  shape_(inSquareSize, inSquareSize),
183  size_(inSquareSize * inSquareSize)
184  {
185  newArray();
186  }
187 
188  //============================================================================
189  // Method Description:
195  NdArray(size_type inNumRows, size_type inNumCols) :
196  shape_(inNumRows, inNumCols),
197  size_(inNumRows * inNumCols)
198  {
199  newArray();
200  }
201 
202  //============================================================================
203  // Method Description:
208  explicit NdArray(const Shape& inShape) :
209  shape_(inShape),
210  size_(shape_.size())
211  {
212  newArray();
213  }
214 
215  //============================================================================
216  // Method Description:
221  NdArray(std::initializer_list<dtype> inList) :
222  shape_(1, static_cast<uint32>(inList.size())),
223  size_(shape_.size())
224  {
225  newArray();
226  if (size_ > 0)
227  {
228  stl_algorithms::copy(inList.begin(), inList.end(), begin());
229  }
230  }
231 
232  //============================================================================
233  // Method Description:
238  NdArray(const std::initializer_list<std::initializer_list<dtype>>& inList) :
239  shape_(static_cast<uint32>(inList.size()), 0)
240  {
241  for (const auto& list : inList)
242  {
243  if (shape_.cols == 0)
244  {
245  shape_.cols = static_cast<uint32>(list.size());
246  }
247  else if (list.size() != shape_.cols)
248  {
250  "All rows of the initializer list needs to have the same number of elements");
251  }
252  }
253 
254  size_ = shape_.size();
255  newArray();
256  uint32 row = 0;
257  for (const auto& list : inList)
258  {
259  const auto ptr = begin() += row * shape_.cols;
260  stl_algorithms::copy(list.begin(), list.end(), ptr);
261  ++row;
262  }
263  }
264 
265  //============================================================================
266  // Method Description:
273  template<size_t ArraySize, std::enable_if_t<is_valid_dtype_v<dtype>, int> = 0>
274  NdArray(std::array<dtype, ArraySize>& inArray, bool copy = true) :
275  shape_(1, static_cast<uint32>(ArraySize)),
276  size_(shape_.size())
277  {
278  if (copy)
279  {
280  newArray();
281  if (size_ > 0)
282  {
283  stl_algorithms::copy(inArray.begin(), inArray.end(), begin());
284  }
285  }
286  else
287  {
288  array_ = inArray.data();
289  ownsPtr_ = false;
290  }
291  }
292 
293  //============================================================================
294  // Method Description:
301  template<size_t Dim0Size, size_t Dim1Size>
302  NdArray(std::array<std::array<dtype, Dim1Size>, Dim0Size>& in2dArray, bool copy = true) :
303  shape_(static_cast<uint32>(Dim0Size), static_cast<uint32>(Dim1Size)),
304  size_(shape_.size())
305  {
306  if (copy)
307  {
308  newArray();
309  if (size_ > 0)
310  {
311  const auto start = in2dArray.front().begin();
312  stl_algorithms::copy(start, start + size_, begin());
313  }
314  }
315  else
316  {
317  array_ = in2dArray.front().data();
318  ownsPtr_ = false;
319  }
320  }
321 
322  //============================================================================
323  // Method Description:
330  template<std::enable_if_t<is_valid_dtype_v<dtype>, int> = 0>
331  NdArray(std::vector<dtype>& inVector, bool copy = true) :
332  shape_(1, static_cast<uint32>(inVector.size())),
333  size_(shape_.size())
334  {
335  if (copy)
336  {
337  newArray();
338  if (size_ > 0)
339  {
340  stl_algorithms::copy(inVector.begin(), inVector.end(), begin());
341  }
342  }
343  else
344  {
345  array_ = inVector.data();
346  ownsPtr_ = false;
347  }
348  }
349 
350  //============================================================================
351  // Method Description:
356  explicit NdArray(const std::vector<std::vector<dtype>>& in2dVector) :
357  shape_(static_cast<uint32>(in2dVector.size()), 0)
358  {
359  for (const auto& row : in2dVector)
360  {
361  if (shape_.cols == 0)
362  {
363  shape_.cols = static_cast<uint32>(row.size());
364  }
365  else if (row.size() != shape_.cols)
366  {
367  THROW_INVALID_ARGUMENT_ERROR("All rows of the 2d vector need to have the same number of elements");
368  }
369  }
370 
371  size_ = shape_.size();
372 
373  newArray();
374  auto currentPosition = begin();
375  for (const auto& row : in2dVector)
376  {
377  stl_algorithms::copy(row.begin(), row.end(), currentPosition);
378  currentPosition += shape_.cols;
379  }
380  }
381 
382  //============================================================================
383  // Method Description:
390  template<size_t Dim1Size>
391  NdArray(std::vector<std::array<dtype, Dim1Size>>& in2dArray, bool copy = true) :
392  shape_(static_cast<uint32>(in2dArray.size()), static_cast<uint32>(Dim1Size)),
393  size_(shape_.size())
394  {
395  if (copy)
396  {
397  newArray();
398  if (size_ > 0)
399  {
400  const auto start = in2dArray.front().begin();
401  stl_algorithms::copy(start, start + size_, begin());
402  }
403  }
404  else
405  {
406  array_ = in2dArray.front().data();
407  ownsPtr_ = false;
408  }
409  }
410 
411  //============================================================================
412  // Method Description:
417  template<std::enable_if_t<is_valid_dtype_v<dtype>, int> = 0>
418  explicit NdArray(const std::deque<dtype>& inDeque) :
419  shape_(1, static_cast<uint32>(inDeque.size())),
420  size_(shape_.size())
421  {
422  newArray();
423  if (size_ > 0)
424  {
425  stl_algorithms::copy(inDeque.begin(), inDeque.end(), begin());
426  }
427  }
428 
429  //============================================================================
430  // Method Description:
435  explicit NdArray(const std::deque<std::deque<dtype>>& in2dDeque) :
436  shape_(static_cast<uint32>(in2dDeque.size()), 0)
437  {
438  for (const auto& row : in2dDeque)
439  {
440  if (shape_.cols == 0)
441  {
442  shape_.cols = static_cast<uint32>(row.size());
443  }
444  else if (row.size() != shape_.cols)
445  {
446  THROW_INVALID_ARGUMENT_ERROR("All rows of the 2d vector need to have the same number of elements");
447  }
448  }
449 
450  size_ = shape_.size();
451 
452  newArray();
453  auto currentPosition = begin();
454  for (const auto& row : in2dDeque)
455  {
456  stl_algorithms::copy(row.begin(), row.end(), currentPosition);
457  currentPosition += shape_.cols;
458  }
459  }
460 
461  //============================================================================
462  // Method Description:
467  explicit NdArray(const std::list<dtype>& inList) :
468  shape_(1, static_cast<uint32>(inList.size())),
469  size_(shape_.size())
470  {
471  newArray();
472  if (size_ > 0)
473  {
474  stl_algorithms::copy(inList.begin(), inList.end(), begin());
475  }
476  }
477 
478  //============================================================================
479  // Method Description:
485  template<typename Iterator,
486  std::enable_if_t<std::is_same_v<typename std::iterator_traits<Iterator>::value_type, dtype>, int> = 0>
487  NdArray(Iterator inFirst, Iterator inLast) :
488  shape_(1, static_cast<uint32>(std::distance(inFirst, inLast))),
489  size_(shape_.size())
490  {
491  newArray();
492  if (size_ > 0)
493  {
494  stl_algorithms::copy(inFirst, inLast, begin());
495  }
496  }
497 
498  //============================================================================
499  // Method Description:
507  shape_(1, size),
508  size_(size)
509  {
510  newArray();
511  if (inPtr != nullptr && size_ > 0)
512  {
513  stl_algorithms::copy(inPtr, inPtr + size_, begin());
514  }
515  }
516 
517  //============================================================================
518  // Method Description:
526  template<typename UIntType1,
527  typename UIntType2,
528  std::enable_if_t<!std::is_same_v<UIntType1, bool>, int> = 0,
529  std::enable_if_t<!std::is_same_v<UIntType2, bool>, int> = 0>
530  NdArray(const_pointer inPtr, UIntType1 numRows, UIntType2 numCols) :
531  shape_(numRows, numCols),
532  size_(shape_.size())
533  {
534  newArray();
535  if (inPtr != nullptr && size_ > 0)
536  {
537  stl_algorithms::copy(inPtr, inPtr + size_, begin());
538  }
539  }
540 
541  //============================================================================
542  // Method Description:
551  template<typename BoolType, std::enable_if_t<std::is_same_v<BoolType, bool>, int> = 0>
552  NdArray(pointer inPtr, size_type size, BoolType takeOwnership) noexcept :
553  shape_(1, size),
554  size_(size),
555  array_(inPtr),
556  ownsPtr_(takeOwnership)
557  {
558  }
559 
560  //============================================================================
561  // Method Description:
571  template<typename BoolType, std::enable_if_t<std::is_same_v<BoolType, bool>, int> = 0>
572  NdArray(pointer inPtr, size_type numRows, size_type numCols, BoolType takeOwnership) noexcept :
573  shape_(numRows, numCols),
574  size_(numRows * numCols),
575  array_(inPtr),
576  ownsPtr_(takeOwnership)
577  {
578  }
579 
580  //============================================================================
581  // Method Description:
586  NdArray(const self_type& inOtherArray) :
587  shape_(inOtherArray.shape_),
588  size_(inOtherArray.size_),
589  endianess_(inOtherArray.endianess_)
590  {
591  newArray();
592  if (size_ > 0)
593  {
594  stl_algorithms::copy(inOtherArray.cbegin(), inOtherArray.cend(), begin());
595  }
596  }
597 
598  //============================================================================
599  // Method Description:
604  NdArray(self_type&& inOtherArray) noexcept :
605  shape_(inOtherArray.shape_),
606  size_(inOtherArray.size_),
607  endianess_(inOtherArray.endianess_),
608  array_(inOtherArray.array_),
609  ownsPtr_(inOtherArray.ownsPtr_)
610  {
611  inOtherArray.shape_.rows = inOtherArray.shape_.cols = 0;
612  inOtherArray.size_ = 0;
613  inOtherArray.ownsPtr_ = false;
614  inOtherArray.array_ = nullptr;
615  }
616 
617  //============================================================================
618  // Method Description:
621  ~NdArray() noexcept
622  {
623  deleteArray();
624  }
625 
626  //============================================================================
627  // Method Description:
631  explicit operator bool() const noexcept
632  {
633  return isempty();
634  }
635 
636  //============================================================================
637  // Method Description:
644  {
645  if (&rhs != this)
646  {
647  if (rhs.size_ > 0)
648  {
649  newArray(rhs.shape_);
650  endianess_ = rhs.endianess_;
651 
652  stl_algorithms::copy(rhs.cbegin(), rhs.cend(), begin());
653  }
654  }
655 
656  return *this;
657  }
658 
659  //============================================================================
660  // Method Description:
667  self_type& operator=(value_type inValue) noexcept
668  {
669  if (array_ != nullptr)
670  {
671  stl_algorithms::fill(begin(), end(), inValue);
672  }
673 
674  return *this;
675  }
676 
677  //============================================================================
678  // Method Description:
684  self_type& operator=(self_type&& rhs) noexcept
685  {
686  if (&rhs != this)
687  {
688  deleteArray();
689  shape_ = rhs.shape_;
690  size_ = rhs.size_;
691  endianess_ = rhs.endianess_;
692  array_ = rhs.array_;
693  ownsPtr_ = rhs.ownsPtr_;
694 
695  rhs.shape_.rows = rhs.shape_.cols = rhs.size_ = 0;
696  rhs.array_ = nullptr;
697  rhs.ownsPtr_ = false;
698  }
699 
700  return *this;
701  }
702 
703  //============================================================================
704  // Method Description:
710  reference operator[](index_type inIndex) noexcept
711  {
712  return const_cast<reference>(const_cast<const self_type*>(this)->operator[](inIndex));
713  }
714 
715  //============================================================================
716  // Method Description:
722  [[nodiscard]] const_reference operator[](index_type inIndex) const noexcept
723  {
724  if (inIndex < 0)
725  {
726  inIndex += size_;
727  }
728 
729  return array_[inIndex];
730  }
731 
732  //============================================================================
733  // Method Description:
740  reference operator()(index_type inRowIndex, index_type inColIndex) noexcept
741  {
742  return const_cast<reference>(const_cast<const self_type*>(this)->operator()(inRowIndex, inColIndex));
743  }
744 
745  //============================================================================
746  // Method Description:
753  [[nodiscard]] const_reference operator()(index_type inRowIndex, index_type inColIndex) const noexcept
754  {
755  if (inRowIndex < 0)
756  {
757  inRowIndex += shape_.rows;
758  }
759 
760  if (inColIndex < 0)
761  {
762  inColIndex += shape_.cols;
763  }
764 
765  return array_[inRowIndex * shape_.cols + inColIndex];
766  }
767 
768  //============================================================================
769  // Method Description:
776  [[nodiscard]] self_type operator[](Slice inSlice) const
777  {
778  return operator[](toIndices(inSlice, Axis::NONE));
779  }
780 
781  //============================================================================
782  // Method Description:
788  [[nodiscard]] self_type operator[](const NdArray<bool>& inMask) const
789  {
790  return operator[](inMask.flatnonzero());
791  }
792 
793  //============================================================================
794  // Method Description:
801  template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
802  [[nodiscard]] self_type operator[](const Indices& inIndices) const
803  {
804  auto outArray = self_type(1, static_cast<size_type>(inIndices.size()));
805  size_type i = 0;
806  for (auto& index : inIndices)
807  {
808  outArray[i++] = operator[](static_cast<index_type>(index));
809  }
810 
811  return outArray;
812  }
813 
814  //============================================================================
815  // Method Description:
823  [[nodiscard]] self_type operator()(Slice inRowSlice, Slice inColSlice) const
824  {
825  return operator()(toIndices(inRowSlice, Axis::ROW), toIndices(inColSlice, Axis::COL));
826  }
827 
828  //============================================================================
829  // Method Description:
837  [[nodiscard]] self_type operator()(Slice inRowSlice, index_type inColIndex) const
838  {
839  const NdArray<index_type> colIndices = { inColIndex };
840  return operator()(toIndices(inRowSlice, Axis::ROW), colIndices);
841  }
842 
843  //============================================================================
844  // Method Description:
852  [[nodiscard]] self_type operator()(index_type inRowIndex, Slice inColSlice) const
853  {
854  const NdArray<index_type> rowIndices = { inRowIndex };
855  return operator()(rowIndices, toIndices(inColSlice, Axis::COL));
856  }
857 
858  //============================================================================
859  // Method Description:
867  template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
868  [[nodiscard]] self_type operator()(const Indices& rowIndices, index_type colIndex) const
869  {
870  const NdArray<index_type> colIndices = { colIndex };
871  return operator()(rowIndices, colIndices);
872  }
873 
874  //============================================================================
875  // Method Description:
883  template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
884  [[nodiscard]] self_type operator()(const Indices& rowIndices, Slice colSlice) const
885  {
886  return operator()(rowIndices, toIndices(colSlice, Axis::COL));
887  }
888 
889  //============================================================================
890  // Method Description:
898  template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
899  [[nodiscard]] self_type operator()(index_type rowIndex, const Indices& colIndices) const
900  {
901  const NdArray<index_type> rowIndices = { rowIndex };
902  return operator()(rowIndices, colIndices);
903  }
904 
905  //============================================================================
906  // Method Description:
914  template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
915  [[nodiscard]] self_type operator()(Slice rowSlice, const Indices& colIndices) const
916  {
917  return operator()(toIndices(rowSlice, Axis::ROW), colIndices);
918  }
919 
920  //============================================================================
921  // Method Description:
929  template<typename RowIndices,
930  typename ColIndices,
933  [[nodiscard]] self_type operator()(const RowIndices& rowIndices, const ColIndices& colIndices) const
934  {
935  self_type returnArray(rowIndices.size(), colIndices.size());
936 
937  size_type rowCounter = 0;
938  for (auto rowIter = rowIndices.begin(); rowIter != rowIndices.end(); ++rowIter)
939  {
940  size_type colCounter = 0;
941  for (auto colIter = colIndices.begin(); colIter != colIndices.end(); ++colIter)
942  {
943  returnArray(rowCounter, colCounter++) = operator()(*rowIter, *colIter);
944  }
945 
946  ++rowCounter;
947  }
948 
949  return returnArray;
950  }
951 
952  //============================================================================
953  // Method Description:
961  [[nodiscard]] Slice cSlice(index_type inStartIdx = 0, size_type inStepSize = 1) const
962  {
963  return Slice(inStartIdx, shape_.cols, inStepSize); // NOLINT(modernize-return-braced-init-list)
964  }
965 
966  //============================================================================
967  // Method Description:
975  [[nodiscard]] Slice rSlice(index_type inStartIdx = 0, size_type inStepSize = 1) const
976  {
977  return Slice(inStartIdx, shape_.rows, inStepSize); // NOLINT(modernize-return-braced-init-list)
978  }
979 
980  //============================================================================
981  // Method Description:
988  {
989  return const_cast<reference>(const_cast<const self_type*>(this)->at(inIndex));
990  }
991 
992  //============================================================================
993  // Method Description:
999  [[nodiscard]] const_reference at(index_type inIndex) const
1000  {
1001  // this doesn't allow for calling the first element as -size_...
1002  // but why would you really want to do that anyway?
1003  if (std::abs(inIndex) > static_cast<int64>(size_ - 1))
1004  {
1005  std::string errStr = "Input index " + utils::num2str(inIndex);
1006  errStr += " is out of bounds for array of size " + utils::num2str(size_) + ".";
1008  }
1009 
1010  return operator[](inIndex); // cppcheck-suppress returnTempReference
1011  }
1012 
1013  //============================================================================
1014  // Method Description:
1021  reference at(index_type inRowIndex, index_type inColIndex)
1022  {
1023  return const_cast<reference>(const_cast<const self_type*>(this)->at(inRowIndex, inColIndex));
1024  }
1025 
1026  //============================================================================
1027  // Method Description:
1034  [[nodiscard]] const_reference at(index_type inRowIndex, index_type inColIndex) const
1035  {
1036  // this doesn't allow for calling the first element as -size_...
1037  // but why would you really want to do that anyway?
1038  if (std::abs(inRowIndex) > static_cast<index_type>(shape_.rows - 1))
1039  {
1040  std::string errStr = "Row index " + utils::num2str(inRowIndex);
1041  errStr += " is out of bounds for array of size " + utils::num2str(shape_.rows) + ".";
1043  }
1044 
1045  // this doesn't allow for calling the first element as -size_...
1046  // but why would you really want to do that anyway?
1047  if (std::abs(inColIndex) > static_cast<index_type>(shape_.cols - 1))
1048  {
1049  std::string errStr = "Column index " + utils::num2str(inColIndex);
1050  errStr += " is out of bounds for array of size " + utils::num2str(shape_.cols) + ".";
1052  }
1053 
1054  return operator()(inRowIndex, inColIndex); // cppcheck-suppress returnTempReference
1055  }
1056 
1057  //============================================================================
1058  // Method Description:
1064  [[nodiscard]] self_type at(const Slice& inSlice) const
1065  {
1066  return at(toIndices(inSlice, Axis::NONE));
1067  }
1068 
1069  //============================================================================
1070  // Method Description:
1076  [[nodiscard]] self_type at(const NdArray<bool>& inMask) const
1077  {
1078  if (inMask.shape() != shape_)
1079  {
1080  THROW_INVALID_ARGUMENT_ERROR("Input mask must have the same dimensions as array.");
1081  }
1082 
1083  return operator[](inMask);
1084  }
1085 
1086  //============================================================================
1087  // Method Description:
1093  template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
1094  [[nodiscard]] self_type at(const Indices& inIndices) const
1095  {
1096  stl_algorithms::for_each(inIndices.begin(),
1097  inIndices.end(),
1098  [this](auto index)
1099  {
1100  auto indexSigned = static_cast<index_type>(index);
1101  if (indexSigned < 0)
1102  {
1103  indexSigned += size_;
1104  }
1105 
1106  if (indexSigned < 0 || indexSigned > static_cast<index_type>(size_ - 1))
1107  {
1108  THROW_INVALID_ARGUMENT_ERROR("Index exceeds matrix dimensions");
1109  }
1110  });
1111 
1112  return operator[](inIndices);
1113  }
1114 
1115  //============================================================================
1116  // Method Description:
1123  [[nodiscard]] self_type at(const Slice& inRowSlice, const Slice& inColSlice) const
1124  {
1125  return at(toIndices(inRowSlice, Axis::ROW), toIndices(inColSlice, Axis::COL));
1126  }
1127 
1128  //============================================================================
1129  // Method Description:
1136  [[nodiscard]] self_type at(const Slice& inRowSlice, index_type inColIndex) const
1137  {
1138  const NdArray<index_type> colIndices = { inColIndex };
1139  return at(toIndices(inRowSlice, Axis::ROW), colIndices);
1140  }
1141 
1142  //============================================================================
1143  // Method Description:
1150  [[nodiscard]] self_type at(index_type inRowIndex, const Slice& inColSlice) const
1151  {
1152  const NdArray<index_type> rowIndices = { inRowIndex };
1153  return at(rowIndices, toIndices(inColSlice, Axis::COL));
1154  }
1155 
1156  //============================================================================
1157  // Method Description:
1164  template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
1165  [[nodiscard]] self_type at(const Indices& rowIndices, index_type colIndex) const
1166  {
1167  const NdArray<index_type> colIndices = { colIndex };
1168  return at(rowIndices, colIndices);
1169  }
1170 
1171  //============================================================================
1172  // Method Description:
1179  template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
1180  [[nodiscard]] self_type at(const Indices& rowIndices, Slice colSlice) const
1181  {
1182  return at(rowIndices, toIndices(colSlice, Axis::COL));
1183  }
1184 
1185  //============================================================================
1186  // Method Description:
1193  template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
1194  [[nodiscard]] self_type at(index_type rowIndex, const Indices& colIndices) const
1195  {
1196  const NdArray<index_type> rowIndices = { rowIndex };
1197  return at(rowIndices, colIndices);
1198  }
1199 
1200  //============================================================================
1201  // Method Description:
1208  template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
1209  [[nodiscard]] self_type at(Slice rowSlice, const Indices& colIndices) const
1210  {
1211  return at(toIndices(rowSlice, Axis::ROW), colIndices);
1212  }
1213 
1214  //============================================================================
1215  // Method Description:
1222  template<typename RowIndices,
1223  typename ColIndices,
1226  [[nodiscard]] self_type at(const RowIndices& rowIndices, const ColIndices& colIndices) const
1227  {
1228  stl_algorithms::for_each(rowIndices.begin(),
1229  rowIndices.end(),
1230  [this](auto row)
1231  {
1232  auto rowSigned = static_cast<index_type>(row);
1233  if (rowSigned < 0)
1234  {
1235  rowSigned += shape_.rows;
1236  }
1237 
1238  if (rowSigned < 0 || rowSigned > static_cast<index_type>(shape_.rows - 1))
1239  {
1240  THROW_INVALID_ARGUMENT_ERROR("Row index exceeds matrix dimensions");
1241  }
1242  });
1243 
1244  stl_algorithms::for_each(colIndices.begin(),
1245  colIndices.end(),
1246  [this](auto col)
1247  {
1248  auto colSigned = static_cast<index_type>(col);
1249  if (colSigned < 0)
1250  {
1251  colSigned += shape_.cols;
1252  }
1253 
1254  if (colSigned < 0 || colSigned > static_cast<index_type>(shape_.cols - 1))
1255  {
1256  THROW_INVALID_ARGUMENT_ERROR("Column index exceeds matrix dimensions");
1257  }
1258  });
1259 
1260  return operator()(rowIndices, colIndices);
1261  }
1262 
1263  //============================================================================
1264  // Method Description:
1268  [[nodiscard]] iterator begin() noexcept
1269  {
1270  return iterator(array_);
1271  }
1272 
1273  //============================================================================
1274  // Method Description:
1280  [[nodiscard]] iterator begin(size_type inRow)
1281  {
1282  if (inRow >= shape_.rows)
1283  {
1284  THROW_INVALID_ARGUMENT_ERROR("input row is greater than the number of rows in the array.");
1285  }
1286 
1287  return begin() += (inRow * shape_.cols);
1288  }
1289 
1290  //============================================================================
1291  // Method Description:
1295  [[nodiscard]] const_iterator begin() const noexcept
1296  {
1297  return cbegin();
1298  }
1299 
1300  //============================================================================
1301  // Method Description:
1307  [[nodiscard]] const_iterator begin(size_type inRow) const
1308  {
1309  return cbegin(inRow);
1310  }
1311 
1312  //============================================================================
1313  // Method Description:
1318  [[nodiscard]] const_iterator cbegin() const noexcept
1319  {
1320  return const_iterator(array_);
1321  }
1322 
1323  //============================================================================
1324  // Method Description:
1330  [[nodiscard]] const_iterator cbegin(size_type inRow) const
1331  {
1332  if (inRow >= shape_.rows)
1333  {
1334  THROW_INVALID_ARGUMENT_ERROR("input row is greater than the number of rows in the array.");
1335  }
1336 
1337  return cbegin() += (inRow * shape_.cols);
1338  }
1339 
1340  //============================================================================
1341  // Method Description:
1345  [[nodiscard]] column_iterator colbegin() noexcept
1346  {
1347  return column_iterator(array_, shape_.rows, shape_.cols);
1348  }
1349 
1350  //============================================================================
1351  // Method Description:
1357  [[nodiscard]] column_iterator colbegin(size_type inCol)
1358  {
1359  if (inCol >= shape_.cols)
1360  {
1361  THROW_INVALID_ARGUMENT_ERROR("input col is greater than the number of cols in the array.");
1362  }
1363 
1364  return colbegin() += (inCol * shape_.rows);
1365  }
1366 
1367  //============================================================================
1368  // Method Description:
1372  [[nodiscard]] const_column_iterator colbegin() const noexcept
1373  {
1374  return ccolbegin();
1375  }
1376 
1377  //============================================================================
1378  // Method Description:
1384  [[nodiscard]] const_column_iterator colbegin(size_type inCol) const
1385  {
1386  return ccolbegin(inCol);
1387  }
1388 
1389  //============================================================================
1390  // Method Description:
1395  [[nodiscard]] const_column_iterator ccolbegin() const noexcept
1396  {
1397  return const_column_iterator(array_, shape_.rows, shape_.cols);
1398  }
1399 
1400  //============================================================================
1401  // Method Description:
1407  [[nodiscard]] const_column_iterator ccolbegin(size_type inCol) const
1408  {
1409  if (inCol >= shape_.cols)
1410  {
1411  THROW_INVALID_ARGUMENT_ERROR("input col is greater than the number of cols in the array.");
1412  }
1413 
1414  return ccolbegin() += (inCol * shape_.rows);
1415  }
1416 
1417  //============================================================================
1418  // Method Description:
1422  [[nodiscard]] reverse_iterator rbegin() noexcept
1423  {
1424  return reverse_iterator(end());
1425  }
1426 
1427  //============================================================================
1428  // Method Description:
1434  [[nodiscard]] reverse_iterator rbegin(size_type inRow)
1435  {
1436  if (inRow >= shape_.rows)
1437  {
1438  THROW_INVALID_ARGUMENT_ERROR("input row is greater than the number of rows in the array.");
1439  }
1440 
1441  return rbegin() += (shape_.rows - inRow - 1) * shape_.cols;
1442  }
1443 
1444  //============================================================================
1445  // Method Description:
1449  [[nodiscard]] const_reverse_iterator rbegin() const noexcept
1450  {
1451  return crbegin();
1452  }
1453 
1454  //============================================================================
1455  // Method Description:
1461  [[nodiscard]] const_reverse_iterator rbegin(size_type inRow) const
1462  {
1463  return crbegin(inRow);
1464  }
1465 
1466  //============================================================================
1467  // Method Description:
1472  [[nodiscard]] const_reverse_iterator crbegin() const noexcept
1473  {
1474  return const_reverse_iterator(cend());
1475  }
1476 
1477  //============================================================================
1478  // Method Description:
1484  [[nodiscard]] const_reverse_iterator crbegin(size_type inRow) const
1485  {
1486  if (inRow >= shape_.rows)
1487  {
1488  THROW_INVALID_ARGUMENT_ERROR("input row is greater than the number of rows in the array.");
1489  }
1490 
1491  return crbegin() += (shape_.rows - inRow - 1) * shape_.cols;
1492  }
1493 
1494  //============================================================================
1495  // Method Description:
1499  [[nodiscard]] reverse_column_iterator rcolbegin() noexcept
1500  {
1501  return reverse_column_iterator(colend());
1502  }
1503 
1504  //============================================================================
1505  // Method Description:
1512  {
1513  if (inCol >= shape_.cols)
1514  {
1515  THROW_INVALID_ARGUMENT_ERROR("input col is greater than the number of cols in the array.");
1516  }
1517 
1518  return rcolbegin() += (shape_.cols - inCol - 1) * shape_.rows;
1519  }
1520 
1521  //============================================================================
1522  // Method Description:
1526  [[nodiscard]] const_reverse_column_iterator rcolbegin() const noexcept
1527  {
1528  return crcolbegin();
1529  }
1530 
1531  //============================================================================
1532  // Method Description:
1539  {
1540  return crcolbegin(inCol);
1541  }
1542 
1543  //============================================================================
1544  // Method Description:
1549  [[nodiscard]] const_reverse_column_iterator crcolbegin() const noexcept
1550  {
1551  return const_reverse_column_iterator(ccolend());
1552  }
1553 
1554  //============================================================================
1555  // Method Description:
1562  {
1563  if (inCol >= shape_.cols)
1564  {
1565  THROW_INVALID_ARGUMENT_ERROR("input col is greater than the number of cols in the array.");
1566  }
1567 
1568  return crcolbegin() += (shape_.cols - inCol - 1) * shape_.rows;
1569  }
1570 
1571  //============================================================================
1572  // Method Description:
1576  [[nodiscard]] iterator end() noexcept
1577  {
1578  return begin() += size_;
1579  }
1580 
1581  //============================================================================
1582  // Method Description:
1588  [[nodiscard]] iterator end(size_type inRow)
1589  {
1590  if (inRow >= shape_.rows)
1591  {
1592  THROW_INVALID_ARGUMENT_ERROR("input row is greater than the number of rows in the array.");
1593  }
1594 
1595  return begin(inRow) += shape_.cols;
1596  }
1597 
1598  //============================================================================
1599  // Method Description:
1603  [[nodiscard]] const_iterator end() const noexcept
1604  {
1605  return cend();
1606  }
1607 
1608  //============================================================================
1609  // Method Description:
1615  [[nodiscard]] const_iterator end(size_type inRow) const
1616  {
1617  return cend(inRow);
1618  }
1619 
1620  //============================================================================
1621  // Method Description:
1626  [[nodiscard]] const_iterator cend() const noexcept
1627  {
1628  return cbegin() += size_;
1629  }
1630 
1631  //============================================================================
1632  // Method Description:
1638  [[nodiscard]] const_iterator cend(size_type inRow) const
1639  {
1640  if (inRow >= shape_.rows)
1641  {
1642  THROW_INVALID_ARGUMENT_ERROR("input row is greater than the number of rows in the array.");
1643  }
1644 
1645  return cbegin(inRow) += shape_.cols;
1646  }
1647 
1648  //============================================================================
1649  // Method Description:
1653  [[nodiscard]] reverse_iterator rend() noexcept
1654  {
1655  return rbegin() += size_;
1656  }
1657 
1658  //============================================================================
1659  // Method Description:
1665  [[nodiscard]] reverse_iterator rend(size_type inRow)
1666  {
1667  if (inRow >= shape_.rows)
1668  {
1669  THROW_INVALID_ARGUMENT_ERROR("input row is greater than the number of rows in the array.");
1670  }
1671 
1672  return rbegin(inRow) += shape_.cols;
1673  }
1674 
1675  //============================================================================
1676  // Method Description:
1680  [[nodiscard]] const_reverse_iterator rend() const noexcept
1681  {
1682  return crend();
1683  }
1684 
1685  //============================================================================
1686  // Method Description:
1692  [[nodiscard]] const_reverse_iterator rend(size_type inRow) const
1693  {
1694  return crend(inRow);
1695  }
1696 
1697  //============================================================================
1698  // Method Description:
1703  [[nodiscard]] const_reverse_iterator crend() const noexcept
1704  {
1705  return crbegin() += size_;
1706  }
1707 
1708  //============================================================================
1709  // Method Description:
1715  [[nodiscard]] const_reverse_iterator crend(size_type inRow) const
1716  {
1717  if (inRow >= shape_.rows)
1718  {
1719  THROW_INVALID_ARGUMENT_ERROR("input row is greater than the number of rows in the array.");
1720  }
1721 
1722  return crbegin(inRow) += shape_.cols;
1723  }
1724 
1725  //============================================================================
1726  // Method Description:
1730  [[nodiscard]] column_iterator colend() noexcept
1731  {
1732  return colbegin() += size_;
1733  }
1734 
1735  //============================================================================
1736  // Method Description:
1742  [[nodiscard]] column_iterator colend(size_type inCol)
1743  {
1744  if (inCol >= shape_.cols)
1745  {
1746  THROW_INVALID_ARGUMENT_ERROR("input col is greater than the number of cols in the array.");
1747  }
1748 
1749  return colbegin(inCol) += shape_.rows;
1750  }
1751 
1752  //============================================================================
1753  // Method Description:
1757  [[nodiscard]] const_column_iterator colend() const noexcept
1758  {
1759  return ccolend();
1760  }
1761 
1762  //============================================================================
1763  // Method Description:
1769  [[nodiscard]] const_column_iterator colend(size_type inCol) const
1770  {
1771  return ccolend(inCol);
1772  }
1773 
1774  //============================================================================
1775  // Method Description:
1780  [[nodiscard]] const_column_iterator ccolend() const noexcept
1781  {
1782  return ccolbegin() += size_;
1783  }
1784 
1785  //============================================================================
1786  // Method Description:
1792  [[nodiscard]] const_column_iterator ccolend(size_type inCol) const
1793  {
1794  if (inCol >= shape_.cols)
1795  {
1796  THROW_INVALID_ARGUMENT_ERROR("input col is greater than the number of cols in the array.");
1797  }
1798 
1799  return ccolbegin(inCol) += shape_.rows;
1800  }
1801 
1802  //============================================================================
1803  // Method Description:
1807  [[nodiscard]] reverse_column_iterator rcolend() noexcept
1808  {
1809  return rcolbegin() += size_;
1810  }
1811 
1812  //============================================================================
1813  // Method Description:
1820  {
1821  if (inCol >= shape_.cols)
1822  {
1823  THROW_INVALID_ARGUMENT_ERROR("input col is greater than the number of cols in the array.");
1824  }
1825 
1826  return rcolbegin(inCol) += shape_.rows;
1827  }
1828 
1829  //============================================================================
1830  // Method Description:
1834  [[nodiscard]] const_reverse_column_iterator rcolend() const noexcept
1835  {
1836  return crcolend();
1837  }
1838 
1839  //============================================================================
1840  // Method Description:
1847  {
1848  return crcolend(inCol);
1849  }
1850 
1851  //============================================================================
1852  // Method Description:
1857  [[nodiscard]] const_reverse_column_iterator crcolend() const noexcept
1858  {
1859  return crcolbegin() += size_;
1860  }
1861 
1862  //============================================================================
1863  // Method Description:
1870  {
1871  if (inCol >= shape_.cols)
1872  {
1873  THROW_INVALID_ARGUMENT_ERROR("input col is greater than the number of cols in the array.");
1874  }
1875 
1876  return crcolbegin(inCol) += shape_.rows;
1877  }
1878 
1879  //============================================================================
1880  // Method Description:
1888  [[nodiscard]] NdArray<bool> all(Axis inAxis = Axis::NONE) const
1889  {
1891 
1892  const auto function = [](dtype i) -> bool { return !utils::essentiallyEqual(i, dtype{ 0 }); };
1893 
1894  switch (inAxis)
1895  {
1896  case Axis::NONE:
1897  {
1898  NdArray<bool> returnArray = { stl_algorithms::all_of(cbegin(), cend(), function) };
1899  return returnArray;
1900  }
1901  case Axis::COL:
1902  {
1903  NdArray<bool> returnArray(1, shape_.rows);
1904  for (uint32 row = 0; row < shape_.rows; ++row)
1905  {
1906  returnArray(0, row) = stl_algorithms::all_of(cbegin(row), cend(row), function);
1907  }
1908 
1909  return returnArray;
1910  }
1911  case Axis::ROW:
1912  {
1913  return transpose().all(Axis::COL);
1914  }
1915  default:
1916  {
1917  THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
1918  return {}; // get rid of compiler warning
1919  }
1920  }
1921  }
1922 
1923  //============================================================================
1924  // Method Description:
1932  [[nodiscard]] NdArray<bool> any(Axis inAxis = Axis::NONE) const
1933  {
1935 
1936  const auto function = [](dtype i) -> bool { return !utils::essentiallyEqual(i, dtype{ 0 }); };
1937 
1938  switch (inAxis)
1939  {
1940  case Axis::NONE:
1941  {
1942  NdArray<bool> returnArray = { stl_algorithms::any_of(cbegin(), cend(), function) };
1943  return returnArray;
1944  }
1945  case Axis::COL:
1946  {
1947  NdArray<bool> returnArray(1, shape_.rows);
1948  for (uint32 row = 0; row < shape_.rows; ++row)
1949  {
1950  returnArray(0, row) = stl_algorithms::any_of(cbegin(row), cend(row), function);
1951  }
1952 
1953  return returnArray;
1954  }
1955  case Axis::ROW:
1956  {
1957  return transpose().any(Axis::COL);
1958  }
1959  default:
1960  {
1961  THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
1962  return {}; // get rid of compiler warning
1963  }
1964  }
1965  }
1966 
1967  //============================================================================
1968  // Method Description:
1977  [[nodiscard]] NdArray<size_type> argmax(Axis inAxis = Axis::NONE) const
1978  {
1980 
1981  const auto comparitor = [](dtype lhs, dtype rhs) noexcept -> bool { return lhs < rhs; };
1982 
1983  switch (inAxis)
1984  {
1985  case Axis::NONE:
1986  {
1987  NdArray<size_type> returnArray = { static_cast<size_type>(
1988  stl_algorithms::max_element(cbegin(), cend(), comparitor) - cbegin()) };
1989  return returnArray;
1990  }
1991  case Axis::COL:
1992  {
1993  NdArray<size_type> returnArray(1, shape_.rows);
1994  for (size_type row = 0; row < shape_.rows; ++row)
1995  {
1996  returnArray(0, row) = static_cast<size_type>(
1997  stl_algorithms::max_element(cbegin(row), cend(row), comparitor) - cbegin(row));
1998  }
1999 
2000  return returnArray;
2001  }
2002  case Axis::ROW:
2003  {
2004  return transpose().argmax(Axis::COL);
2005  }
2006  default:
2007  {
2008  THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
2009  return {}; // get rid of compiler warning
2010  }
2011  }
2012  }
2013 
2014  //============================================================================
2015  // Method Description:
2024  [[nodiscard]] NdArray<size_type> argmin(Axis inAxis = Axis::NONE) const
2025  {
2027 
2028  const auto comparitor = [](dtype lhs, dtype rhs) noexcept -> bool { return lhs < rhs; };
2029 
2030  switch (inAxis)
2031  {
2032  case Axis::NONE:
2033  {
2034  NdArray<size_type> returnArray = { static_cast<size_type>(
2035  stl_algorithms::min_element(cbegin(), cend(), comparitor) - cbegin()) };
2036  return returnArray;
2037  }
2038  case Axis::COL:
2039  {
2040  NdArray<size_type> returnArray(1, shape_.rows);
2041  for (size_type row = 0; row < shape_.rows; ++row)
2042  {
2043  returnArray(0, row) = static_cast<size_type>(
2044  stl_algorithms::min_element(cbegin(row), cend(row), comparitor) - cbegin(row));
2045  }
2046 
2047  return returnArray;
2048  }
2049  case Axis::ROW:
2050  {
2051  return transpose().argmin(Axis::COL);
2052  }
2053  default:
2054  {
2055  THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
2056  return {}; // get rid of compiler warning
2057  }
2058  }
2059  }
2060 
2061  //============================================================================
2062  // Method Description:
2070  [[nodiscard]] NdArray<size_type> argsort(Axis inAxis = Axis::NONE) const
2071  {
2073 
2074  switch (inAxis)
2075  {
2076  case Axis::NONE:
2077  {
2078  std::vector<size_type> idx(size_);
2079  std::iota(idx.begin(), idx.end(), 0);
2080 
2081  const auto function = [this](size_type i1, size_type i2) noexcept -> bool
2082  { return (*this)[i1] < (*this)[i2]; };
2083 
2084  stl_algorithms::stable_sort(idx.begin(), idx.end(), function);
2085  return NdArray<size_type>(idx); // NOLINT(modernize-return-braced-init-list)
2086  }
2087  case Axis::COL:
2088  {
2089  NdArray<size_type> returnArray(shape_);
2090  std::vector<size_type> idx(shape_.cols);
2091 
2092  for (index_type row = 0; row < static_cast<index_type>(shape_.rows); ++row)
2093  {
2094  std::iota(idx.begin(), idx.end(), 0);
2095 
2096  const auto function = [this, row](size_type i1, size_type i2) noexcept -> bool
2097  { return operator()(row, i1) < operator()(row, i2); };
2098 
2099  stl_algorithms::stable_sort(idx.begin(), idx.end(), function);
2100 
2101  for (index_type col = 0; col < static_cast<index_type>(shape_.cols); ++col)
2102  {
2103  returnArray(row, col) = idx[static_cast<size_type>(col)];
2104  }
2105  }
2106  return returnArray;
2107  }
2108  case Axis::ROW:
2109  {
2110  return transpose().argsort(Axis::COL).transpose();
2111  }
2112  default:
2113  {
2114  THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
2115  return {}; // get rid of compiler warning
2116  }
2117  }
2118  }
2119 
2120  //============================================================================
2121  // Method Description:
2129  template<typename dtypeOut,
2130  typename dtype_ = dtype,
2131  std::enable_if_t<std::is_same_v<dtype_, dtype>, int> = 0,
2132  std::enable_if_t<std::is_arithmetic_v<dtype_>, int> = 0,
2133  std::enable_if_t<std::is_arithmetic_v<dtypeOut>, int> = 0>
2134  [[nodiscard]] NdArray<dtypeOut> astype() const
2135  {
2136  if constexpr (std::is_same_v<dtypeOut, dtype>)
2137  {
2138  return *this;
2139  }
2140  else
2141  {
2142  NdArray<dtypeOut> outArray(shape_);
2143  stl_algorithms::transform(cbegin(),
2144  cend(),
2145  outArray.begin(),
2146  [](dtype value) -> dtypeOut { return static_cast<dtypeOut>(value); });
2147 
2148  return outArray;
2149  }
2150  }
2151 
2152  //============================================================================
2153  // Method Description:
2161  template<typename dtypeOut,
2162  typename dtype_ = dtype,
2163  std::enable_if_t<std::is_same_v<dtype_, dtype>, int> = 0,
2164  std::enable_if_t<std::is_arithmetic_v<dtype_>, int> = 0,
2165  std::enable_if_t<is_complex_v<dtypeOut>, int> = 0>
2166  [[nodiscard]] NdArray<dtypeOut> astype() const
2167  {
2168  NdArray<dtypeOut> outArray(shape_);
2169 
2170  const auto function = [](const_reference value) -> dtypeOut
2171  { return std::complex<typename dtypeOut::value_type>(value); };
2172 
2173  stl_algorithms::transform(cbegin(), cend(), outArray.begin(), function);
2174 
2175  return outArray;
2176  }
2177 
2178  //============================================================================
2179  // Method Description:
2187  template<typename dtypeOut,
2188  typename dtype_ = dtype,
2189  std::enable_if_t<std::is_same_v<dtype_, dtype>, int> = 0,
2190  std::enable_if_t<is_complex_v<dtype_>, int> = 0,
2191  std::enable_if_t<is_complex_v<dtypeOut>, int> = 0>
2192  [[nodiscard]] NdArray<dtypeOut> astype() const
2193  {
2194  if constexpr (std::is_same_v<dtypeOut, dtype>)
2195  {
2196  return *this;
2197  }
2198  else
2199  {
2200  const auto function = [](const_reference value) noexcept -> dtypeOut
2201  { return complex_cast<typename dtypeOut::value_type>(value); };
2202 
2203  NdArray<dtypeOut> outArray(shape_);
2204  stl_algorithms::transform(cbegin(), cend(), outArray.begin(), function);
2205  return outArray;
2206  }
2207  }
2208 
2209  //============================================================================
2210  // Method Description:
2218  template<typename dtypeOut,
2219  typename dtype_ = dtype,
2220  std::enable_if_t<std::is_same_v<dtype_, dtype>, int> = 0,
2221  std::enable_if_t<is_complex_v<dtype_>, int> = 0,
2222  std::enable_if_t<std::is_arithmetic_v<dtypeOut>, int> = 0>
2223  [[nodiscard]] NdArray<dtypeOut> astype() const
2224  {
2225  NdArray<dtypeOut> outArray(shape_);
2226 
2227  const auto function = [](const_reference value) -> dtypeOut { return static_cast<dtypeOut>(value.real()); };
2228 
2229  stl_algorithms::transform(cbegin(), cend(), outArray.begin(), function);
2230 
2231  return outArray;
2232  }
2233 
2234  //============================================================================
2235  // Method Description:
2240  [[nodiscard]] const_reference back() const noexcept
2241  {
2242  return *(cend() - 1);
2243  }
2244 
2245  //============================================================================
2246  // Method Description:
2251  reference back() noexcept
2252  {
2253  return *(end() - 1);
2254  }
2255 
2256  //============================================================================
2257  // Method Description:
2262  [[nodiscard]] const_reference back(size_type row) const
2263  {
2264  return *(cend(row) - 1);
2265  }
2266 
2267  //============================================================================
2268  // Method Description:
2274  {
2275  return *(end(row) - 1);
2276  }
2277 
2278  //============================================================================
2279  // Method Description:
2286  self_type& byteswap() noexcept
2287  {
2288  STATIC_ASSERT_INTEGER(dtype);
2289 
2290  stl_algorithms::for_each(begin(),
2291  end(),
2292  [](dtype& value) noexcept -> void { value = endian::byteSwap(value); });
2293 
2294  switch (endianess_)
2295  {
2296  case Endian::NATIVE:
2297  {
2298  endianess_ = endian::isLittleEndian() ? Endian::BIG : Endian::LITTLE;
2299  break;
2300  }
2301  case Endian::LITTLE:
2302  {
2303  endianess_ = Endian::BIG;
2304  break;
2305  }
2306  case Endian::BIG:
2307  {
2308  endianess_ = Endian::LITTLE;
2309  break;
2310  }
2311  }
2312 
2313  return *this;
2314  }
2315 
2316  //============================================================================
2317  // Method Description:
2326  [[nodiscard]] self_type clip(value_type inMin, value_type inMax) const
2327  {
2329 
2330  self_type outArray(shape_);
2331  stl_algorithms::transform(cbegin(),
2332  cend(),
2333  outArray.begin(),
2334  [inMin, inMax](dtype value) noexcept -> dtype
2335  {
2336 #ifdef __cpp_lib_clamp
2337  const auto comparitor = [](dtype lhs, dtype rhs) noexcept -> bool
2338  { return lhs < rhs; };
2339 
2340  return std::clamp(value, inMin, inMax, comparitor);
2341 #else
2342  if (value < inMin)
2343  {
2344  return inMin;
2345  }
2346  else if (value > inMax)
2347  {
2348  return inMax;
2349  }
2350 
2351  return value;
2352 #endif
2353  });
2354 
2355  return outArray;
2356  }
2357 
2358  //============================================================================
2359  // Method Description:
2365  [[nodiscard]] self_type column(size_type inColumn) const
2366  {
2367  return operator()(rSlice(), inColumn);
2368  }
2369 
2370  //============================================================================
2371  // Method Description:
2377  [[nodiscard]] self_type columns(const NdArray<size_type>& inCols) const
2378  {
2379  auto returnArray = self_type(shape_.rows, inCols.size());
2380  const auto rSlice = returnArray.rSlice();
2381 
2382  for (size_type i = 0; i < inCols.size(); ++i)
2383  {
2384  returnArray.put(rSlice, i, column(inCols[i]));
2385  }
2386 
2387  return returnArray;
2388  }
2389 
2390  //============================================================================
2391  // Method Description:
2398  [[nodiscard]] NdArray<bool> contains(value_type inValue, Axis inAxis = Axis::NONE) const
2399  {
2401 
2402  switch (inAxis)
2403  {
2404  case Axis::NONE:
2405  {
2406  NdArray<bool> returnArray = { stl_algorithms::find(cbegin(), cend(), inValue) != cend() };
2407  return returnArray;
2408  }
2409  case Axis::COL:
2410  {
2411  NdArray<bool> returnArray(1, shape_.rows);
2412  for (size_type row = 0; row < shape_.rows; ++row)
2413  {
2414  returnArray(0, row) = stl_algorithms::find(cbegin(row), cend(row), inValue) != cend(row);
2415  }
2416 
2417  return returnArray;
2418  }
2419  case Axis::ROW:
2420  {
2421  return transpose().contains(inValue, Axis::COL);
2422  }
2423  default:
2424  {
2425  THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
2426  return {}; // get rid of compiler warning
2427  }
2428  }
2429  }
2430 
2431  //============================================================================
2432  // Method Description:
2439  [[nodiscard]] self_type copy() const
2440  {
2441  return self_type(*this);
2442  }
2443 
2444  //============================================================================
2445  // Method Description:
2453  [[nodiscard]] self_type cumprod(Axis inAxis = Axis::NONE) const
2454  {
2456 
2457  switch (inAxis)
2458  {
2459  case Axis::NONE:
2460  {
2461  self_type returnArray(1, size_);
2462  returnArray[0] = front();
2463  for (size_type i = 1; i < size_; ++i)
2464  {
2465  returnArray[i] = returnArray[i - 1] * array_[i];
2466  }
2467 
2468  return returnArray;
2469  }
2470  case Axis::COL:
2471  {
2472  self_type returnArray(shape_);
2473  for (uint32 row = 0; row < shape_.rows; ++row)
2474  {
2475  returnArray(row, 0) = operator()(row, 0);
2476  for (uint32 col = 1; col < shape_.cols; ++col)
2477  {
2478  returnArray(row, col) = returnArray(row, col - 1) * operator()(row, col);
2479  }
2480  }
2481 
2482  return returnArray;
2483  }
2484  case Axis::ROW:
2485  {
2486  return transpose().cumprod(Axis::COL).transpose();
2487  }
2488  default:
2489  {
2490  THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
2491  return {}; // get rid of compiler warning
2492  }
2493  }
2494  }
2495 
2496  //============================================================================
2497  // Method Description:
2505  [[nodiscard]] self_type cumsum(Axis inAxis = Axis::NONE) const
2506  {
2508 
2509  switch (inAxis)
2510  {
2511  case Axis::NONE:
2512  {
2513  self_type returnArray(1, size_);
2514  returnArray[0] = front();
2515  for (size_type i = 1; i < size_; ++i)
2516  {
2517  returnArray[i] = returnArray[i - 1] + array_[i];
2518  }
2519 
2520  return returnArray;
2521  }
2522  case Axis::COL:
2523  {
2524  self_type returnArray(shape_);
2525  for (uint32 row = 0; row < shape_.rows; ++row)
2526  {
2527  returnArray(row, 0) = operator()(row, 0);
2528  for (uint32 col = 1; col < shape_.cols; ++col)
2529  {
2530  returnArray(row, col) = returnArray(row, col - 1) + operator()(row, col);
2531  }
2532  }
2533 
2534  return returnArray;
2535  }
2536  case Axis::ROW:
2537  {
2538  return transpose().cumsum(Axis::COL).transpose();
2539  }
2540  default:
2541  {
2542  THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
2543  return {}; // get rid of compiler warning
2544  }
2545  }
2546  }
2547 
2548  //============================================================================
2549  // Method Description:
2553  [[nodiscard]] pointer data() noexcept
2554  {
2555  return array_;
2556  }
2557 
2558  //============================================================================
2559  // Method Description:
2563  [[nodiscard]] const_pointer data() const noexcept
2564  {
2565  return array_;
2566  }
2567 
2568  //============================================================================
2569  // Method Description:
2575  [[nodiscard]] pointer dataRelease() noexcept
2576  {
2577  ownsPtr_ = false;
2578  return data();
2579  }
2580 
2581  //============================================================================
2582  // Method Description:
2592  [[nodiscard]] self_type diagonal(index_type inOffset = 0, Axis inAxis = Axis::ROW) const
2593  {
2594  switch (inAxis)
2595  {
2596  case Axis::COL:
2597  {
2598  std::vector<dtype> diagnolValues;
2599  size_type col = 0;
2600  for (index_type row = inOffset; row < static_cast<index_type>(shape_.rows); ++row)
2601  {
2602  if (row < 0)
2603  {
2604  ++col;
2605  continue;
2606  }
2607  if (col >= shape_.cols)
2608  {
2609  break;
2610  }
2611 
2612  diagnolValues.push_back(operator()(static_cast<size_type>(row), col));
2613  ++col;
2614  }
2615 
2616  return self_type(diagnolValues);
2617  }
2618  case Axis::ROW:
2619  {
2620  return transpose().diagonal(inOffset, Axis::COL);
2621  }
2622  default:
2623  {
2624  THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
2625  return {}; // get rid of compiler warning
2626  }
2627  }
2628  }
2629 
2630  //============================================================================
2631  // Method Description:
2637  [[nodiscard]] size_type dimSize(Axis inAxis) const noexcept
2638  {
2639  switch (inAxis)
2640  {
2641  case Axis::NONE:
2642  {
2643  return size();
2644  }
2645  case Axis::ROW:
2646  {
2647  return numRows();
2648  }
2649  case Axis::COL:
2650  {
2651  return numCols();
2652  }
2653  default:
2654  {
2655  return {}; // get rid of compiler warning
2656  }
2657  }
2658  }
2659 
2660  //============================================================================
2661  // Method Description:
2672  [[nodiscard]] self_type dot(const self_type& inOtherArray) const
2673  {
2675 
2676  if (shape_ == inOtherArray.shape_ && (shape_.rows == 1 || shape_.cols == 1))
2677  {
2678  dtype dotProduct = std::inner_product(cbegin(), cend(), inOtherArray.cbegin(), dtype{ 0 });
2679  self_type returnArray = { dotProduct };
2680  return returnArray;
2681  }
2682  if (shape_.cols == inOtherArray.shape_.rows)
2683  {
2684  // 2D array, use matrix multiplication
2685  self_type returnArray(shape_.rows, inOtherArray.shape_.cols);
2686  auto otherArrayT = inOtherArray.transpose();
2687 
2688  for (uint32 i = 0; i < shape_.rows; ++i)
2689  {
2690  for (uint32 j = 0; j < otherArrayT.shape_.rows; ++j)
2691  {
2692  returnArray(i, j) =
2693  std::inner_product(otherArrayT.cbegin(j), otherArrayT.cend(j), cbegin(i), dtype{ 0 });
2694  }
2695  }
2696 
2697  return returnArray;
2698  }
2699 
2700  std::string errStr = "shapes of [" + utils::num2str(shape_.rows) + ", " + utils::num2str(shape_.cols) + "]";
2701  errStr += " and [" + utils::num2str(inOtherArray.shape_.rows) + ", " +
2702  utils::num2str(inOtherArray.shape_.cols) + "]";
2703  errStr += " are not consistent.";
2705 
2706  return self_type(); // get rid of compiler warning
2707  }
2708 
2709  //============================================================================
2710  // Method Description:
2718  void dump(const std::string& inFilename) const
2719  {
2720  std::filesystem::path f(inFilename);
2721  if (!f.has_extension())
2722  {
2723  f.replace_extension("bin");
2724  }
2725 
2726  std::ofstream ofile(f.c_str(), std::ios::binary);
2727  if (!ofile.good())
2728  {
2729  THROW_RUNTIME_ERROR("Unable to open the input file:\n\t" + inFilename);
2730  }
2731 
2732  if (array_ != nullptr)
2733  {
2734  ofile.write(reinterpret_cast<const char*>(array_), size_ * sizeof(dtype));
2735  }
2736  ofile.close();
2737  }
2738 
2739  //============================================================================
2740  // Method Description:
2745  [[nodiscard]] Endian endianess() const noexcept
2746  {
2747  STATIC_ASSERT_ARITHMETIC(dtype);
2748 
2749  return endianess_;
2750  }
2751 
2752  //============================================================================
2753  // Method Description:
2761  self_type& fill(value_type inFillValue) noexcept
2762  {
2763  stl_algorithms::fill(begin(), end(), inFillValue);
2764  return *this;
2765  }
2766 
2767  //============================================================================
2768  // Method Description:
2774  [[nodiscard]] NdArray<size_type> flatnonzero() const
2775  {
2777 
2778  std::vector<size_type> indices;
2779  size_type idx = 0;
2780  for (auto value : *this)
2781  {
2782  if (!utils::essentiallyEqual(value, dtype{ 0 }))
2783  {
2784  indices.push_back(idx);
2785  }
2786  ++idx;
2787  }
2788 
2789  return NdArray<size_type>(indices); // NOLINT(modernize-return-braced-init-list)
2790  }
2791 
2792  //============================================================================
2793  // Method Description:
2800  [[nodiscard]] self_type flatten() const
2801  {
2802  self_type outArray(1, size_);
2803  stl_algorithms::copy(cbegin(), cend(), outArray.begin());
2804  return outArray;
2805  }
2806 
2807  //============================================================================
2808  // Method Description:
2813  [[nodiscard]] const_reference front() const noexcept
2814  {
2815  return *cbegin();
2816  }
2817 
2818  //============================================================================
2819  // Method Description:
2824  reference front() noexcept
2825  {
2826  return *begin();
2827  }
2828 
2829  //============================================================================
2830  // Method Description:
2835  [[nodiscard]] const_reference front(size_type row) const
2836  {
2837  return *cbegin(row);
2838  }
2839 
2840  //============================================================================
2841  // Method Description:
2847  {
2848  return *begin(row);
2849  }
2850 
2851  //============================================================================
2852  // Method Description:
2858  [[nodiscard]] self_type getByIndices(const NdArray<size_type>& inIndices) const
2859  {
2860  return operator[](inIndices);
2861  }
2862 
2863  //============================================================================
2864  // Method Description:
2872  [[nodiscard]] self_type getByMask(const NdArray<bool>& inMask) const
2873  {
2874  return operator[](inMask);
2875  }
2876 
2877  //============================================================================
2878  // Method Description:
2884  // NOLINTNEXTLINE(modernize-use-nodiscard)
2885  bool isempty() const noexcept
2886  {
2887  return size_ == 0;
2888  }
2889 
2890  //============================================================================
2891  // Method Description:
2897  // NOLINTNEXTLINE(modernize-use-nodiscard)
2898  bool isflat() const noexcept
2899  {
2900  return !isscalar() && (shape_.rows == 1 || shape_.cols == 1);
2901  }
2902 
2903  //============================================================================
2904  // Method Description:
2908  // NOLINTNEXTLINE(modernize-use-nodiscard)
2909  bool isscalar() const noexcept
2910  {
2911  return size_ == 1;
2912  }
2913 
2914  //============================================================================
2915  // Method Description:
2921  [[nodiscard]] NdArray<bool> issorted(Axis inAxis = Axis::NONE) const
2922  {
2924 
2925  const auto comparitor = [](dtype lhs, dtype rhs) noexcept -> bool { return lhs < rhs; };
2926 
2927  switch (inAxis)
2928  {
2929  case Axis::NONE:
2930  {
2931  return { stl_algorithms::is_sorted(cbegin(), cend(), comparitor) };
2932  }
2933  case Axis::COL:
2934  {
2935  NdArray<bool> returnArray(1, shape_.rows);
2936  for (uint32 row = 0; row < shape_.rows; ++row)
2937  {
2938  returnArray(0, row) = stl_algorithms::is_sorted(cbegin(row), cend(row), comparitor);
2939  }
2940 
2941  return returnArray;
2942  }
2943  case Axis::ROW:
2944  {
2945  return transpose().issorted(Axis::COL);
2946  }
2947  default:
2948  {
2949  THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
2950  return {}; // get rid of compiler warning
2951  }
2952  }
2953  }
2954 
2955  //============================================================================
2956  // Method Description:
2961  // NOLINTNEXTLINE(modernize-use-nodiscard)
2962  bool issquare() const noexcept
2963  {
2964  return shape_.issquare();
2965  }
2966 
2967  //============================================================================
2968  // Method Description:
2975  [[nodiscard]] value_type item() const
2976  {
2977  if (!isscalar())
2978  {
2979  THROW_INVALID_ARGUMENT_ERROR("Can only convert an array of size 1 to a C++ scalar");
2980  }
2981 
2982  return front();
2983  }
2984 
2985  //============================================================================
2986  // Method Description:
2994  [[nodiscard]] self_type max(Axis inAxis = Axis::NONE) const
2995  {
2997 
2998  const auto comparitor = [](dtype lhs, dtype rhs) noexcept -> bool { return lhs < rhs; };
2999 
3000  switch (inAxis)
3001  {
3002  case Axis::NONE:
3003  {
3004  self_type returnArray = { *stl_algorithms::max_element(cbegin(), cend(), comparitor) };
3005  return returnArray;
3006  }
3007  case Axis::COL:
3008  {
3009  self_type returnArray(1, shape_.rows);
3010  for (uint32 row = 0; row < shape_.rows; ++row)
3011  {
3012  returnArray(0, row) = *stl_algorithms::max_element(cbegin(row), cend(row), comparitor);
3013  }
3014 
3015  return returnArray;
3016  }
3017  case Axis::ROW:
3018  {
3019  return transpose().max(Axis::COL);
3020  }
3021  default:
3022  {
3023  THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
3024  return {}; // get rid of compiler warning
3025  }
3026  }
3027  }
3028 
3029  //============================================================================
3030  // Method Description:
3038  [[nodiscard]] self_type min(Axis inAxis = Axis::NONE) const
3039  {
3041 
3042  const auto comparitor = [](dtype lhs, dtype rhs) noexcept -> bool { return lhs < rhs; };
3043 
3044  switch (inAxis)
3045  {
3046  case Axis::NONE:
3047  {
3048  self_type returnArray = { *stl_algorithms::min_element(cbegin(), cend(), comparitor) };
3049  return returnArray;
3050  }
3051  case Axis::COL:
3052  {
3053  self_type returnArray(1, shape_.rows);
3054  for (uint32 row = 0; row < shape_.rows; ++row)
3055  {
3056  returnArray(0, row) = *stl_algorithms::min_element(cbegin(row), cend(row), comparitor);
3057  }
3058 
3059  return returnArray;
3060  }
3061  case Axis::ROW:
3062  {
3063  return transpose().min(Axis::COL);
3064  }
3065  default:
3066  {
3067  THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
3068  return {}; // get rid of compiler warning
3069  }
3070  }
3071  }
3072 
3073  //============================================================================
3074  // Method Description:
3084  [[nodiscard]] self_type median(Axis inAxis = Axis::NONE) const
3085  {
3087 
3088  const auto comparitor = [](dtype lhs, dtype rhs) noexcept -> bool { return lhs < rhs; };
3089 
3090  if (size_ == 0)
3091  {
3092  THROW_RUNTIME_ERROR("Median is undefined for an array of size = 0.");
3093  }
3094 
3095  switch (inAxis)
3096  {
3097  case Axis::NONE:
3098  {
3099  self_type copyArray(*this);
3100 
3101  const size_type middleIdx = size_ / 2; // integer division
3102  stl_algorithms::nth_element(copyArray.begin(),
3103  copyArray.begin() + middleIdx,
3104  copyArray.end(),
3105  comparitor);
3106 
3107  dtype medianValue = copyArray.array_[middleIdx];
3108  if (size_ % 2 == 0)
3109  {
3110  const size_type lhsIndex = middleIdx - 1;
3111  stl_algorithms::nth_element(copyArray.begin(),
3112  copyArray.begin() + lhsIndex,
3113  copyArray.end(),
3114  comparitor);
3115  medianValue =
3116  (medianValue + copyArray.array_[lhsIndex]) / dtype{ 2 }; // potentially integer division, ok
3117  }
3118 
3119  return { medianValue };
3120  }
3121  case Axis::COL:
3122  {
3123  self_type copyArray(*this);
3124  self_type returnArray(1, shape_.rows);
3125 
3126  const bool isEven = shape_.cols % 2 == 0;
3127  for (uint32 row = 0; row < shape_.rows; ++row)
3128  {
3129  const uint32 middleIdx = shape_.cols / 2; // integer division
3130  stl_algorithms::nth_element(copyArray.begin(row),
3131  copyArray.begin(row) + middleIdx,
3132  copyArray.end(row),
3133  comparitor);
3134 
3135  dtype medianValue = copyArray(row, middleIdx);
3136  if (isEven)
3137  {
3138  const size_type lhsIndex = middleIdx - 1;
3139  stl_algorithms::nth_element(copyArray.begin(row),
3140  copyArray.begin(row) + lhsIndex,
3141  copyArray.end(row),
3142  comparitor);
3143  medianValue = (medianValue + copyArray(row, lhsIndex)) /
3144  dtype{ 2 }; // potentially integer division, ok
3145  }
3146 
3147  returnArray(0, row) = medianValue;
3148  }
3149 
3150  return returnArray;
3151  }
3152  case Axis::ROW:
3153  {
3154  return transpose().median(Axis::COL);
3155  }
3156  default:
3157  {
3158  THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
3159  return {}; // get rid of compiler warning
3160  }
3161  }
3162  }
3163 
3164  //============================================================================
3165  // Method Description:
3169  self_type& nans() noexcept
3170 
3171  {
3172  STATIC_ASSERT_FLOAT(dtype);
3173 
3175  return *this;
3176  }
3177 
3178  //============================================================================
3179  // Method Description:
3186  [[nodiscard]] uint64 nbytes() const noexcept
3187  {
3188  return static_cast<uint64>(sizeof(dtype) * size_);
3189  }
3190 
3191  //============================================================================
3192  // Method Description:
3201  [[nodiscard]] self_type newbyteorder(Endian inEndianess) const
3202  {
3203  STATIC_ASSERT_INTEGER(dtype);
3204 
3205  const bool nativeIsLittle = endian::isLittleEndian();
3206 
3207  switch (endianess_)
3208  {
3209  case Endian::NATIVE:
3210  {
3211  switch (inEndianess)
3212  {
3213  case Endian::NATIVE:
3214  {
3215  return NdArray(*this);
3216  }
3217  case Endian::BIG:
3218  {
3219  if (nativeIsLittle)
3220  {
3221  self_type outArray(shape_);
3222 
3223  stl_algorithms::transform(cbegin(), end(), outArray.begin(), endian::byteSwap<dtype>);
3224 
3225  outArray.endianess_ = Endian::BIG;
3226  return outArray;
3227  }
3228  else
3229  {
3230  auto outArray = NdArray(*this);
3231  outArray.endianess_ = Endian::BIG;
3232  return outArray;
3233  }
3234  }
3235  case Endian::LITTLE:
3236  {
3237  if (nativeIsLittle)
3238  {
3239  auto outArray = NdArray(*this);
3240  outArray.endianess_ = Endian::LITTLE;
3241  return outArray;
3242  }
3243  else
3244  {
3245  self_type outArray(shape_);
3246 
3247  stl_algorithms::transform(cbegin(), end(), outArray.begin(), endian::byteSwap<dtype>);
3248 
3249  outArray.endianess_ = Endian::LITTLE;
3250  return outArray;
3251  }
3252  }
3253  default:
3254  {
3255  THROW_INVALID_ARGUMENT_ERROR("Unimplemented endian type.");
3256  return {}; // get rid of compiler warning
3257  }
3258  }
3259  break;
3260  }
3261  case Endian::BIG:
3262  {
3263  switch (inEndianess)
3264  {
3265  case Endian::NATIVE:
3266  {
3267  if (nativeIsLittle)
3268  {
3269  self_type outArray(shape_);
3270 
3271  stl_algorithms::transform(cbegin(), end(), outArray.begin(), endian::byteSwap<dtype>);
3272 
3273  outArray.endianess_ = Endian::NATIVE;
3274  return outArray;
3275  }
3276  else
3277  {
3278  auto outArray = NdArray(*this);
3279  outArray.endianess_ = Endian::NATIVE;
3280  return outArray;
3281  }
3282  }
3283  case Endian::BIG:
3284  {
3285  return NdArray(*this);
3286  }
3287  case Endian::LITTLE:
3288  {
3289  self_type outArray(shape_);
3290 
3291  stl_algorithms::transform(cbegin(), end(), outArray.begin(), endian::byteSwap<dtype>);
3292 
3293  outArray.endianess_ = Endian::LITTLE;
3294  return outArray;
3295  }
3296  default:
3297  {
3298  THROW_INVALID_ARGUMENT_ERROR("Unimplemented endian type.");
3299  return {}; // get rid of compiler warning
3300  }
3301  }
3302  break;
3303  }
3304  case Endian::LITTLE:
3305  {
3306  switch (inEndianess)
3307  {
3308  case Endian::NATIVE:
3309  {
3310  if (nativeIsLittle)
3311  {
3312  auto outArray = NdArray(*this);
3313  outArray.endianess_ = Endian::NATIVE;
3314  return outArray;
3315  }
3316  else
3317  {
3318  self_type outArray(shape_);
3319 
3320  stl_algorithms::transform(cbegin(), end(), outArray.begin(), endian::byteSwap<dtype>);
3321 
3322  outArray.endianess_ = Endian::NATIVE;
3323  return outArray;
3324  }
3325  }
3326  case Endian::BIG:
3327  {
3328  self_type outArray(shape_);
3329 
3330  stl_algorithms::transform(cbegin(), end(), outArray.begin(), endian::byteSwap<dtype>);
3331 
3332  outArray.endianess_ = Endian::BIG;
3333  return outArray;
3334  }
3335  case Endian::LITTLE:
3336  {
3337  return NdArray(*this);
3338  }
3339  default:
3340  {
3341  THROW_INVALID_ARGUMENT_ERROR("Unimplemented endian type.");
3342  return {}; // get rid of compiler warning
3343  }
3344  }
3345  break;
3346  }
3347  default:
3348  {
3349  THROW_INVALID_ARGUMENT_ERROR("Unimplemented endian type.");
3350  return {}; // get rid of compiler warning
3351  }
3352  }
3353  }
3354 
3355  //============================================================================
3356  // Method Description:
3364  [[nodiscard]] NdArray<bool> none(Axis inAxis = Axis::NONE) const
3365  {
3367 
3368  const auto function = [](dtype i) -> bool { return !utils::essentiallyEqual(i, dtype{ 0 }); };
3369 
3370  switch (inAxis)
3371  {
3372  case Axis::NONE:
3373  {
3374  NdArray<bool> returnArray = { stl_algorithms::none_of(cbegin(), cend(), function) };
3375  return returnArray;
3376  }
3377  case Axis::COL:
3378  {
3379  NdArray<bool> returnArray(1, shape_.rows);
3380  for (uint32 row = 0; row < shape_.rows; ++row)
3381  {
3382  returnArray(0, row) = stl_algorithms::none_of(cbegin(row), cend(row), function);
3383  }
3384 
3385  return returnArray;
3386  }
3387  case Axis::ROW:
3388  {
3389  return transpose().none(Axis::COL);
3390  }
3391  default:
3392  {
3393  THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
3394  return {}; // get rid of compiler warning
3395  }
3396  }
3397  }
3398 
3399  //============================================================================
3400  // Method Description:
3409  [[nodiscard]] std::pair<NdArray<size_type>, NdArray<size_type>> nonzero() const;
3410 
3411  //============================================================================
3412  // Method Description:
3418  [[nodiscard]] size_type numCols() const noexcept
3419  {
3420  return shape_.cols;
3421  }
3422 
3423  //============================================================================
3424  // Method Description:
3430  [[nodiscard]] size_type numRows() const noexcept
3431  {
3432  return shape_.rows;
3433  }
3434 
3435  //============================================================================
3436  // Method Description:
3440  self_type& ones() noexcept
3441  {
3443 
3444  fill(dtype{ 1 });
3445  return *this;
3446  }
3447 
3448  //============================================================================
3449  // Method Description:
3454  bool ownsInternalData() noexcept
3455  {
3456  return ownsPtr_;
3457  }
3458 
3459  //============================================================================
3460  // Method Description:
3474  self_type& partition(size_type inKth, Axis inAxis = Axis::NONE)
3475  {
3477 
3478  const auto comparitor = [](dtype lhs, dtype rhs) noexcept -> bool
3479  { return lhs < rhs; }; // cppcheck-suppress returnTempReference
3480 
3481  switch (inAxis)
3482  {
3483  case Axis::NONE:
3484  {
3485  if (inKth >= size_)
3486  {
3487  std::string errStr = "kth(=" + utils::num2str(inKth);
3488  errStr += ") out of bounds (" + utils::num2str(size_) + ")";
3490  }
3491 
3492  stl_algorithms::nth_element(begin(), begin() + inKth, end(), comparitor);
3493  break;
3494  }
3495  case Axis::COL:
3496  {
3497  if (inKth >= shape_.cols)
3498  {
3499  std::string errStr = "kth(=" + utils::num2str(inKth);
3500  errStr += ") out of bounds (" + utils::num2str(shape_.cols) + ")";
3502  }
3503 
3504  for (uint32 row = 0; row < shape_.rows; ++row)
3505  {
3506  stl_algorithms::nth_element(begin(row), begin(row) + inKth, end(row), comparitor);
3507  }
3508  break;
3509  }
3510  case Axis::ROW:
3511  {
3512  if (inKth >= shape_.rows)
3513  {
3514  std::string errStr = "kth(=" + utils::num2str(inKth);
3515  errStr += ") out of bounds (" + utils::num2str(shape_.rows) + ")";
3517  }
3518 
3519  self_type transposedArray = transpose();
3520  for (uint32 row = 0; row < transposedArray.shape_.rows; ++row)
3521  {
3522  stl_algorithms::nth_element(transposedArray.begin(row),
3523  transposedArray.begin(row) + inKth,
3524  transposedArray.end(row),
3525  comparitor);
3526  }
3527  *this = transposedArray.transpose();
3528  break;
3529  }
3530  }
3531 
3532  return *this;
3533  }
3534 
3535  //============================================================================
3536  // Method Description:
3540  void print() const
3541  {
3543 
3544  std::cout << *this;
3545  }
3546 
3547  //============================================================================
3548  // Method Description:
3556  [[nodiscard]] self_type prod(Axis inAxis = Axis::NONE) const
3557  {
3559 
3560  switch (inAxis)
3561  {
3562  case Axis::NONE:
3563  {
3564  dtype product = std::accumulate(cbegin(), cend(), dtype{ 1 }, std::multiplies<dtype>());
3565  self_type returnArray = { product };
3566  return returnArray;
3567  }
3568  case Axis::COL:
3569  {
3570  self_type returnArray(1, shape_.rows);
3571  for (uint32 row = 0; row < shape_.rows; ++row)
3572  {
3573  returnArray(0, row) =
3574  std::accumulate(cbegin(row), cend(row), dtype{ 1 }, std::multiplies<dtype>());
3575  }
3576 
3577  return returnArray;
3578  }
3579  case Axis::ROW:
3580  {
3581  return transpose().prod(Axis::COL);
3582  }
3583  default:
3584  {
3585  THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
3586  return {}; // get rid of compiler warning
3587  }
3588  }
3589  }
3590 
3591  //============================================================================
3592  // Method Description:
3600  [[nodiscard]] self_type ptp(Axis inAxis = Axis::NONE) const
3601  {
3603 
3604  const auto comparitor = [](dtype lhs, dtype rhs) noexcept -> bool { return lhs < rhs; };
3605 
3606  switch (inAxis)
3607  {
3608  case Axis::NONE:
3609  {
3610  const auto result = stl_algorithms::minmax_element(cbegin(), cend(), comparitor);
3611  self_type returnArray = { *result.second - *result.first };
3612  return returnArray;
3613  }
3614  case Axis::COL:
3615  {
3616  self_type returnArray(1, shape_.rows);
3617  for (uint32 row = 0; row < shape_.rows; ++row)
3618  {
3619  const auto result = stl_algorithms::minmax_element(cbegin(row), cend(row), comparitor);
3620  returnArray(0, row) = *result.second - *result.first;
3621  }
3622 
3623  return returnArray;
3624  }
3625  case Axis::ROW:
3626  {
3627  return transpose().ptp(Axis::COL);
3628  }
3629  default:
3630  {
3631  THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
3632  return {}; // get rid of compiler warning
3633  }
3634  }
3635  }
3636 
3637  //============================================================================
3638  // Method Description:
3646  self_type& put(index_type inIndex, const value_type& inValue)
3647  {
3648  at(inIndex) = inValue;
3649 
3650  return *this;
3651  }
3652 
3653  //============================================================================
3654  // Method Description:
3663  self_type& put(index_type inRow, index_type inCol, const value_type& inValue)
3664  {
3665  at(inRow, inCol) = inValue;
3666 
3667  return *this;
3668  }
3669 
3670  //============================================================================
3671  // Method Description:
3680  template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
3681  self_type& put(const Indices& inIndices, const value_type& inValue)
3682  {
3683  for (auto index : inIndices)
3684  {
3685  put(index, inValue);
3686  }
3687 
3688  return *this;
3689  }
3690 
3691  //============================================================================
3692  // Method Description:
3701  template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
3702  self_type& put(const Indices& inIndices, const self_type& inValues)
3703  {
3704  if (inValues.isscalar())
3705  {
3706  return put(inIndices, inValues.item());
3707  }
3708  else if (inIndices.size() != inValues.size())
3709  {
3710  THROW_INVALID_ARGUMENT_ERROR("Input indices do not match values dimensions.");
3711  }
3712 
3713  size_type counter = 0;
3714  for (auto index : inIndices)
3715  {
3716  put(index, inValues[counter++]);
3717  }
3718 
3719  return *this;
3720  }
3721 
3722  //============================================================================
3723  // Method Description:
3732  self_type& put(const Slice& inSlice, const value_type& inValue)
3733  {
3734  return put(toIndices(inSlice, Axis::NONE), inValue);
3735  }
3736 
3737  //============================================================================
3738  // Method Description:
3747  self_type& put(const Slice& inSlice, const self_type& inValues)
3748  {
3749  return put(toIndices(inSlice, Axis::NONE), inValues);
3750  }
3751 
3752  //============================================================================
3753  // Method Description:
3763  template<typename RowIndices,
3764  typename ColIndices,
3767  self_type& put(const RowIndices& inRowIndices, const ColIndices& inColIndices, const value_type& inValue)
3768  {
3769  stl_algorithms::for_each(inRowIndices.begin(),
3770  inRowIndices.end(),
3771  [this, &inColIndices, &inValue](const auto row)
3772  {
3773  stl_algorithms::for_each(inColIndices.begin(),
3774  inColIndices.end(),
3775  [this, row, &inValue](const auto col)
3776  { this->put(row, col, inValue); });
3777  });
3778 
3779  return *this;
3780  }
3781 
3782  //============================================================================
3783  // Method Description:
3793  template<typename RowIndices, type_traits::ndarray_int_concept<RowIndices> = 0>
3794  self_type& put(const RowIndices& inRowIndices, const Slice& inColSlice, const value_type& inValue)
3795  {
3796  return put(inRowIndices, toIndices(inColSlice, Axis::COL), inValue);
3797  }
3798 
3799  //============================================================================
3800  // Method Description:
3810  template<typename ColIndices, type_traits::ndarray_int_concept<ColIndices> = 0>
3811  self_type& put(const Slice& inRowSlice, const ColIndices& inColIndices, const value_type& inValue)
3812  {
3813  return put(toIndices(inRowSlice, Axis::ROW), inColIndices, inValue);
3814  }
3815 
3816  //============================================================================
3817  // Method Description:
3827  self_type& put(const Slice& inRowSlice, const Slice& inColSlice, const value_type& inValue)
3828  {
3829  return put(toIndices(inRowSlice, Axis::ROW), toIndices(inColSlice, Axis::COL), inValue);
3830  }
3831 
3832  //============================================================================
3833  // Method Description:
3843  template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
3844  self_type& put(const Indices& inRowIndices, index_type inColIndex, const value_type& inValue)
3845  {
3846  const NdArray<index_type> colIndices = { inColIndex };
3847  return put(inRowIndices, colIndices, inValue);
3848  }
3849 
3850  //============================================================================
3851  // Method Description:
3861  self_type& put(const Slice& inRowSlice, index_type inColIndex, const value_type& inValue)
3862  {
3863  const NdArray<index_type> colIndices = { inColIndex };
3864  return put(toIndices(inRowSlice, Axis::ROW), colIndices, inValue);
3865  }
3866 
3867  //============================================================================
3868  // Method Description:
3878  template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
3879  self_type& put(index_type inRowIndex, const Indices& inColIndices, const value_type& inValue)
3880  {
3881  const NdArray<index_type> rowIndices = { inRowIndex };
3882  return put(rowIndices, inColIndices, inValue);
3883  }
3884 
3885  //============================================================================
3886  // Method Description:
3896  self_type& put(index_type inRowIndex, const Slice& inColSlice, const value_type& inValue)
3897  {
3898  const NdArray<index_type> rowIndices = { inRowIndex };
3899  return put(rowIndices, toIndices(inColSlice, Axis::COL), inValue);
3900  }
3901 
3902  //============================================================================
3903  // Method Description:
3913  template<typename RowIndices,
3914  typename ColIndices,
3917  self_type& put(const RowIndices& inRowIndices, const ColIndices& inColIndices, const self_type& inValues)
3918  {
3919  std::vector<size_type> indices;
3920  indices.reserve(inRowIndices.size() * inColIndices.size());
3921  std::for_each(inRowIndices.begin(),
3922  inRowIndices.end(),
3923  [this, &inColIndices, &indices](auto row)
3924  {
3925  if constexpr (std::is_signed_v<decltype(row)>)
3926  {
3927  if (row < 0)
3928  {
3929  row += shape_.rows;
3930  }
3931  // still
3932  if (row < 0)
3933  {
3934  THROW_INVALID_ARGUMENT_ERROR("row index exceeds matrix dimensions");
3935  }
3936  }
3937  std::for_each(inColIndices.begin(),
3938  inColIndices.end(),
3939  [this, row, &indices](auto col)
3940  {
3941  if constexpr (std::is_signed_v<decltype(col)>)
3942  {
3943  if (col < 0)
3944  {
3945  col += shape_.cols;
3946  }
3947  // still
3948  if (col < 0)
3949  {
3950  THROW_INVALID_ARGUMENT_ERROR(
3951  "col index exceeds matrix dimensions");
3952  }
3953  }
3954  indices.push_back(row * shape_.cols + col);
3955  });
3956  });
3957 
3958  return put(NdArray<size_type>(indices.data(), indices.size(), false), inValues);
3959  }
3960 
3961  //============================================================================
3962  // Method Description:
3972  template<typename RowIndices, type_traits::ndarray_int_concept<RowIndices> = 0>
3973  self_type& put(const RowIndices& inRowIndices, Slice inColSlice, const self_type& inValues)
3974  {
3975  return put(inRowIndices, toIndices(inColSlice, Axis::COL), inValues);
3976  }
3977 
3978  //============================================================================
3979  // Method Description:
3989  template<typename ColIndices, type_traits::ndarray_int_concept<ColIndices> = 0>
3990  self_type& put(Slice inRowSlice, const ColIndices& inColIndices, const self_type& inValues)
3991  {
3992  return put(toIndices(inRowSlice, Axis::ROW), inColIndices, inValues);
3993  }
3994 
3995  //============================================================================
3996  // Method Description:
4006  self_type& put(Slice inRowSlice, Slice inColSlice, const self_type& inValues)
4007  {
4008  return put(toIndices(inRowSlice, Axis::ROW), toIndices(inColSlice, Axis::COL), inValues);
4009  }
4010 
4011  //============================================================================
4012  // Method Description:
4022  template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
4023  self_type& put(const Indices& inRowIndices, index_type inColIndex, const self_type& inValues)
4024  {
4025  const NdArray<index_type> colIndices = { inColIndex };
4026  return put(inRowIndices, colIndices, inValues);
4027  }
4028 
4029  //============================================================================
4030  // Method Description:
4040  self_type& put(const Slice& inRowSlice, index_type inColIndex, const self_type& inValues)
4041  {
4042  const NdArray<index_type> colIndices = { inColIndex };
4043  return put(toIndices(inRowSlice, Axis::ROW), colIndices, inValues);
4044  }
4045 
4046  //============================================================================
4047  // Method Description:
4057  template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
4058  self_type& put(index_type inRowIndex, const Indices& inColIndices, const self_type& inValues)
4059  {
4060  const NdArray<index_type> rowIndices = { inRowIndex };
4061  return put(rowIndices, inColIndices, inValues);
4062  }
4063 
4064  //============================================================================
4065  // Method Description:
4075  self_type& put(index_type inRowIndex, const Slice& inColSlice, const self_type& inValues)
4076  {
4077  const NdArray<index_type> rowIndices = { inRowIndex };
4078  return put(rowIndices, toIndices(inColSlice, Axis::COL), inValues);
4079  }
4080 
4081  //============================================================================
4082  // Method Description:
4088  self_type& putMask(const NdArray<bool>& inMask, const value_type& inValue)
4089  {
4090  if (inMask.shape() != shape_)
4091  {
4092  THROW_INVALID_ARGUMENT_ERROR("input inMask must be the same shape as the array it is masking.");
4093  }
4094 
4095  return put(inMask.flatnonzero(), inValue);
4096  }
4097 
4098  //============================================================================
4099  // Method Description:
4105  self_type& putMask(const NdArray<bool>& inMask, const self_type& inValues)
4106  {
4107  if (inMask.shape() != shape_)
4108  {
4109  THROW_INVALID_ARGUMENT_ERROR("input inMask must be the same shape as the array it is masking.");
4110  }
4111 
4112  if (inValues.isscalar())
4113  {
4114  put(inMask.flatnonzero(), inValues.item());
4115  }
4116  else
4117  {
4118  put(inMask.flatnonzero(), inValues);
4119  }
4120 
4121  return *this;
4122  }
4123 
4124  //============================================================================
4125  // Method Description:
4133  {
4134  reshape(size_);
4135  return *this;
4136  }
4137 
4138  //============================================================================
4139  // Method Description:
4148  [[nodiscard]] self_type repeat(size_type inNumRows, size_type inNumCols) const
4149  {
4150  self_type returnArray(shape_.rows * inNumRows, shape_.cols * inNumCols);
4151 
4152  for (size_type row = 0; row < inNumRows; ++row)
4153  {
4154  for (size_type col = 0; col < inNumCols; ++col)
4155  {
4156  std::vector<size_type> indices(shape_.size());
4157 
4158  const size_type rowStart = row * shape_.rows;
4159  const size_type colStart = col * shape_.cols;
4160 
4161  const size_type rowEnd = (row + 1) * shape_.rows;
4162  const size_type colEnd = (col + 1) * shape_.cols;
4163 
4164  size_type counter = 0;
4165  for (size_type rowIdx = rowStart; rowIdx < rowEnd; ++rowIdx)
4166  {
4167  for (size_type colIdx = colStart; colIdx < colEnd; ++colIdx)
4168  {
4169  indices[counter++] = rowIdx * returnArray.shape_.cols + colIdx;
4170  }
4171  }
4172 
4173  returnArray.put(NdArray<size_type>(indices), *this);
4174  }
4175  }
4176 
4177  return returnArray;
4178  }
4179 
4180  //============================================================================
4181  // Method Description:
4189  [[nodiscard]] self_type repeat(const Shape& inRepeatShape) const
4190  {
4191  return repeat(inRepeatShape.rows, inRepeatShape.cols);
4192  }
4193 
4194  //============================================================================
4195  // Method Description:
4202  {
4204 
4205  stl_algorithms::replace(begin(), end(), oldValue, newValue);
4206  return *this;
4207  }
4208 
4209  //============================================================================
4210  // Method Description:
4225  {
4226  if (inSize != size_)
4227  {
4228  std::string errStr = "Cannot reshape array of size " + utils::num2str(size_) + " into shape ";
4229  errStr += "[" + utils::num2str(1) + ", " + utils::num2str(inSize) + "]";
4230  THROW_RUNTIME_ERROR(errStr);
4231  }
4232 
4233  shape_.rows = 1;
4234  shape_.cols = inSize;
4235 
4236  return *this;
4237  }
4238 
4239  //============================================================================
4240  // Method Description:
4255  self_type& reshape(index_type inNumRows, index_type inNumCols)
4256  {
4257  if (inNumRows < 0)
4258  {
4259  if (size_ % inNumCols == 0)
4260  {
4261  return reshape(size_ / inNumCols, inNumCols);
4262  }
4263 
4264  std::string errStr = "Cannot reshape array of size " + utils::num2str(size_) + " into a shape ";
4265  errStr += "with " + utils::num2str(inNumCols) + " columns";
4267  }
4268 
4269  if (inNumCols < 0)
4270  {
4271  if (size_ % inNumRows == 0)
4272  {
4273  return reshape(inNumRows, size_ / inNumRows);
4274  }
4275 
4276  std::string errStr = "Cannot reshape array of size " + utils::num2str(size_) + " into a shape ";
4277  errStr += "with " + utils::num2str(inNumRows) + " rows";
4279  }
4280 
4281  if (static_cast<size_type>(inNumRows * inNumCols) != size_)
4282  {
4283  std::string errStr = "Cannot reshape array of size " + utils::num2str(size_) + " into shape ";
4284  errStr += "[" + utils::num2str(inNumRows) + ", " + utils::num2str(inNumCols) + "]";
4286  }
4287 
4288  shape_.rows = static_cast<size_type>(inNumRows);
4289  shape_.cols = static_cast<size_type>(inNumCols);
4290 
4291  return *this;
4292  }
4293 
4294  //============================================================================
4295  // Method Description:
4309  self_type& reshape(const Shape& inShape)
4310  {
4311  return reshape(inShape.rows, inShape.cols);
4312  }
4313 
4314  //============================================================================
4315  // Method Description:
4324  self_type& resizeFast(size_type inNumRows, size_type inNumCols)
4325  {
4326  newArray(Shape(inNumRows, inNumCols));
4327  return *this;
4328  }
4329 
4330  //============================================================================
4331  // Method Description:
4339  self_type& resizeFast(const Shape& inShape)
4340  {
4341  return resizeFast(inShape.rows, inShape.cols);
4342  }
4343 
4344  //============================================================================
4345  // Method Description:
4356  self_type& resizeSlow(size_type inNumRows, size_type inNumCols)
4357  {
4358  std::vector<dtype> oldData(size_);
4359  stl_algorithms::copy(begin(), end(), oldData.begin());
4360 
4361  const Shape inShape(inNumRows, inNumCols);
4362  const Shape oldShape = shape_;
4363 
4364  newArray(inShape);
4365 
4366  for (uint32 row = 0; row < inShape.rows; ++row)
4367  {
4368  for (uint32 col = 0; col < inShape.cols; ++col)
4369  {
4370  if (row >= oldShape.rows || col >= oldShape.cols)
4371  {
4372  operator()(row, col) = dtype{ 0 }; // zero fill
4373  }
4374  else
4375  {
4376  operator()(row, col) = oldData[row * oldShape.cols + col];
4377  }
4378  }
4379  }
4380 
4381  return *this;
4382  }
4383 
4384  //============================================================================
4385  // Method Description:
4395  self_type& resizeSlow(const Shape& inShape)
4396  {
4397  return resizeSlow(inShape.rows, inShape.cols);
4398  }
4399 
4400  //============================================================================
4401  // Method Description:
4410  [[nodiscard]] self_type round(uint8 inNumDecimals = 0) const
4411  {
4412  STATIC_ASSERT_FLOAT(dtype);
4413 
4414  self_type returnArray(shape_);
4415  const double multFactor = utils::power(10., inNumDecimals);
4416  const auto function = [multFactor](dtype value) noexcept -> dtype
4417  { return static_cast<dtype>(std::nearbyint(static_cast<double>(value) * multFactor) / multFactor); };
4418 
4419  stl_algorithms::transform(cbegin(), cend(), returnArray.begin(), function);
4420 
4421  return returnArray;
4422  }
4423 
4424  //============================================================================
4425  // Method Description:
4431  [[nodiscard]] self_type row(size_type inRow) const
4432  {
4433  return self_type(cbegin(inRow), cend(inRow));
4434  }
4435 
4436  //============================================================================
4437  // Method Description:
4443  [[nodiscard]] self_type rows(const NdArray<size_type>& inRows) const
4444  {
4445  auto returnArray = self_type(inRows.size(), shape_.cols);
4446  const auto cSlice = returnArray.cSlice();
4447 
4448  for (size_type i = 0; i < inRows.size(); ++i)
4449  {
4450  returnArray.put(i, cSlice, row(inRows[i]));
4451  }
4452 
4453  return returnArray;
4454  }
4455 
4456  //============================================================================
4457  // Method Description:
4464  [[nodiscard]] const Shape& shape() const noexcept
4465  {
4466  return shape_;
4467  }
4468 
4469  //============================================================================
4470  // Method Description:
4477  [[nodiscard]] size_type size() const noexcept
4478  {
4479  return size_;
4480  }
4481 
4482  //============================================================================
4483  // Method Description:
4491  self_type& sort(Axis inAxis = Axis::NONE)
4492  {
4494 
4495  const auto comparitor = [](dtype lhs, dtype rhs) noexcept -> bool
4496  { return lhs < rhs; }; // cppcheck-suppress returnTempReference
4497 
4498  switch (inAxis)
4499  {
4500  case Axis::NONE:
4501  {
4502  stl_algorithms::sort(begin(), end(), comparitor);
4503  break;
4504  }
4505  case Axis::COL:
4506  {
4507  for (uint32 row = 0; row < shape_.rows; ++row)
4508  {
4509  stl_algorithms::sort(begin(row), end(row), comparitor);
4510  }
4511  break;
4512  }
4513  case Axis::ROW:
4514  {
4515  self_type transposedArray = transpose();
4516  for (uint32 row = 0; row < transposedArray.shape_.rows; ++row)
4517  {
4518  stl_algorithms::sort(transposedArray.begin(row), transposedArray.end(row), comparitor);
4519  }
4520 
4521  *this = transposedArray.transpose();
4522  break;
4523  }
4524  }
4525 
4526  return *this;
4527  }
4528 
4529  //============================================================================
4530  // Method Description:
4535  [[nodiscard]] std::string str() const
4536  {
4538 
4539  std::string out;
4540  out += "[";
4541  for (uint32 row = 0; row < shape_.rows; ++row)
4542  {
4543  out += "[";
4544  for (uint32 col = 0; col < shape_.cols; ++col)
4545  {
4546  out += utils::value2str(operator()(row, col)) + ", ";
4547  }
4548 
4549  if (row == shape_.rows - 1)
4550  {
4551  out += "]";
4552  }
4553  else
4554  {
4555  out += "]\n";
4556  }
4557  }
4558  out += "]\n";
4559  return out;
4560  }
4561 
4562  //============================================================================
4563  // Method Description:
4571  [[nodiscard]] self_type sum(Axis inAxis = Axis::NONE) const
4572  {
4574 
4575  switch (inAxis)
4576  {
4577  case Axis::NONE:
4578  {
4579  self_type returnArray = { std::accumulate(cbegin(), cend(), dtype{ 0 }) };
4580  return returnArray;
4581  }
4582  case Axis::COL:
4583  {
4584  self_type returnArray(1, shape_.rows);
4585  for (uint32 row = 0; row < shape_.rows; ++row)
4586  {
4587  returnArray(0, row) = std::accumulate(cbegin(row), cend(row), dtype{ 0 });
4588  }
4589 
4590  return returnArray;
4591  }
4592  case Axis::ROW:
4593  {
4594  return transpose().sum(Axis::COL);
4595  }
4596  default:
4597  {
4598  THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
4599  return {}; // get rid of compiler warning
4600  }
4601  }
4602  }
4603 
4604  //============================================================================
4605  // Method Description:
4612  [[nodiscard]] self_type swapaxes() const
4613  {
4614  return transpose();
4615  }
4616 
4617  //============================================================================
4618  // Method Description:
4625  self_type& swapCols(index_type colIdx1, index_type colIdx2) noexcept
4626  {
4627  for (index_type row = 0; row < static_cast<index_type>(shape_.rows); ++row)
4628  {
4629  std::swap(operator()(row, colIdx1), operator()(row, colIdx2));
4630  }
4631 
4632  return *this;
4633  }
4634 
4635  //============================================================================
4636  // Method Description:
4643  self_type& swapRows(index_type rowIdx1, index_type rowIdx2) noexcept
4644  {
4645  for (index_type col = 0; col < static_cast<index_type>(shape_.cols); ++col)
4646  {
4647  std::swap(operator()(rowIdx1, col), operator()(rowIdx2, col));
4648  }
4649 
4650  return *this;
4651  }
4652 
4653  //============================================================================
4654  // Method Description:
4664  void tofile(const std::string& inFilename) const
4665  {
4666  dump(inFilename);
4667  }
4668 
4669  //============================================================================
4670  // Method Description:
4681  void tofile(const std::string& inFilename, const char inSep) const
4682  {
4684 
4685  std::filesystem::path f(inFilename);
4686  if (!f.has_extension())
4687  {
4688  f.replace_extension("txt");
4689  }
4690 
4691  std::ofstream ofile(f.c_str());
4692  if (!ofile.good())
4693  {
4694  THROW_RUNTIME_ERROR("Input file could not be opened:\n\t" + inFilename);
4695  }
4696 
4697  size_type counter = 0;
4698  for (auto value : *this)
4699  {
4700  ofile << value;
4701  if (counter++ != size_ - 1)
4702  {
4703  ofile << inSep;
4704  }
4705  }
4706  ofile.close();
4707  }
4708 
4709  //============================================================================
4710  // Method Description:
4718  [[nodiscard]] NdArray<size_type> toIndices(Slice inSlice, Axis inAxis = Axis::NONE) const
4719  {
4720  size_type numElements = 0;
4721  switch (inAxis)
4722  {
4723  case Axis::NONE:
4724  {
4725  numElements = inSlice.numElements(size_);
4726  break;
4727  }
4728  case Axis::ROW:
4729  {
4730  numElements = inSlice.numElements(shape_.rows);
4731  break;
4732  }
4733  case Axis::COL:
4734  {
4735  numElements = inSlice.numElements(shape_.cols);
4736  break;
4737  }
4738  default:
4739  {
4740  // not actually possible, getting rid of compiler warning
4741  THROW_INVALID_ARGUMENT_ERROR("Invalid 'inAxis' option");
4742  }
4743  }
4744 
4745  if (numElements == 0)
4746  {
4747  return {};
4748  }
4749 
4750  NdArray<size_type> indices(1, numElements);
4751  indices[0] = static_cast<size_type>(inSlice.start);
4752  for (size_type i = 1; i < indices.size(); ++i)
4753  {
4754  indices[static_cast<index_type>(i)] = static_cast<size_type>(
4755  indices[static_cast<index_type>(i - size_type{ 1 })] + static_cast<size_type>(inSlice.step));
4756  }
4757 
4758  return indices;
4759  }
4760 
4761  //============================================================================
4762  // Method Description:
4767  [[nodiscard]] std::vector<dtype> toStlVector() const
4768  {
4769  return std::vector<dtype>(cbegin(), cend());
4770  }
4771 
4772  //============================================================================
4773  // Method Description:
4784  [[nodiscard]] value_type trace(size_type inOffset = 0, Axis inAxis = Axis::ROW) const noexcept
4785  {
4787 
4788  size_type rowStart = 0;
4789  size_type colStart = 0;
4790  switch (inAxis)
4791  {
4792  case Axis::ROW:
4793  {
4794  rowStart += inOffset;
4795  break;
4796  }
4797  case Axis::COL:
4798  {
4799  colStart += inOffset;
4800  break;
4801  }
4802  default:
4803  {
4804  // if the user input NONE, override back to ROW
4805  inAxis = Axis::ROW;
4806  break;
4807  }
4808  }
4809 
4810  if (rowStart >= shape_.rows || colStart >= shape_.cols)
4811  {
4812  return dtype{ 0 };
4813  }
4814 
4815  size_type col = colStart;
4816  dtype sum = 0;
4817  for (size_type row = rowStart; row < shape_.rows; ++row)
4818  {
4819  if (col >= shape_.cols)
4820  {
4821  break;
4822  }
4823  sum += operator()(row, col++);
4824  }
4825 
4826  return sum;
4827  }
4828 
4829  //============================================================================
4830  // Method Description:
4837  [[nodiscard]] self_type transpose() const
4838  {
4839  self_type transArray(shape_.cols, shape_.rows);
4840  for (uint32 row = 0; row < shape_.rows; ++row)
4841  {
4842  for (uint32 col = 0; col < shape_.cols; ++col)
4843  {
4844  transArray(col, row) = operator()(row, col);
4845  }
4846  }
4847  return transArray;
4848  }
4849 
4850  //============================================================================
4851  // Method Description:
4855  self_type& zeros() noexcept
4856  {
4858 
4859  fill(dtype{ 0 });
4860  return *this;
4861  }
4862 
4863  private:
4864  //====================================Attributes==============================
4865  allocator_type allocator_{};
4866  Shape shape_{ 0, 0 };
4867  size_type size_{ 0 };
4868  Endian endianess_{ Endian::NATIVE };
4869  pointer array_{ nullptr };
4870  bool ownsPtr_{ false };
4871 
4872  //============================================================================
4873  // Method Description:
4876  void deleteArray() noexcept
4877  {
4878  if (ownsPtr_ && array_ != nullptr)
4879  {
4880  allocator_.deallocate(array_, size_);
4881  }
4882 
4883  array_ = nullptr;
4884  shape_.rows = shape_.cols = 0;
4885  size_ = 0;
4886  ownsPtr_ = false;
4887  endianess_ = Endian::NATIVE;
4888  }
4889 
4890  //============================================================================
4891  // Method Description:
4894  void newArray()
4895  {
4896  if (size_ > 0)
4897  {
4898  array_ = allocator_.allocate(size_);
4899  ownsPtr_ = true;
4900  }
4901  }
4902 
4903  //============================================================================
4904  // Method Description:
4909  void newArray(const Shape& inShape)
4910  {
4911  deleteArray();
4912 
4913  shape_ = inShape;
4914  size_ = inShape.size();
4915  newArray();
4916  }
4917  };
4918 
4919  // NOTE: this needs to be defined outside of the class to get rid of a compiler
4920  // error in Visual Studio
4921  template<typename dtype, class Alloc_>
4922  [[nodiscard]] std::pair<NdArray<uint32>, NdArray<uint32>> NdArray<dtype, Alloc_>::nonzero() const
4923  {
4925 
4926  std::vector<size_type> rowIndices;
4927  std::vector<size_type> colIndices;
4928 
4929  for (uint32 row = 0; row < shape_.rows; ++row)
4930  {
4931  for (uint32 col = 0; col < shape_.cols; ++col)
4932  {
4933  if (!utils::essentiallyEqual(operator()(row, col), dtype{ 0 }))
4934  {
4935  rowIndices.push_back(row);
4936  colIndices.push_back(col);
4937  }
4938  }
4939  }
4940 
4941  return std::make_pair(NdArray<size_type>(rowIndices), NdArray<size_type>(colIndices));
4942  }
4943 } // namespace nc
#define THROW_RUNTIME_ERROR(msg)
Definition: Error.hpp:40
#define THROW_INVALID_ARGUMENT_ERROR(msg)
Definition: Error.hpp:37
#define STATIC_ASSERT_FLOAT(dtype)
Definition: StaticAsserts.hpp:50
#define STATIC_ASSERT_ARITHMETIC_OR_COMPLEX(dtype)
Definition: StaticAsserts.hpp:56
#define STATIC_ASSERT_INTEGER(dtype)
Definition: StaticAsserts.hpp:43
#define STATIC_ASSERT_ARITHMETIC(dtype)
Definition: StaticAsserts.hpp:39
Custom column iterator for NdArray.
Definition: NdArrayIterators.hpp:813
Custom column const_iterator for NdArray.
Definition: NdArrayIterators.hpp:487
Custom const_iterator for NdArray.
Definition: NdArrayIterators.hpp:41
Holds 1D and 2D arrays, the main work horse of the NumCpp library.
Definition: NdArrayCore.hpp:138
NdArray(std::vector< std::array< dtype, Dim1Size >> &in2dArray, bool copy=true)
Definition: NdArrayCore.hpp:391
const_reverse_column_iterator rcolbegin() const noexcept
Definition: NdArrayCore.hpp:1526
size_type dimSize(Axis inAxis) const noexcept
Definition: NdArrayCore.hpp:2637
NdArray< dtypeOut > astype() const
Definition: NdArrayCore.hpp:2134
self_type operator[](Slice inSlice) const
Definition: NdArrayCore.hpp:776
self_type & fill(value_type inFillValue) noexcept
Definition: NdArrayCore.hpp:2761
self_type max(Axis inAxis=Axis::NONE) const
Definition: NdArrayCore.hpp:2994
size_type size() const noexcept
Definition: NdArrayCore.hpp:4477
self_type & resizeFast(size_type inNumRows, size_type inNumCols)
Definition: NdArrayCore.hpp:4324
self_type & zeros() noexcept
Definition: NdArrayCore.hpp:4855
reverse_iterator rbegin() noexcept
Definition: NdArrayCore.hpp:1422
self_type at(index_type inRowIndex, const Slice &inColSlice) const
Definition: NdArrayCore.hpp:1150
self_type columns(const NdArray< size_type > &inCols) const
Definition: NdArrayCore.hpp:2377
self_type & reshape(size_type inSize)
Definition: NdArrayCore.hpp:4224
self_type & put(const Indices &inRowIndices, index_type inColIndex, const self_type &inValues)
Definition: NdArrayCore.hpp:4023
NdArray< bool > issorted(Axis inAxis=Axis::NONE) const
Definition: NdArrayCore.hpp:2921
const_iterator cbegin() const noexcept
Definition: NdArrayCore.hpp:1318
self_type at(const RowIndices &rowIndices, const ColIndices &colIndices) const
Definition: NdArrayCore.hpp:1226
self_type & put(const Slice &inRowSlice, index_type inColIndex, const self_type &inValues)
Definition: NdArrayCore.hpp:4040
self_type & put(const Indices &inRowIndices, index_type inColIndex, const value_type &inValue)
Definition: NdArrayCore.hpp:3844
const_column_iterator ccolbegin(size_type inCol) const
Definition: NdArrayCore.hpp:1407
self_type & put(index_type inRowIndex, const Slice &inColSlice, const self_type &inValues)
Definition: NdArrayCore.hpp:4075
NdArray< bool > any(Axis inAxis=Axis::NONE) const
Definition: NdArrayCore.hpp:1932
self_type & put(index_type inRowIndex, const Indices &inColIndices, const value_type &inValue)
Definition: NdArrayCore.hpp:3879
const_pointer data() const noexcept
Definition: NdArrayCore.hpp:2563
iterator end() noexcept
Definition: NdArrayCore.hpp:1576
NdArray(std::vector< dtype > &inVector, bool copy=true)
Definition: NdArrayCore.hpp:331
self_type & ones() noexcept
Definition: NdArrayCore.hpp:3440
self_type & put(index_type inIndex, const value_type &inValue)
Definition: NdArrayCore.hpp:3646
reference at(index_type inRowIndex, index_type inColIndex)
Definition: NdArrayCore.hpp:1021
self_type & resizeFast(const Shape &inShape)
Definition: NdArrayCore.hpp:4339
self_type & swapCols(index_type colIdx1, index_type colIdx2) noexcept
Definition: NdArrayCore.hpp:4625
self_type repeat(const Shape &inRepeatShape) const
Definition: NdArrayCore.hpp:4189
self_type at(Slice rowSlice, const Indices &colIndices) const
Definition: NdArrayCore.hpp:1209
std::vector< dtype > toStlVector() const
Definition: NdArrayCore.hpp:4767
reference back(size_type row)
Definition: NdArrayCore.hpp:2273
iterator end(size_type inRow)
Definition: NdArrayCore.hpp:1588
NdArray(const std::initializer_list< std::initializer_list< dtype >> &inList)
Definition: NdArrayCore.hpp:238
self_type operator()(const RowIndices &rowIndices, const ColIndices &colIndices) const
Definition: NdArrayCore.hpp:933
void tofile(const std::string &inFilename, const char inSep) const
Definition: NdArrayCore.hpp:4681
const_column_iterator ccolbegin() const noexcept
Definition: NdArrayCore.hpp:1395
NdArray< size_type > argmin(Axis inAxis=Axis::NONE) const
Definition: NdArrayCore.hpp:2024
typename AllocTraits::pointer pointer
Definition: NdArrayCore.hpp:151
self_type transpose() const
Definition: NdArrayCore.hpp:4837
reverse_iterator rbegin(size_type inRow)
Definition: NdArrayCore.hpp:1434
self_type & ravel()
Definition: NdArrayCore.hpp:4132
NdArray< size_type > toIndices(Slice inSlice, Axis inAxis=Axis::NONE) const
Definition: NdArrayCore.hpp:4718
const_reverse_column_iterator rcolend() const noexcept
Definition: NdArrayCore.hpp:1834
self_type rows(const NdArray< size_type > &inRows) const
Definition: NdArrayCore.hpp:4443
const dtype & const_reference
Definition: NdArrayCore.hpp:154
bool issquare() const noexcept
Definition: NdArrayCore.hpp:2962
bool isflat() const noexcept
Definition: NdArrayCore.hpp:2898
Endian endianess() const noexcept
Definition: NdArrayCore.hpp:2745
self_type dot(const self_type &inOtherArray) const
Definition: NdArrayCore.hpp:2672
void tofile(const std::string &inFilename) const
Definition: NdArrayCore.hpp:4664
const_reverse_column_iterator crcolbegin() const noexcept
Definition: NdArrayCore.hpp:1549
const_reverse_column_iterator crcolend(size_type inCol) const
Definition: NdArrayCore.hpp:1869
size_type numCols() const noexcept
Definition: NdArrayCore.hpp:3418
column_iterator colbegin(size_type inCol)
Definition: NdArrayCore.hpp:1357
NdArray< bool > none(Axis inAxis=Axis::NONE) const
Definition: NdArrayCore.hpp:3364
self_type median(Axis inAxis=Axis::NONE) const
Definition: NdArrayCore.hpp:3084
const_reference at(index_type inRowIndex, index_type inColIndex) const
Definition: NdArrayCore.hpp:1034
self_type at(const Slice &inSlice) const
Definition: NdArrayCore.hpp:1064
pointer data() noexcept
Definition: NdArrayCore.hpp:2553
bool isempty() const noexcept
Definition: NdArrayCore.hpp:2885
column_iterator colbegin() noexcept
Definition: NdArrayCore.hpp:1345
const_reference front(size_type row) const
Definition: NdArrayCore.hpp:2835
reverse_column_iterator rcolend(size_type inCol)
Definition: NdArrayCore.hpp:1819
self_type column(size_type inColumn) const
Definition: NdArrayCore.hpp:2365
self_type & put(const Slice &inRowSlice, const Slice &inColSlice, const value_type &inValue)
Definition: NdArrayCore.hpp:3827
self_type prod(Axis inAxis=Axis::NONE) const
Definition: NdArrayCore.hpp:3556
NdArray(Iterator inFirst, Iterator inLast)
Definition: NdArrayCore.hpp:487
reference at(index_type inIndex)
Definition: NdArrayCore.hpp:987
reverse_column_iterator rcolbegin() noexcept
Definition: NdArrayCore.hpp:1499
self_type & reshape(const Shape &inShape)
Definition: NdArrayCore.hpp:4309
self_type at(const Indices &inIndices) const
Definition: NdArrayCore.hpp:1094
const_iterator cbegin(size_type inRow) const
Definition: NdArrayCore.hpp:1330
const_column_iterator ccolend(size_type inCol) const
Definition: NdArrayCore.hpp:1792
self_type at(index_type rowIndex, const Indices &colIndices) const
Definition: NdArrayCore.hpp:1194
const_iterator cend(size_type inRow) const
Definition: NdArrayCore.hpp:1638
self_type & reshape(index_type inNumRows, index_type inNumCols)
Definition: NdArrayCore.hpp:4255
self_type getByIndices(const NdArray< size_type > &inIndices) const
Definition: NdArrayCore.hpp:2858
const_reverse_column_iterator rcolend(size_type inCol) const
Definition: NdArrayCore.hpp:1846
const_iterator end(size_type inRow) const
Definition: NdArrayCore.hpp:1615
self_type flatten() const
Definition: NdArrayCore.hpp:2800
reference back() noexcept
Definition: NdArrayCore.hpp:2251
const_reverse_column_iterator crcolend() const noexcept
Definition: NdArrayCore.hpp:1857
const_reference back(size_type row) const
Definition: NdArrayCore.hpp:2262
reverse_column_iterator rcolbegin(size_type inCol)
Definition: NdArrayCore.hpp:1511
NdArray(const std::deque< std::deque< dtype >> &in2dDeque)
Definition: NdArrayCore.hpp:435
iterator begin(size_type inRow)
Definition: NdArrayCore.hpp:1280
const_reverse_iterator rend() const noexcept
Definition: NdArrayCore.hpp:1680
self_type copy() const
Definition: NdArrayCore.hpp:2439
self_type round(uint8 inNumDecimals=0) const
Definition: NdArrayCore.hpp:4410
self_type swapaxes() const
Definition: NdArrayCore.hpp:4612
const_reverse_column_iterator rcolbegin(size_type inCol) const
Definition: NdArrayCore.hpp:1538
typename AllocTraits::difference_type difference_type
Definition: NdArrayCore.hpp:157
self_type & put(const Slice &inRowSlice, const ColIndices &inColIndices, const value_type &inValue)
Definition: NdArrayCore.hpp:3811
const_iterator end() const noexcept
Definition: NdArrayCore.hpp:1603
bool ownsInternalData() noexcept
Definition: NdArrayCore.hpp:3454
self_type operator[](const NdArray< bool > &inMask) const
Definition: NdArrayCore.hpp:788
column_iterator colend() noexcept
Definition: NdArrayCore.hpp:1730
NdArray(std::initializer_list< dtype > inList)
Definition: NdArrayCore.hpp:221
self_type & operator=(self_type &&rhs) noexcept
Definition: NdArrayCore.hpp:684
self_type at(const Indices &rowIndices, Slice colSlice) const
Definition: NdArrayCore.hpp:1180
self_type & put(const Slice &inSlice, const self_type &inValues)
Definition: NdArrayCore.hpp:3747
const_reference back() const noexcept
Definition: NdArrayCore.hpp:2240
self_type & operator=(const self_type &rhs)
Definition: NdArrayCore.hpp:643
std::pair< NdArray< size_type >, NdArray< size_type > > nonzero() const
Definition: NdArrayCore.hpp:4922
self_type diagonal(index_type inOffset=0, Axis inAxis=Axis::ROW) const
Definition: NdArrayCore.hpp:2592
std::reverse_iterator< const_iterator > const_reverse_iterator
Definition: NdArrayCore.hpp:162
self_type at(const Slice &inRowSlice, index_type inColIndex) const
Definition: NdArrayCore.hpp:1136
NdArray(const_pointer inPtr, UIntType1 numRows, UIntType2 numCols)
Definition: NdArrayCore.hpp:530
NdArray(const self_type &inOtherArray)
Definition: NdArrayCore.hpp:586
NdArray(self_type &&inOtherArray) noexcept
Definition: NdArrayCore.hpp:604
self_type & put(index_type inRow, index_type inCol, const value_type &inValue)
Definition: NdArrayCore.hpp:3663
uint64 nbytes() const noexcept
Definition: NdArrayCore.hpp:3186
self_type & put(const RowIndices &inRowIndices, const ColIndices &inColIndices, const self_type &inValues)
Definition: NdArrayCore.hpp:3917
self_type & putMask(const NdArray< bool > &inMask, const self_type &inValues)
Definition: NdArrayCore.hpp:4105
self_type at(const NdArray< bool > &inMask) const
Definition: NdArrayCore.hpp:1076
NdArray(const std::list< dtype > &inList)
Definition: NdArrayCore.hpp:467
NdArray()=default
const_reference front() const noexcept
Definition: NdArrayCore.hpp:2813
~NdArray() noexcept
Definition: NdArrayCore.hpp:621
Slice rSlice(index_type inStartIdx=0, size_type inStepSize=1) const
Definition: NdArrayCore.hpp:975
reference front() noexcept
Definition: NdArrayCore.hpp:2824
NdArray(size_type inNumRows, size_type inNumCols)
Definition: NdArrayCore.hpp:195
Allocator allocator_type
Definition: NdArrayCore.hpp:150
self_type & put(const Indices &inIndices, const value_type &inValue)
Definition: NdArrayCore.hpp:3681
void print() const
Definition: NdArrayCore.hpp:3540
self_type & byteswap() noexcept
Definition: NdArrayCore.hpp:2286
const_reverse_column_iterator crcolbegin(size_type inCol) const
Definition: NdArrayCore.hpp:1561
self_type & put(const RowIndices &inRowIndices, const ColIndices &inColIndices, const value_type &inValue)
Definition: NdArrayCore.hpp:3767
size_type numRows() const noexcept
Definition: NdArrayCore.hpp:3430
reverse_iterator rend(size_type inRow)
Definition: NdArrayCore.hpp:1665
NdArray(size_type inSquareSize)
Definition: NdArrayCore.hpp:181
self_type at(const Indices &rowIndices, index_type colIndex) const
Definition: NdArrayCore.hpp:1165
reverse_iterator rend() noexcept
Definition: NdArrayCore.hpp:1653
const_reverse_iterator rend(size_type inRow) const
Definition: NdArrayCore.hpp:1692
typename AllocTraits::const_pointer const_pointer
Definition: NdArrayCore.hpp:152
const_reverse_iterator crbegin() const noexcept
Definition: NdArrayCore.hpp:1472
const_column_iterator colend(size_type inCol) const
Definition: NdArrayCore.hpp:1769
self_type & operator=(value_type inValue) noexcept
Definition: NdArrayCore.hpp:667
self_type & put(const RowIndices &inRowIndices, Slice inColSlice, const self_type &inValues)
Definition: NdArrayCore.hpp:3973
std::reverse_iterator< iterator > reverse_iterator
Definition: NdArrayCore.hpp:161
self_type & put(const Slice &inRowSlice, index_type inColIndex, const value_type &inValue)
Definition: NdArrayCore.hpp:3861
self_type & put(Slice inRowSlice, const ColIndices &inColIndices, const self_type &inValues)
Definition: NdArrayCore.hpp:3990
NdArray(const std::vector< std::vector< dtype >> &in2dVector)
Definition: NdArrayCore.hpp:356
const_reverse_iterator rbegin(size_type inRow) const
Definition: NdArrayCore.hpp:1461
self_type operator[](const Indices &inIndices) const
Definition: NdArrayCore.hpp:802
const_iterator cend() const noexcept
Definition: NdArrayCore.hpp:1626
self_type & put(index_type inRowIndex, const Slice &inColSlice, const value_type &inValue)
Definition: NdArrayCore.hpp:3896
std::string str() const
Definition: NdArrayCore.hpp:4535
std::reverse_iterator< const_column_iterator > const_reverse_column_iterator
Definition: NdArrayCore.hpp:167
self_type cumsum(Axis inAxis=Axis::NONE) const
Definition: NdArrayCore.hpp:2505
self_type & put(Slice inRowSlice, Slice inColSlice, const self_type &inValues)
Definition: NdArrayCore.hpp:4006
reference front(size_type row)
Definition: NdArrayCore.hpp:2846
self_type & nans() noexcept
Definition: NdArrayCore.hpp:3169
self_type & partition(size_type inKth, Axis inAxis=Axis::NONE)
Definition: NdArrayCore.hpp:3474
self_type repeat(size_type inNumRows, size_type inNumCols) const
Definition: NdArrayCore.hpp:4148
NdArray< size_type > argmax(Axis inAxis=Axis::NONE) const
Definition: NdArrayCore.hpp:1977
NdArray(pointer inPtr, size_type numRows, size_type numCols, BoolType takeOwnership) noexcept
Definition: NdArrayCore.hpp:572
NdArray< size_type > flatnonzero() const
Definition: NdArrayCore.hpp:2774
const_iterator begin(size_type inRow) const
Definition: NdArrayCore.hpp:1307
iterator begin() noexcept
Definition: NdArrayCore.hpp:1268
self_type & put(const RowIndices &inRowIndices, const Slice &inColSlice, const value_type &inValue)
Definition: NdArrayCore.hpp:3794
const_column_iterator colbegin() const noexcept
Definition: NdArrayCore.hpp:1372
bool isscalar() const noexcept
Definition: NdArrayCore.hpp:2909
std::reverse_iterator< column_iterator > reverse_column_iterator
Definition: NdArrayCore.hpp:166
self_type operator()(Slice inRowSlice, Slice inColSlice) const
Definition: NdArrayCore.hpp:823
self_type newbyteorder(Endian inEndianess) const
Definition: NdArrayCore.hpp:3201
value_type item() const
Definition: NdArrayCore.hpp:2975
const_reference at(index_type inIndex) const
Definition: NdArrayCore.hpp:999
const_column_iterator colend() const noexcept
Definition: NdArrayCore.hpp:1757
self_type row(size_type inRow) const
Definition: NdArrayCore.hpp:4431
self_type operator()(const Indices &rowIndices, index_type colIndex) const
Definition: NdArrayCore.hpp:868
self_type at(const Slice &inRowSlice, const Slice &inColSlice) const
Definition: NdArrayCore.hpp:1123
self_type operator()(Slice inRowSlice, index_type inColIndex) const
Definition: NdArrayCore.hpp:837
const_reverse_iterator crend() const noexcept
Definition: NdArrayCore.hpp:1703
self_type & sort(Axis inAxis=Axis::NONE)
Definition: NdArrayCore.hpp:4491
self_type operator()(index_type rowIndex, const Indices &colIndices) const
Definition: NdArrayCore.hpp:899
NdArray< dtype, Allocator > self_type
Definition: NdArrayCore.hpp:148
const_column_iterator colbegin(size_type inCol) const
Definition: NdArrayCore.hpp:1384
self_type cumprod(Axis inAxis=Axis::NONE) const
Definition: NdArrayCore.hpp:2453
NdArray< bool > contains(value_type inValue, Axis inAxis=Axis::NONE) const
Definition: NdArrayCore.hpp:2398
const_column_iterator ccolend() const noexcept
Definition: NdArrayCore.hpp:1780
reference operator()(index_type inRowIndex, index_type inColIndex) noexcept
Definition: NdArrayCore.hpp:740
self_type operator()(index_type inRowIndex, Slice inColSlice) const
Definition: NdArrayCore.hpp:852
reverse_column_iterator rcolend() noexcept
Definition: NdArrayCore.hpp:1807
NdArray(std::array< dtype, ArraySize > &inArray, bool copy=true)
Definition: NdArrayCore.hpp:274
const_reverse_iterator rbegin() const noexcept
Definition: NdArrayCore.hpp:1449
NdArray(const_pointer inPtr, size_type size)
Definition: NdArrayCore.hpp:506
NdArray(const std::deque< dtype > &inDeque)
Definition: NdArrayCore.hpp:418
self_type & replace(value_type oldValue, value_type newValue)
Definition: NdArrayCore.hpp:4201
NdArray(std::array< std::array< dtype, Dim1Size >, Dim0Size > &in2dArray, bool copy=true)
Definition: NdArrayCore.hpp:302
self_type & put(const Indices &inIndices, const self_type &inValues)
Definition: NdArrayCore.hpp:3702
void dump(const std::string &inFilename) const
Definition: NdArrayCore.hpp:2718
dtype & reference
Definition: NdArrayCore.hpp:153
value_type trace(size_type inOffset=0, Axis inAxis=Axis::ROW) const noexcept
Definition: NdArrayCore.hpp:4784
pointer dataRelease() noexcept
Definition: NdArrayCore.hpp:2575
self_type ptp(Axis inAxis=Axis::NONE) const
Definition: NdArrayCore.hpp:3600
self_type & put(const Slice &inSlice, const value_type &inValue)
Definition: NdArrayCore.hpp:3732
self_type clip(value_type inMin, value_type inMax) const
Definition: NdArrayCore.hpp:2326
self_type getByMask(const NdArray< bool > &inMask) const
Definition: NdArrayCore.hpp:2872
self_type & swapRows(index_type rowIdx1, index_type rowIdx2) noexcept
Definition: NdArrayCore.hpp:4643
uint32 size_type
Definition: NdArrayCore.hpp:155
const_iterator begin() const noexcept
Definition: NdArrayCore.hpp:1295
column_iterator colend(size_type inCol)
Definition: NdArrayCore.hpp:1742
const_reference operator[](index_type inIndex) const noexcept
Definition: NdArrayCore.hpp:722
self_type operator()(Slice rowSlice, const Indices &colIndices) const
Definition: NdArrayCore.hpp:915
const_reference operator()(index_type inRowIndex, index_type inColIndex) const noexcept
Definition: NdArrayCore.hpp:753
self_type min(Axis inAxis=Axis::NONE) const
Definition: NdArrayCore.hpp:3038
dtype value_type
Definition: NdArrayCore.hpp:149
const Shape & shape() const noexcept
Definition: NdArrayCore.hpp:4464
reference operator[](index_type inIndex) noexcept
Definition: NdArrayCore.hpp:710
Slice cSlice(index_type inStartIdx=0, size_type inStepSize=1) const
Definition: NdArrayCore.hpp:961
self_type & put(index_type inRowIndex, const Indices &inColIndices, const self_type &inValues)
Definition: NdArrayCore.hpp:4058
NdArray< size_type > argsort(Axis inAxis=Axis::NONE) const
Definition: NdArrayCore.hpp:2070
const_reverse_iterator crend(size_type inRow) const
Definition: NdArrayCore.hpp:1715
const_reverse_iterator crbegin(size_type inRow) const
Definition: NdArrayCore.hpp:1484
int32 index_type
Definition: NdArrayCore.hpp:156
NdArray(pointer inPtr, size_type size, BoolType takeOwnership) noexcept
Definition: NdArrayCore.hpp:552
NdArray(const Shape &inShape)
Definition: NdArrayCore.hpp:208
self_type sum(Axis inAxis=Axis::NONE) const
Definition: NdArrayCore.hpp:4571
self_type operator()(const Indices &rowIndices, Slice colSlice) const
Definition: NdArrayCore.hpp:884
NdArray< bool > all(Axis inAxis=Axis::NONE) const
Definition: NdArrayCore.hpp:1888
self_type & resizeSlow(size_type inNumRows, size_type inNumCols)
Definition: NdArrayCore.hpp:4356
self_type & resizeSlow(const Shape &inShape)
Definition: NdArrayCore.hpp:4395
self_type & putMask(const NdArray< bool > &inMask, const value_type &inValue)
Definition: NdArrayCore.hpp:4088
Custom iterator for NdArray.
Definition: NdArrayIterators.hpp:313
A Shape Class for NdArrays.
Definition: Core/Shape.hpp:41
uint32 rows
Definition: Core/Shape.hpp:44
uint32 cols
Definition: Core/Shape.hpp:45
uint32 size() const noexcept
Definition: Core/Shape.hpp:104
A Class for slicing into NdArrays.
Definition: Slice.hpp:45
int32 step
Definition: Slice.hpp:50
int32 start
Definition: Slice.hpp:48
uint32 numElements(uint32 inArraySize)
Definition: Slice.hpp:195
constexpr auto j
Definition: Core/Constants.hpp:42
const double nan
NaN.
Definition: Core/Constants.hpp:41
bool isLittleEndian() noexcept
Definition: Endian.hpp:43
dtype byteSwap(dtype value) noexcept
Definition: Endian.hpp:63
dtype f(GeneratorType &generator, dtype inDofN, dtype inDofD)
Definition: f.hpp:56
bool any_of(InputIt first, InputIt last, UnaryPredicate p) noexcept
Definition: StlAlgorithms.hpp:76
void sort(RandomIt first, RandomIt last) noexcept
Definition: StlAlgorithms.hpp:696
bool none_of(InputIt first, InputIt last, UnaryPredicate p) noexcept
Definition: StlAlgorithms.hpp:405
ForwardIt max_element(ForwardIt first, ForwardIt last) noexcept
Definition: StlAlgorithms.hpp:285
void stable_sort(RandomIt first, RandomIt last) noexcept
Definition: StlAlgorithms.hpp:734
OutputIt transform(InputIt first, InputIt last, OutputIt destination, UnaryOperation unaryFunction)
Definition: StlAlgorithms.hpp:775
bool all_of(InputIt first, InputIt last, UnaryPredicate p) noexcept
Definition: StlAlgorithms.hpp:55
void for_each(InputIt first, InputIt last, UnaryFunction f)
Definition: StlAlgorithms.hpp:225
InputIt find(InputIt first, InputIt last, const T &value) noexcept
Definition: StlAlgorithms.hpp:205
std::pair< ForwardIt, ForwardIt > minmax_element(ForwardIt first, ForwardIt last) noexcept
Definition: StlAlgorithms.hpp:364
void replace(ForwardIt first, ForwardIt last, const T &oldValue, const T &newValue) noexcept
Definition: StlAlgorithms.hpp:468
bool is_sorted(ForwardIt first, ForwardIt last) noexcept
Definition: StlAlgorithms.hpp:245
OutputIt copy(InputIt first, InputIt last, OutputIt destination) noexcept
Definition: StlAlgorithms.hpp:97
void nth_element(RandomIt first, RandomIt nth, RandomIt last) noexcept
Definition: StlAlgorithms.hpp:425
ForwardIt min_element(ForwardIt first, ForwardIt last) noexcept
Definition: StlAlgorithms.hpp:324
void fill(ForwardIt first, ForwardIt last, const T &value) noexcept
Definition: StlAlgorithms.hpp:183
constexpr bool is_ndarray_signed_int_v
Definition: NdArrayCore.hpp:123
std::enable_if_t< is_ndarray_int_v< T >, int > ndarray_int_concept
Definition: NdArrayCore.hpp:130
constexpr bool is_ndarray_int_v
Definition: NdArrayCore.hpp:96
std::string num2str(dtype inNumber)
Definition: num2str.hpp:44
std::string value2str(dtype inValue)
Definition: value2str.hpp:46
bool essentiallyEqual(dtype inValue1, dtype inValue2) noexcept
Definition: essentiallyEqual.hpp:48
Definition: Cartesian.hpp:40
constexpr dtype power(dtype inValue, uint8 inExponent) noexcept
Definition: Functions/power.hpp:52
uint32 size(const NdArray< dtype > &inArray) noexcept
Definition: size.hpp:43
NdArray< dtype > repeat(const NdArray< dtype > &inArray, uint32 inNumRows, uint32 inNumCols)
Definition: repeat.hpp:49
void swap(NdArray< dtype > &inArray1, NdArray< dtype > &inArray2) noexcept
Definition: swap.hpp:42
std::pair< NdArray< uint32 >, NdArray< uint32 > > nonzero(const NdArray< dtype > &inArray)
Definition: nonzero.hpp:48
NdArray< dtype > & resizeFast(NdArray< dtype > &inArray, uint32 inNumRows, uint32 inNumCols)
Definition: resizeFast.hpp:50
Axis
Enum To describe an axis.
Definition: Types.hpp:47
NdArray< dtype > & reshape(NdArray< dtype > &inArray, uint32 inSize)
Definition: reshape.hpp:51
std::int64_t int64
Definition: Types.hpp:35
auto abs(dtype inValue) noexcept
Definition: abs.hpp:49
std::uint64_t uint64
Definition: Types.hpp:39
NdArray< dtype > & resizeSlow(NdArray< dtype > &inArray, uint32 inNumRows, uint32 inNumCols)
Definition: resizeSlow.hpp:52
Endian
Enum for endianess.
Definition: Types.hpp:56
std::int32_t int32
Definition: Types.hpp:36
std::uint8_t uint8
Definition: Types.hpp:42
NdArray< dtype > sum(const NdArray< dtype > &inArray, Axis inAxis=Axis::NONE)
Definition: sum.hpp:46
NdArray< dtype > transpose(const NdArray< dtype > &inArray)
Definition: transpose.hpp:45
std::uint32_t uint32
Definition: Types.hpp:40
void dump(const NdArray< dtype > &inArray, const std::string &inFilename)
Definition: dump.hpp:46
NdArray< dtype > & put(NdArray< dtype > &inArray, int32 inIndex, const dtype &inValue)
Definition: put.hpp:46
Definition: NdArrayCore.hpp:77
Definition: NdArrayCore.hpp:104