NumCpp  2.10.1
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:
634  {
635  if (&rhs != this)
636  {
637  if (rhs.size_ > 0)
638  {
639  newArray(rhs.shape_);
640  endianess_ = rhs.endianess_;
641 
642  stl_algorithms::copy(rhs.cbegin(), rhs.cend(), begin());
643  }
644  }
645 
646  return *this;
647  }
648 
649  //============================================================================
650  // Method Description:
657  self_type& operator=(value_type inValue) noexcept
658  {
659  if (array_ != nullptr)
660  {
661  stl_algorithms::fill(begin(), end(), inValue);
662  }
663 
664  return *this;
665  }
666 
667  //============================================================================
668  // Method Description:
674  self_type& operator=(self_type&& rhs) noexcept
675  {
676  if (&rhs != this)
677  {
678  deleteArray();
679  shape_ = rhs.shape_;
680  size_ = rhs.size_;
681  endianess_ = rhs.endianess_;
682  array_ = rhs.array_;
683  ownsPtr_ = rhs.ownsPtr_;
684 
685  rhs.shape_.rows = rhs.shape_.cols = rhs.size_ = 0;
686  rhs.array_ = nullptr;
687  rhs.ownsPtr_ = false;
688  }
689 
690  return *this;
691  }
692 
693  //============================================================================
694  // Method Description:
700  reference operator[](index_type inIndex) noexcept
701  {
702  return const_cast<reference>(const_cast<const self_type*>(this)->operator[](inIndex));
703  }
704 
705  //============================================================================
706  // Method Description:
712  [[nodiscard]] const_reference operator[](index_type inIndex) const noexcept
713  {
714  if (inIndex < 0)
715  {
716  inIndex += size_;
717  }
718 
719  return array_[inIndex];
720  }
721 
722  //============================================================================
723  // Method Description:
730  reference operator()(index_type inRowIndex, index_type inColIndex) noexcept
731  {
732  return const_cast<reference>(const_cast<const self_type*>(this)->operator()(inRowIndex, inColIndex));
733  }
734 
735  //============================================================================
736  // Method Description:
743  [[nodiscard]] const_reference operator()(index_type inRowIndex, index_type inColIndex) const noexcept
744  {
745  if (inRowIndex < 0)
746  {
747  inRowIndex += shape_.rows;
748  }
749 
750  if (inColIndex < 0)
751  {
752  inColIndex += shape_.cols;
753  }
754 
755  return array_[inRowIndex * shape_.cols + inColIndex];
756  }
757 
758  //============================================================================
759  // Method Description:
766  [[nodiscard]] self_type operator[](Slice inSlice) const
767  {
768  return operator[](toIndices(inSlice, Axis::NONE));
769  }
770 
771  //============================================================================
772  // Method Description:
778  [[nodiscard]] self_type operator[](const NdArray<bool>& inMask) const
779  {
780  return operator[](inMask.flatnonzero());
781  }
782 
783  //============================================================================
784  // Method Description:
791  template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
792  [[nodiscard]] self_type operator[](const Indices& inIndices) const
793  {
794  auto outArray = self_type(1, static_cast<size_type>(inIndices.size()));
795  size_type i = 0;
796  for (auto& index : inIndices)
797  {
798  outArray[i++] = operator[](static_cast<index_type>(index));
799  }
800 
801  return outArray;
802  }
803 
804  //============================================================================
805  // Method Description:
813  [[nodiscard]] self_type operator()(Slice inRowSlice, Slice inColSlice) const
814  {
815  return operator()(toIndices(inRowSlice, Axis::ROW), toIndices(inColSlice, Axis::COL));
816  }
817 
818  //============================================================================
819  // Method Description:
827  [[nodiscard]] self_type operator()(Slice inRowSlice, index_type inColIndex) const
828  {
829  const NdArray<index_type> colIndices = { inColIndex };
830  return operator()(toIndices(inRowSlice, Axis::ROW), colIndices);
831  }
832 
833  //============================================================================
834  // Method Description:
842  [[nodiscard]] self_type operator()(index_type inRowIndex, Slice inColSlice) const
843  {
844  const NdArray<index_type> rowIndices = { inRowIndex };
845  return operator()(rowIndices, toIndices(inColSlice, Axis::COL));
846  }
847 
848  //============================================================================
849  // Method Description:
857  template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
858  [[nodiscard]] self_type operator()(const Indices& rowIndices, index_type colIndex) const
859  {
860  const NdArray<index_type> colIndices = { colIndex };
861  return operator()(rowIndices, colIndices);
862  }
863 
864  //============================================================================
865  // Method Description:
873  template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
874  [[nodiscard]] self_type operator()(const Indices& rowIndices, Slice colSlice) const
875  {
876  return operator()(rowIndices, toIndices(colSlice, Axis::COL));
877  }
878 
879  //============================================================================
880  // Method Description:
888  template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
889  [[nodiscard]] self_type operator()(index_type rowIndex, const Indices& colIndices) const
890  {
891  const NdArray<index_type> rowIndices = { rowIndex };
892  return operator()(rowIndices, colIndices);
893  }
894 
895  //============================================================================
896  // Method Description:
904  template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
905  [[nodiscard]] self_type operator()(Slice rowSlice, const Indices& colIndices) const
906  {
907  return operator()(toIndices(rowSlice, Axis::ROW), colIndices);
908  }
909 
910  //============================================================================
911  // Method Description:
919  template<typename RowIndices,
920  typename ColIndices,
923  [[nodiscard]] self_type operator()(const RowIndices& rowIndices, const ColIndices& colIndices) const
924  {
925  self_type returnArray(rowIndices.size(), colIndices.size());
926 
927  size_type rowCounter = 0;
928  for (auto rowIter = rowIndices.begin(); rowIter != rowIndices.end(); ++rowIter)
929  {
930  size_type colCounter = 0;
931  for (auto colIter = colIndices.begin(); colIter != colIndices.end(); ++colIter)
932  {
933  returnArray(rowCounter, colCounter++) = operator()(*rowIter, *colIter);
934  }
935 
936  ++rowCounter;
937  }
938 
939  return returnArray;
940  }
941 
942  //============================================================================
943  // Method Description:
951  [[nodiscard]] Slice cSlice(index_type inStartIdx = 0, size_type inStepSize = 1) const
952  {
953  return Slice(inStartIdx, shape_.cols, inStepSize); // NOLINT(modernize-return-braced-init-list)
954  }
955 
956  //============================================================================
957  // Method Description:
965  [[nodiscard]] Slice rSlice(index_type inStartIdx = 0, size_type inStepSize = 1) const
966  {
967  return Slice(inStartIdx, shape_.rows, inStepSize); // NOLINT(modernize-return-braced-init-list)
968  }
969 
970  //============================================================================
971  // Method Description:
978  {
979  return const_cast<reference>(const_cast<const self_type*>(this)->at(inIndex));
980  }
981 
982  //============================================================================
983  // Method Description:
989  [[nodiscard]] const_reference at(index_type inIndex) const
990  {
991  // this doesn't allow for calling the first element as -size_...
992  // but why would you really want to do that anyway?
993  if (std::abs(inIndex) > static_cast<int64>(size_ - 1))
994  {
995  std::string errStr = "Input index " + utils::num2str(inIndex);
996  errStr += " is out of bounds for array of size " + utils::num2str(size_) + ".";
998  }
999 
1000  return operator[](inIndex); // cppcheck-suppress returnTempReference
1001  }
1002 
1003  //============================================================================
1004  // Method Description:
1011  reference at(index_type inRowIndex, index_type inColIndex)
1012  {
1013  return const_cast<reference>(const_cast<const self_type*>(this)->at(inRowIndex, inColIndex));
1014  }
1015 
1016  //============================================================================
1017  // Method Description:
1024  [[nodiscard]] const_reference at(index_type inRowIndex, index_type inColIndex) const
1025  {
1026  // this doesn't allow for calling the first element as -size_...
1027  // but why would you really want to do that anyway?
1028  if (std::abs(inRowIndex) > static_cast<index_type>(shape_.rows - 1))
1029  {
1030  std::string errStr = "Row index " + utils::num2str(inRowIndex);
1031  errStr += " is out of bounds for array of size " + utils::num2str(shape_.rows) + ".";
1033  }
1034 
1035  // this doesn't allow for calling the first element as -size_...
1036  // but why would you really want to do that anyway?
1037  if (std::abs(inColIndex) > static_cast<index_type>(shape_.cols - 1))
1038  {
1039  std::string errStr = "Column index " + utils::num2str(inColIndex);
1040  errStr += " is out of bounds for array of size " + utils::num2str(shape_.cols) + ".";
1042  }
1043 
1044  return operator()(inRowIndex, inColIndex); // cppcheck-suppress returnTempReference
1045  }
1046 
1047  //============================================================================
1048  // Method Description:
1054  [[nodiscard]] self_type at(const Slice& inSlice) const
1055  {
1056  return at(toIndices(inSlice, Axis::NONE));
1057  }
1058 
1059  //============================================================================
1060  // Method Description:
1066  [[nodiscard]] self_type at(const NdArray<bool>& inMask) const
1067  {
1068  if (inMask.shape() != shape_)
1069  {
1070  THROW_INVALID_ARGUMENT_ERROR("Input mask must have the same dimensions as array.");
1071  }
1072 
1073  return operator[](inMask);
1074  }
1075 
1076  //============================================================================
1077  // Method Description:
1083  template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
1084  [[nodiscard]] self_type at(const Indices& inIndices) const
1085  {
1086  stl_algorithms::for_each(inIndices.begin(),
1087  inIndices.end(),
1088  [this](auto index)
1089  {
1090  auto indexSigned = static_cast<index_type>(index);
1091  if (indexSigned < 0)
1092  {
1093  indexSigned += size_;
1094  }
1095 
1096  if (indexSigned < 0 || indexSigned > static_cast<index_type>(size_ - 1))
1097  {
1098  THROW_INVALID_ARGUMENT_ERROR("Index exceeds matrix dimensions");
1099  }
1100  });
1101 
1102  return operator[](inIndices);
1103  }
1104 
1105  //============================================================================
1106  // Method Description:
1113  [[nodiscard]] self_type at(const Slice& inRowSlice, const Slice& inColSlice) const
1114  {
1115  return at(toIndices(inRowSlice, Axis::ROW), toIndices(inColSlice, Axis::COL));
1116  }
1117 
1118  //============================================================================
1119  // Method Description:
1126  [[nodiscard]] self_type at(const Slice& inRowSlice, index_type inColIndex) const
1127  {
1128  const NdArray<index_type> colIndices = { inColIndex };
1129  return at(toIndices(inRowSlice, Axis::ROW), colIndices);
1130  }
1131 
1132  //============================================================================
1133  // Method Description:
1140  [[nodiscard]] self_type at(index_type inRowIndex, const Slice& inColSlice) const
1141  {
1142  const NdArray<index_type> rowIndices = { inRowIndex };
1143  return at(rowIndices, toIndices(inColSlice, Axis::COL));
1144  }
1145 
1146  //============================================================================
1147  // Method Description:
1154  template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
1155  [[nodiscard]] self_type at(const Indices& rowIndices, index_type colIndex) const
1156  {
1157  const NdArray<index_type> colIndices = { colIndex };
1158  return at(rowIndices, colIndices);
1159  }
1160 
1161  //============================================================================
1162  // Method Description:
1169  template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
1170  [[nodiscard]] self_type at(const Indices& rowIndices, Slice colSlice) const
1171  {
1172  return at(rowIndices, toIndices(colSlice, Axis::COL));
1173  }
1174 
1175  //============================================================================
1176  // Method Description:
1183  template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
1184  [[nodiscard]] self_type at(index_type rowIndex, const Indices& colIndices) const
1185  {
1186  const NdArray<index_type> rowIndices = { rowIndex };
1187  return at(rowIndices, colIndices);
1188  }
1189 
1190  //============================================================================
1191  // Method Description:
1198  template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
1199  [[nodiscard]] self_type at(Slice rowSlice, const Indices& colIndices) const
1200  {
1201  return at(toIndices(rowSlice, Axis::ROW), colIndices);
1202  }
1203 
1204  //============================================================================
1205  // Method Description:
1212  template<typename RowIndices,
1213  typename ColIndices,
1216  [[nodiscard]] self_type at(const RowIndices& rowIndices, const ColIndices& colIndices) const
1217  {
1218  stl_algorithms::for_each(rowIndices.begin(),
1219  rowIndices.end(),
1220  [this](auto row)
1221  {
1222  auto rowSigned = static_cast<index_type>(row);
1223  if (rowSigned < 0)
1224  {
1225  rowSigned += shape_.rows;
1226  }
1227 
1228  if (rowSigned < 0 || rowSigned > static_cast<index_type>(shape_.rows - 1))
1229  {
1230  THROW_INVALID_ARGUMENT_ERROR("Row index exceeds matrix dimensions");
1231  }
1232  });
1233 
1234  stl_algorithms::for_each(colIndices.begin(),
1235  colIndices.end(),
1236  [this](auto col)
1237  {
1238  auto colSigned = static_cast<index_type>(col);
1239  if (colSigned < 0)
1240  {
1241  colSigned += shape_.cols;
1242  }
1243 
1244  if (colSigned < 0 || colSigned > static_cast<index_type>(shape_.cols - 1))
1245  {
1246  THROW_INVALID_ARGUMENT_ERROR("Column index exceeds matrix dimensions");
1247  }
1248  });
1249 
1250  return operator()(rowIndices, colIndices);
1251  }
1252 
1253  //============================================================================
1254  // Method Description:
1258  [[nodiscard]] iterator begin() noexcept
1259  {
1260  return iterator(array_);
1261  }
1262 
1263  //============================================================================
1264  // Method Description:
1270  [[nodiscard]] iterator begin(size_type inRow)
1271  {
1272  if (inRow >= shape_.rows)
1273  {
1274  THROW_INVALID_ARGUMENT_ERROR("input row is greater than the number of rows in the array.");
1275  }
1276 
1277  return begin() += (inRow * shape_.cols);
1278  }
1279 
1280  //============================================================================
1281  // Method Description:
1285  [[nodiscard]] const_iterator begin() const noexcept
1286  {
1287  return cbegin();
1288  }
1289 
1290  //============================================================================
1291  // Method Description:
1297  [[nodiscard]] const_iterator begin(size_type inRow) const
1298  {
1299  return cbegin(inRow);
1300  }
1301 
1302  //============================================================================
1303  // Method Description:
1308  [[nodiscard]] const_iterator cbegin() const noexcept
1309  {
1310  return const_iterator(array_);
1311  }
1312 
1313  //============================================================================
1314  // Method Description:
1320  [[nodiscard]] const_iterator cbegin(size_type inRow) const
1321  {
1322  if (inRow >= shape_.rows)
1323  {
1324  THROW_INVALID_ARGUMENT_ERROR("input row is greater than the number of rows in the array.");
1325  }
1326 
1327  return cbegin() += (inRow * shape_.cols);
1328  }
1329 
1330  //============================================================================
1331  // Method Description:
1335  [[nodiscard]] column_iterator colbegin() noexcept
1336  {
1337  return column_iterator(array_, shape_.rows, shape_.cols);
1338  }
1339 
1340  //============================================================================
1341  // Method Description:
1347  [[nodiscard]] column_iterator colbegin(size_type inCol)
1348  {
1349  if (inCol >= shape_.cols)
1350  {
1351  THROW_INVALID_ARGUMENT_ERROR("input col is greater than the number of cols in the array.");
1352  }
1353 
1354  return colbegin() += (inCol * shape_.rows);
1355  }
1356 
1357  //============================================================================
1358  // Method Description:
1362  [[nodiscard]] const_column_iterator colbegin() const noexcept
1363  {
1364  return ccolbegin();
1365  }
1366 
1367  //============================================================================
1368  // Method Description:
1374  [[nodiscard]] const_column_iterator colbegin(size_type inCol) const
1375  {
1376  return ccolbegin(inCol);
1377  }
1378 
1379  //============================================================================
1380  // Method Description:
1385  [[nodiscard]] const_column_iterator ccolbegin() const noexcept
1386  {
1387  return const_column_iterator(array_, shape_.rows, shape_.cols);
1388  }
1389 
1390  //============================================================================
1391  // Method Description:
1397  [[nodiscard]] const_column_iterator ccolbegin(size_type inCol) const
1398  {
1399  if (inCol >= shape_.cols)
1400  {
1401  THROW_INVALID_ARGUMENT_ERROR("input col is greater than the number of cols in the array.");
1402  }
1403 
1404  return ccolbegin() += (inCol * shape_.rows);
1405  }
1406 
1407  //============================================================================
1408  // Method Description:
1412  [[nodiscard]] reverse_iterator rbegin() noexcept
1413  {
1414  return reverse_iterator(end());
1415  }
1416 
1417  //============================================================================
1418  // Method Description:
1424  [[nodiscard]] reverse_iterator rbegin(size_type inRow)
1425  {
1426  if (inRow >= shape_.rows)
1427  {
1428  THROW_INVALID_ARGUMENT_ERROR("input row is greater than the number of rows in the array.");
1429  }
1430 
1431  return rbegin() += (shape_.rows - inRow - 1) * shape_.cols;
1432  }
1433 
1434  //============================================================================
1435  // Method Description:
1439  [[nodiscard]] const_reverse_iterator rbegin() const noexcept
1440  {
1441  return crbegin();
1442  }
1443 
1444  //============================================================================
1445  // Method Description:
1451  [[nodiscard]] const_reverse_iterator rbegin(size_type inRow) const
1452  {
1453  return crbegin(inRow);
1454  }
1455 
1456  //============================================================================
1457  // Method Description:
1462  [[nodiscard]] const_reverse_iterator crbegin() const noexcept
1463  {
1464  return const_reverse_iterator(cend());
1465  }
1466 
1467  //============================================================================
1468  // Method Description:
1474  [[nodiscard]] const_reverse_iterator crbegin(size_type inRow) const
1475  {
1476  if (inRow >= shape_.rows)
1477  {
1478  THROW_INVALID_ARGUMENT_ERROR("input row is greater than the number of rows in the array.");
1479  }
1480 
1481  return crbegin() += (shape_.rows - inRow - 1) * shape_.cols;
1482  }
1483 
1484  //============================================================================
1485  // Method Description:
1489  [[nodiscard]] reverse_column_iterator rcolbegin() noexcept
1490  {
1491  return reverse_column_iterator(colend());
1492  }
1493 
1494  //============================================================================
1495  // Method Description:
1502  {
1503  if (inCol >= shape_.cols)
1504  {
1505  THROW_INVALID_ARGUMENT_ERROR("input col is greater than the number of cols in the array.");
1506  }
1507 
1508  return rcolbegin() += (shape_.cols - inCol - 1) * shape_.rows;
1509  }
1510 
1511  //============================================================================
1512  // Method Description:
1516  [[nodiscard]] const_reverse_column_iterator rcolbegin() const noexcept
1517  {
1518  return crcolbegin();
1519  }
1520 
1521  //============================================================================
1522  // Method Description:
1529  {
1530  return crcolbegin(inCol);
1531  }
1532 
1533  //============================================================================
1534  // Method Description:
1539  [[nodiscard]] const_reverse_column_iterator crcolbegin() const noexcept
1540  {
1541  return const_reverse_column_iterator(ccolend());
1542  }
1543 
1544  //============================================================================
1545  // Method Description:
1552  {
1553  if (inCol >= shape_.cols)
1554  {
1555  THROW_INVALID_ARGUMENT_ERROR("input col is greater than the number of cols in the array.");
1556  }
1557 
1558  return crcolbegin() += (shape_.cols - inCol - 1) * shape_.rows;
1559  }
1560 
1561  //============================================================================
1562  // Method Description:
1566  [[nodiscard]] iterator end() noexcept
1567  {
1568  return begin() += size_;
1569  }
1570 
1571  //============================================================================
1572  // Method Description:
1578  [[nodiscard]] iterator end(size_type inRow)
1579  {
1580  if (inRow >= shape_.rows)
1581  {
1582  THROW_INVALID_ARGUMENT_ERROR("input row is greater than the number of rows in the array.");
1583  }
1584 
1585  return begin(inRow) += shape_.cols;
1586  }
1587 
1588  //============================================================================
1589  // Method Description:
1593  [[nodiscard]] const_iterator end() const noexcept
1594  {
1595  return cend();
1596  }
1597 
1598  //============================================================================
1599  // Method Description:
1605  [[nodiscard]] const_iterator end(size_type inRow) const
1606  {
1607  return cend(inRow);
1608  }
1609 
1610  //============================================================================
1611  // Method Description:
1616  [[nodiscard]] const_iterator cend() const noexcept
1617  {
1618  return cbegin() += size_;
1619  }
1620 
1621  //============================================================================
1622  // Method Description:
1628  [[nodiscard]] const_iterator cend(size_type inRow) const
1629  {
1630  if (inRow >= shape_.rows)
1631  {
1632  THROW_INVALID_ARGUMENT_ERROR("input row is greater than the number of rows in the array.");
1633  }
1634 
1635  return cbegin(inRow) += shape_.cols;
1636  }
1637 
1638  //============================================================================
1639  // Method Description:
1643  [[nodiscard]] reverse_iterator rend() noexcept
1644  {
1645  return rbegin() += size_;
1646  }
1647 
1648  //============================================================================
1649  // Method Description:
1655  [[nodiscard]] reverse_iterator rend(size_type inRow)
1656  {
1657  if (inRow >= shape_.rows)
1658  {
1659  THROW_INVALID_ARGUMENT_ERROR("input row is greater than the number of rows in the array.");
1660  }
1661 
1662  return rbegin(inRow) += shape_.cols;
1663  }
1664 
1665  //============================================================================
1666  // Method Description:
1670  [[nodiscard]] const_reverse_iterator rend() const noexcept
1671  {
1672  return crend();
1673  }
1674 
1675  //============================================================================
1676  // Method Description:
1682  [[nodiscard]] const_reverse_iterator rend(size_type inRow) const
1683  {
1684  return crend(inRow);
1685  }
1686 
1687  //============================================================================
1688  // Method Description:
1693  [[nodiscard]] const_reverse_iterator crend() const noexcept
1694  {
1695  return crbegin() += size_;
1696  }
1697 
1698  //============================================================================
1699  // Method Description:
1705  [[nodiscard]] const_reverse_iterator crend(size_type inRow) const
1706  {
1707  if (inRow >= shape_.rows)
1708  {
1709  THROW_INVALID_ARGUMENT_ERROR("input row is greater than the number of rows in the array.");
1710  }
1711 
1712  return crbegin(inRow) += shape_.cols;
1713  }
1714 
1715  //============================================================================
1716  // Method Description:
1720  [[nodiscard]] column_iterator colend() noexcept
1721  {
1722  return colbegin() += size_;
1723  }
1724 
1725  //============================================================================
1726  // Method Description:
1732  [[nodiscard]] column_iterator colend(size_type inCol)
1733  {
1734  if (inCol >= shape_.cols)
1735  {
1736  THROW_INVALID_ARGUMENT_ERROR("input col is greater than the number of cols in the array.");
1737  }
1738 
1739  return colbegin(inCol) += shape_.rows;
1740  }
1741 
1742  //============================================================================
1743  // Method Description:
1747  [[nodiscard]] const_column_iterator colend() const noexcept
1748  {
1749  return ccolend();
1750  }
1751 
1752  //============================================================================
1753  // Method Description:
1759  [[nodiscard]] const_column_iterator colend(size_type inCol) const
1760  {
1761  return ccolend(inCol);
1762  }
1763 
1764  //============================================================================
1765  // Method Description:
1770  [[nodiscard]] const_column_iterator ccolend() const noexcept
1771  {
1772  return ccolbegin() += size_;
1773  }
1774 
1775  //============================================================================
1776  // Method Description:
1782  [[nodiscard]] const_column_iterator ccolend(size_type inCol) const
1783  {
1784  if (inCol >= shape_.cols)
1785  {
1786  THROW_INVALID_ARGUMENT_ERROR("input col is greater than the number of cols in the array.");
1787  }
1788 
1789  return ccolbegin(inCol) += shape_.rows;
1790  }
1791 
1792  //============================================================================
1793  // Method Description:
1797  [[nodiscard]] reverse_column_iterator rcolend() noexcept
1798  {
1799  return rcolbegin() += size_;
1800  }
1801 
1802  //============================================================================
1803  // Method Description:
1810  {
1811  if (inCol >= shape_.cols)
1812  {
1813  THROW_INVALID_ARGUMENT_ERROR("input col is greater than the number of cols in the array.");
1814  }
1815 
1816  return rcolbegin(inCol) += shape_.rows;
1817  }
1818 
1819  //============================================================================
1820  // Method Description:
1824  [[nodiscard]] const_reverse_column_iterator rcolend() const noexcept
1825  {
1826  return crcolend();
1827  }
1828 
1829  //============================================================================
1830  // Method Description:
1837  {
1838  return crcolend(inCol);
1839  }
1840 
1841  //============================================================================
1842  // Method Description:
1847  [[nodiscard]] const_reverse_column_iterator crcolend() const noexcept
1848  {
1849  return crcolbegin() += size_;
1850  }
1851 
1852  //============================================================================
1853  // Method Description:
1860  {
1861  if (inCol >= shape_.cols)
1862  {
1863  THROW_INVALID_ARGUMENT_ERROR("input col is greater than the number of cols in the array.");
1864  }
1865 
1866  return crcolbegin(inCol) += shape_.rows;
1867  }
1868 
1869  //============================================================================
1870  // Method Description:
1878  [[nodiscard]] NdArray<bool> all(Axis inAxis = Axis::NONE) const
1879  {
1881 
1882  const auto function = [](dtype i) -> bool { return !utils::essentiallyEqual(i, dtype{ 0 }); };
1883 
1884  switch (inAxis)
1885  {
1886  case Axis::NONE:
1887  {
1888  NdArray<bool> returnArray = { stl_algorithms::all_of(cbegin(), cend(), function) };
1889  return returnArray;
1890  }
1891  case Axis::COL:
1892  {
1893  NdArray<bool> returnArray(1, shape_.rows);
1894  for (uint32 row = 0; row < shape_.rows; ++row)
1895  {
1896  returnArray(0, row) = stl_algorithms::all_of(cbegin(row), cend(row), function);
1897  }
1898 
1899  return returnArray;
1900  }
1901  case Axis::ROW:
1902  {
1903  return transpose().all(Axis::COL);
1904  }
1905  default:
1906  {
1907  THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
1908  return {}; // get rid of compiler warning
1909  }
1910  }
1911  }
1912 
1913  //============================================================================
1914  // Method Description:
1922  [[nodiscard]] NdArray<bool> any(Axis inAxis = Axis::NONE) const
1923  {
1925 
1926  const auto function = [](dtype i) -> bool { return !utils::essentiallyEqual(i, dtype{ 0 }); };
1927 
1928  switch (inAxis)
1929  {
1930  case Axis::NONE:
1931  {
1932  NdArray<bool> returnArray = { stl_algorithms::any_of(cbegin(), cend(), function) };
1933  return returnArray;
1934  }
1935  case Axis::COL:
1936  {
1937  NdArray<bool> returnArray(1, shape_.rows);
1938  for (uint32 row = 0; row < shape_.rows; ++row)
1939  {
1940  returnArray(0, row) = stl_algorithms::any_of(cbegin(row), cend(row), function);
1941  }
1942 
1943  return returnArray;
1944  }
1945  case Axis::ROW:
1946  {
1947  return transpose().any(Axis::COL);
1948  }
1949  default:
1950  {
1951  THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
1952  return {}; // get rid of compiler warning
1953  }
1954  }
1955  }
1956 
1957  //============================================================================
1958  // Method Description:
1967  [[nodiscard]] NdArray<size_type> argmax(Axis inAxis = Axis::NONE) const
1968  {
1970 
1971  const auto comparitor = [](dtype lhs, dtype rhs) noexcept -> bool { return lhs < rhs; };
1972 
1973  switch (inAxis)
1974  {
1975  case Axis::NONE:
1976  {
1977  NdArray<size_type> returnArray = { static_cast<size_type>(
1978  stl_algorithms::max_element(cbegin(), cend(), comparitor) - cbegin()) };
1979  return returnArray;
1980  }
1981  case Axis::COL:
1982  {
1983  NdArray<size_type> returnArray(1, shape_.rows);
1984  for (size_type row = 0; row < shape_.rows; ++row)
1985  {
1986  returnArray(0, row) = static_cast<size_type>(
1987  stl_algorithms::max_element(cbegin(row), cend(row), comparitor) - cbegin(row));
1988  }
1989 
1990  return returnArray;
1991  }
1992  case Axis::ROW:
1993  {
1994  return transpose().argmax(Axis::COL);
1995  }
1996  default:
1997  {
1998  THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
1999  return {}; // get rid of compiler warning
2000  }
2001  }
2002  }
2003 
2004  //============================================================================
2005  // Method Description:
2014  [[nodiscard]] NdArray<size_type> argmin(Axis inAxis = Axis::NONE) const
2015  {
2017 
2018  const auto comparitor = [](dtype lhs, dtype rhs) noexcept -> bool { return lhs < rhs; };
2019 
2020  switch (inAxis)
2021  {
2022  case Axis::NONE:
2023  {
2024  NdArray<size_type> returnArray = { static_cast<size_type>(
2025  stl_algorithms::min_element(cbegin(), cend(), comparitor) - cbegin()) };
2026  return returnArray;
2027  }
2028  case Axis::COL:
2029  {
2030  NdArray<size_type> returnArray(1, shape_.rows);
2031  for (size_type row = 0; row < shape_.rows; ++row)
2032  {
2033  returnArray(0, row) = static_cast<size_type>(
2034  stl_algorithms::min_element(cbegin(row), cend(row), comparitor) - cbegin(row));
2035  }
2036 
2037  return returnArray;
2038  }
2039  case Axis::ROW:
2040  {
2041  return transpose().argmin(Axis::COL);
2042  }
2043  default:
2044  {
2045  THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
2046  return {}; // get rid of compiler warning
2047  }
2048  }
2049  }
2050 
2051  //============================================================================
2052  // Method Description:
2060  [[nodiscard]] NdArray<size_type> argsort(Axis inAxis = Axis::NONE) const
2061  {
2063 
2064  switch (inAxis)
2065  {
2066  case Axis::NONE:
2067  {
2068  std::vector<size_type> idx(size_);
2069  std::iota(idx.begin(), idx.end(), 0);
2070 
2071  const auto function = [this](size_type i1, size_type i2) noexcept -> bool
2072  { return (*this)[i1] < (*this)[i2]; };
2073 
2074  stl_algorithms::stable_sort(idx.begin(), idx.end(), function);
2075  return NdArray<size_type>(idx); // NOLINT(modernize-return-braced-init-list)
2076  }
2077  case Axis::COL:
2078  {
2079  NdArray<size_type> returnArray(shape_);
2080  std::vector<size_type> idx(shape_.cols);
2081 
2082  for (index_type row = 0; row < static_cast<index_type>(shape_.rows); ++row)
2083  {
2084  std::iota(idx.begin(), idx.end(), 0);
2085 
2086  const auto function = [this, row](size_type i1, size_type i2) noexcept -> bool
2087  { return operator()(row, i1) < operator()(row, i2); };
2088 
2089  stl_algorithms::stable_sort(idx.begin(), idx.end(), function);
2090 
2091  for (index_type col = 0; col < static_cast<index_type>(shape_.cols); ++col)
2092  {
2093  returnArray(row, col) = idx[static_cast<size_type>(col)];
2094  }
2095  }
2096  return returnArray;
2097  }
2098  case Axis::ROW:
2099  {
2100  return transpose().argsort(Axis::COL).transpose();
2101  }
2102  default:
2103  {
2104  THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
2105  return {}; // get rid of compiler warning
2106  }
2107  }
2108  }
2109 
2110  //============================================================================
2111  // Method Description:
2119  template<typename dtypeOut,
2120  typename dtype_ = dtype,
2121  std::enable_if_t<std::is_same_v<dtype_, dtype>, int> = 0,
2122  std::enable_if_t<std::is_arithmetic_v<dtype_>, int> = 0,
2123  std::enable_if_t<std::is_arithmetic_v<dtypeOut>, int> = 0>
2124  [[nodiscard]] NdArray<dtypeOut> astype() const
2125  {
2126  if constexpr (std::is_same_v<dtypeOut, dtype>)
2127  {
2128  return *this;
2129  }
2130  else
2131  {
2132  NdArray<dtypeOut> outArray(shape_);
2133  stl_algorithms::transform(cbegin(),
2134  cend(),
2135  outArray.begin(),
2136  [](dtype value) -> dtypeOut { return static_cast<dtypeOut>(value); });
2137 
2138  return outArray;
2139  }
2140  }
2141 
2142  //============================================================================
2143  // Method Description:
2151  template<typename dtypeOut,
2152  typename dtype_ = dtype,
2153  std::enable_if_t<std::is_same_v<dtype_, dtype>, int> = 0,
2154  std::enable_if_t<std::is_arithmetic_v<dtype_>, int> = 0,
2155  std::enable_if_t<is_complex_v<dtypeOut>, int> = 0>
2156  [[nodiscard]] NdArray<dtypeOut> astype() const
2157  {
2158  NdArray<dtypeOut> outArray(shape_);
2159 
2160  const auto function = [](const_reference value) -> dtypeOut
2161  { return std::complex<typename dtypeOut::value_type>(value); };
2162 
2163  stl_algorithms::transform(cbegin(), cend(), outArray.begin(), function);
2164 
2165  return outArray;
2166  }
2167 
2168  //============================================================================
2169  // Method Description:
2177  template<typename dtypeOut,
2178  typename dtype_ = dtype,
2179  std::enable_if_t<std::is_same_v<dtype_, dtype>, int> = 0,
2180  std::enable_if_t<is_complex_v<dtype_>, int> = 0,
2181  std::enable_if_t<is_complex_v<dtypeOut>, int> = 0>
2182  [[nodiscard]] NdArray<dtypeOut> astype() const
2183  {
2184  if constexpr (std::is_same_v<dtypeOut, dtype>)
2185  {
2186  return *this;
2187  }
2188  else
2189  {
2190  const auto function = [](const_reference value) noexcept -> dtypeOut
2191  { return complex_cast<typename dtypeOut::value_type>(value); };
2192 
2193  NdArray<dtypeOut> outArray(shape_);
2194  stl_algorithms::transform(cbegin(), cend(), outArray.begin(), function);
2195  return outArray;
2196  }
2197  }
2198 
2199  //============================================================================
2200  // Method Description:
2208  template<typename dtypeOut,
2209  typename dtype_ = dtype,
2210  std::enable_if_t<std::is_same_v<dtype_, dtype>, int> = 0,
2211  std::enable_if_t<is_complex_v<dtype_>, int> = 0,
2212  std::enable_if_t<std::is_arithmetic_v<dtypeOut>, int> = 0>
2213  [[nodiscard]] NdArray<dtypeOut> astype() const
2214  {
2215  NdArray<dtypeOut> outArray(shape_);
2216 
2217  const auto function = [](const_reference value) -> dtypeOut { return static_cast<dtypeOut>(value.real()); };
2218 
2219  stl_algorithms::transform(cbegin(), cend(), outArray.begin(), function);
2220 
2221  return outArray;
2222  }
2223 
2224  //============================================================================
2225  // Method Description:
2230  [[nodiscard]] const_reference back() const noexcept
2231  {
2232  return *(cend() - 1);
2233  }
2234 
2235  //============================================================================
2236  // Method Description:
2241  reference back() noexcept
2242  {
2243  return *(end() - 1);
2244  }
2245 
2246  //============================================================================
2247  // Method Description:
2252  [[nodiscard]] const_reference back(size_type row) const
2253  {
2254  return *(cend(row) - 1);
2255  }
2256 
2257  //============================================================================
2258  // Method Description:
2264  {
2265  return *(end(row) - 1);
2266  }
2267 
2268  //============================================================================
2269  // Method Description:
2276  self_type& byteswap() noexcept
2277  {
2278  STATIC_ASSERT_INTEGER(dtype);
2279 
2280  stl_algorithms::for_each(begin(),
2281  end(),
2282  [](dtype& value) noexcept -> void { value = endian::byteSwap(value); });
2283 
2284  switch (endianess_)
2285  {
2286  case Endian::NATIVE:
2287  {
2288  endianess_ = endian::isLittleEndian() ? Endian::BIG : Endian::LITTLE;
2289  break;
2290  }
2291  case Endian::LITTLE:
2292  {
2293  endianess_ = Endian::BIG;
2294  break;
2295  }
2296  case Endian::BIG:
2297  {
2298  endianess_ = Endian::LITTLE;
2299  break;
2300  }
2301  }
2302 
2303  return *this;
2304  }
2305 
2306  //============================================================================
2307  // Method Description:
2316  [[nodiscard]] self_type clip(value_type inMin, value_type inMax) const
2317  {
2319 
2320  self_type outArray(shape_);
2321  stl_algorithms::transform(cbegin(),
2322  cend(),
2323  outArray.begin(),
2324  [inMin, inMax](dtype value) noexcept -> dtype
2325  {
2326 #ifdef __cpp_lib_clamp
2327  const auto comparitor = [](dtype lhs, dtype rhs) noexcept -> bool
2328  { return lhs < rhs; };
2329 
2330  return std::clamp(value, inMin, inMax, comparitor);
2331 #else
2332  if (value < inMin)
2333  {
2334  return inMin;
2335  }
2336  else if (value > inMax)
2337  {
2338  return inMax;
2339  }
2340 
2341  return value;
2342 #endif
2343  });
2344 
2345  return outArray;
2346  }
2347 
2348  //============================================================================
2349  // Method Description:
2355  [[nodiscard]] self_type column(size_type inColumn)
2356  {
2357  return operator()(rSlice(), inColumn);
2358  }
2359 
2360  //============================================================================
2361  // Method Description:
2368  [[nodiscard]] NdArray<bool> contains(value_type inValue, Axis inAxis = Axis::NONE) const
2369  {
2371 
2372  switch (inAxis)
2373  {
2374  case Axis::NONE:
2375  {
2376  NdArray<bool> returnArray = { stl_algorithms::find(cbegin(), cend(), inValue) != cend() };
2377  return returnArray;
2378  }
2379  case Axis::COL:
2380  {
2381  NdArray<bool> returnArray(1, shape_.rows);
2382  for (size_type row = 0; row < shape_.rows; ++row)
2383  {
2384  returnArray(0, row) = stl_algorithms::find(cbegin(row), cend(row), inValue) != cend(row);
2385  }
2386 
2387  return returnArray;
2388  }
2389  case Axis::ROW:
2390  {
2391  return transpose().contains(inValue, Axis::COL);
2392  }
2393  default:
2394  {
2395  THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
2396  return {}; // get rid of compiler warning
2397  }
2398  }
2399  }
2400 
2401  //============================================================================
2402  // Method Description:
2409  [[nodiscard]] self_type copy() const
2410  {
2411  return self_type(*this);
2412  }
2413 
2414  //============================================================================
2415  // Method Description:
2423  [[nodiscard]] self_type cumprod(Axis inAxis = Axis::NONE) const
2424  {
2426 
2427  switch (inAxis)
2428  {
2429  case Axis::NONE:
2430  {
2431  self_type returnArray(1, size_);
2432  returnArray[0] = front();
2433  for (size_type i = 1; i < size_; ++i)
2434  {
2435  returnArray[i] = returnArray[i - 1] * array_[i];
2436  }
2437 
2438  return returnArray;
2439  }
2440  case Axis::COL:
2441  {
2442  self_type returnArray(shape_);
2443  for (uint32 row = 0; row < shape_.rows; ++row)
2444  {
2445  returnArray(row, 0) = operator()(row, 0);
2446  for (uint32 col = 1; col < shape_.cols; ++col)
2447  {
2448  returnArray(row, col) = returnArray(row, col - 1) * operator()(row, col);
2449  }
2450  }
2451 
2452  return returnArray;
2453  }
2454  case Axis::ROW:
2455  {
2456  return transpose().cumprod(Axis::COL).transpose();
2457  }
2458  default:
2459  {
2460  THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
2461  return {}; // get rid of compiler warning
2462  }
2463  }
2464  }
2465 
2466  //============================================================================
2467  // Method Description:
2475  [[nodiscard]] self_type cumsum(Axis inAxis = Axis::NONE) const
2476  {
2478 
2479  switch (inAxis)
2480  {
2481  case Axis::NONE:
2482  {
2483  self_type returnArray(1, size_);
2484  returnArray[0] = front();
2485  for (size_type i = 1; i < size_; ++i)
2486  {
2487  returnArray[i] = returnArray[i - 1] + array_[i];
2488  }
2489 
2490  return returnArray;
2491  }
2492  case Axis::COL:
2493  {
2494  self_type returnArray(shape_);
2495  for (uint32 row = 0; row < shape_.rows; ++row)
2496  {
2497  returnArray(row, 0) = operator()(row, 0);
2498  for (uint32 col = 1; col < shape_.cols; ++col)
2499  {
2500  returnArray(row, col) = returnArray(row, col - 1) + operator()(row, col);
2501  }
2502  }
2503 
2504  return returnArray;
2505  }
2506  case Axis::ROW:
2507  {
2508  return transpose().cumsum(Axis::COL).transpose();
2509  }
2510  default:
2511  {
2512  THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
2513  return {}; // get rid of compiler warning
2514  }
2515  }
2516  }
2517 
2518  //============================================================================
2519  // Method Description:
2523  [[nodiscard]] pointer data() noexcept
2524  {
2525  return array_;
2526  }
2527 
2528  //============================================================================
2529  // Method Description:
2533  [[nodiscard]] const_pointer data() const noexcept
2534  {
2535  return array_;
2536  }
2537 
2538  //============================================================================
2539  // Method Description:
2545  [[nodiscard]] pointer dataRelease() noexcept
2546  {
2547  ownsPtr_ = false;
2548  return data();
2549  }
2550 
2551  //============================================================================
2552  // Method Description:
2562  [[nodiscard]] self_type diagonal(index_type inOffset = 0, Axis inAxis = Axis::ROW) const
2563  {
2564  switch (inAxis)
2565  {
2566  case Axis::COL:
2567  {
2568  std::vector<dtype> diagnolValues;
2569  size_type col = 0;
2570  for (index_type row = inOffset; row < static_cast<index_type>(shape_.rows); ++row)
2571  {
2572  if (row < 0)
2573  {
2574  ++col;
2575  continue;
2576  }
2577  if (col >= shape_.cols)
2578  {
2579  break;
2580  }
2581 
2582  diagnolValues.push_back(operator()(static_cast<size_type>(row), col));
2583  ++col;
2584  }
2585 
2586  return self_type(diagnolValues);
2587  }
2588  case Axis::ROW:
2589  {
2590  return transpose().diagonal(inOffset, Axis::COL);
2591  }
2592  default:
2593  {
2594  THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
2595  return {}; // get rid of compiler warning
2596  }
2597  }
2598  }
2599 
2600  //============================================================================
2601  // Method Description:
2607  [[nodiscard]] size_type dimSize(Axis inAxis) const noexcept
2608  {
2609  switch (inAxis)
2610  {
2611  case Axis::NONE:
2612  {
2613  return size();
2614  }
2615  case Axis::ROW:
2616  {
2617  return numRows();
2618  }
2619  case Axis::COL:
2620  {
2621  return numCols();
2622  }
2623  default:
2624  {
2625  return {}; // get rid of compiler warning
2626  }
2627  }
2628  }
2629 
2630  //============================================================================
2631  // Method Description:
2642  [[nodiscard]] self_type dot(const self_type& inOtherArray) const
2643  {
2645 
2646  if (shape_ == inOtherArray.shape_ && (shape_.rows == 1 || shape_.cols == 1))
2647  {
2648  dtype dotProduct = std::inner_product(cbegin(), cend(), inOtherArray.cbegin(), dtype{ 0 });
2649  self_type returnArray = { dotProduct };
2650  return returnArray;
2651  }
2652  if (shape_.cols == inOtherArray.shape_.rows)
2653  {
2654  // 2D array, use matrix multiplication
2655  self_type returnArray(shape_.rows, inOtherArray.shape_.cols);
2656  auto otherArrayT = inOtherArray.transpose();
2657 
2658  for (uint32 i = 0; i < shape_.rows; ++i)
2659  {
2660  for (uint32 j = 0; j < otherArrayT.shape_.rows; ++j)
2661  {
2662  returnArray(i, j) =
2663  std::inner_product(otherArrayT.cbegin(j), otherArrayT.cend(j), cbegin(i), dtype{ 0 });
2664  }
2665  }
2666 
2667  return returnArray;
2668  }
2669 
2670  std::string errStr = "shapes of [" + utils::num2str(shape_.rows) + ", " + utils::num2str(shape_.cols) + "]";
2671  errStr += " and [" + utils::num2str(inOtherArray.shape_.rows) + ", " +
2672  utils::num2str(inOtherArray.shape_.cols) + "]";
2673  errStr += " are not consistent.";
2675 
2676  return self_type(); // get rid of compiler warning
2677  }
2678 
2679  //============================================================================
2680  // Method Description:
2688  void dump(const std::string& inFilename) const
2689  {
2690  std::filesystem::path f(inFilename);
2691  if (!f.has_extension())
2692  {
2693  f.replace_extension("bin");
2694  }
2695 
2696  std::ofstream ofile(f.c_str(), std::ios::binary);
2697  if (!ofile.good())
2698  {
2699  THROW_RUNTIME_ERROR("Unable to open the input file:\n\t" + inFilename);
2700  }
2701 
2702  if (array_ != nullptr)
2703  {
2704  ofile.write(reinterpret_cast<const char*>(array_), size_ * sizeof(dtype));
2705  }
2706  ofile.close();
2707  }
2708 
2709  //============================================================================
2710  // Method Description:
2715  [[nodiscard]] Endian endianess() const noexcept
2716  {
2717  STATIC_ASSERT_ARITHMETIC(dtype);
2718 
2719  return endianess_;
2720  }
2721 
2722  //============================================================================
2723  // Method Description:
2731  self_type& fill(value_type inFillValue) noexcept
2732  {
2733  stl_algorithms::fill(begin(), end(), inFillValue);
2734  return *this;
2735  }
2736 
2737  //============================================================================
2738  // Method Description:
2744  [[nodiscard]] NdArray<size_type> flatnonzero() const
2745  {
2747 
2748  std::vector<size_type> indices;
2749  size_type idx = 0;
2750  for (auto value : *this)
2751  {
2752  if (!utils::essentiallyEqual(value, dtype{ 0 }))
2753  {
2754  indices.push_back(idx);
2755  }
2756  ++idx;
2757  }
2758 
2759  return NdArray<size_type>(indices); // NOLINT(modernize-return-braced-init-list)
2760  }
2761 
2762  //============================================================================
2763  // Method Description:
2770  [[nodiscard]] self_type flatten() const
2771  {
2772  self_type outArray(1, size_);
2773  stl_algorithms::copy(cbegin(), cend(), outArray.begin());
2774  return outArray;
2775  }
2776 
2777  //============================================================================
2778  // Method Description:
2783  [[nodiscard]] const_reference front() const noexcept
2784  {
2785  return *cbegin();
2786  }
2787 
2788  //============================================================================
2789  // Method Description:
2794  reference front() noexcept
2795  {
2796  return *begin();
2797  }
2798 
2799  //============================================================================
2800  // Method Description:
2805  [[nodiscard]] const_reference front(size_type row) const
2806  {
2807  return *cbegin(row);
2808  }
2809 
2810  //============================================================================
2811  // Method Description:
2817  {
2818  return *begin(row);
2819  }
2820 
2821  //============================================================================
2822  // Method Description:
2828  [[nodiscard]] self_type getByIndices(const NdArray<size_type>& inIndices) const
2829  {
2830  return operator[](inIndices);
2831  }
2832 
2833  //============================================================================
2834  // Method Description:
2842  [[nodiscard]] self_type getByMask(const NdArray<bool>& inMask) const
2843  {
2844  return operator[](inMask);
2845  }
2846 
2847  //============================================================================
2848  // Method Description:
2854  // NOLINTNEXTLINE(modernize-use-nodiscard)
2855  bool isempty() const noexcept
2856  {
2857  return size_ == 0;
2858  }
2859 
2860  //============================================================================
2861  // Method Description:
2867  // NOLINTNEXTLINE(modernize-use-nodiscard)
2868  bool isflat() const noexcept
2869  {
2870  return !isscalar() && (shape_.rows == 1 || shape_.cols == 1);
2871  }
2872 
2873  //============================================================================
2874  // Method Description:
2878  // NOLINTNEXTLINE(modernize-use-nodiscard)
2879  bool isscalar() const noexcept
2880  {
2881  return size_ == 1;
2882  }
2883 
2884  //============================================================================
2885  // Method Description:
2891  [[nodiscard]] NdArray<bool> issorted(Axis inAxis = Axis::NONE) const
2892  {
2894 
2895  const auto comparitor = [](dtype lhs, dtype rhs) noexcept -> bool { return lhs < rhs; };
2896 
2897  switch (inAxis)
2898  {
2899  case Axis::NONE:
2900  {
2901  return { stl_algorithms::is_sorted(cbegin(), cend(), comparitor) };
2902  }
2903  case Axis::COL:
2904  {
2905  NdArray<bool> returnArray(1, shape_.rows);
2906  for (uint32 row = 0; row < shape_.rows; ++row)
2907  {
2908  returnArray(0, row) = stl_algorithms::is_sorted(cbegin(row), cend(row), comparitor);
2909  }
2910 
2911  return returnArray;
2912  }
2913  case Axis::ROW:
2914  {
2915  return transpose().issorted(Axis::COL);
2916  }
2917  default:
2918  {
2919  THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
2920  return {}; // get rid of compiler warning
2921  }
2922  }
2923  }
2924 
2925  //============================================================================
2926  // Method Description:
2931  // NOLINTNEXTLINE(modernize-use-nodiscard)
2932  bool issquare() const noexcept
2933  {
2934  return shape_.issquare();
2935  }
2936 
2937  //============================================================================
2938  // Method Description:
2945  [[nodiscard]] value_type item() const
2946  {
2947  if (!isscalar())
2948  {
2949  THROW_INVALID_ARGUMENT_ERROR("Can only convert an array of size 1 to a C++ scalar");
2950  }
2951 
2952  return front();
2953  }
2954 
2955  //============================================================================
2956  // Method Description:
2964  [[nodiscard]] self_type max(Axis inAxis = Axis::NONE) const
2965  {
2967 
2968  const auto comparitor = [](dtype lhs, dtype rhs) noexcept -> bool { return lhs < rhs; };
2969 
2970  switch (inAxis)
2971  {
2972  case Axis::NONE:
2973  {
2974  self_type returnArray = { *stl_algorithms::max_element(cbegin(), cend(), comparitor) };
2975  return returnArray;
2976  }
2977  case Axis::COL:
2978  {
2979  self_type returnArray(1, shape_.rows);
2980  for (uint32 row = 0; row < shape_.rows; ++row)
2981  {
2982  returnArray(0, row) = *stl_algorithms::max_element(cbegin(row), cend(row), comparitor);
2983  }
2984 
2985  return returnArray;
2986  }
2987  case Axis::ROW:
2988  {
2989  return transpose().max(Axis::COL);
2990  }
2991  default:
2992  {
2993  THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
2994  return {}; // get rid of compiler warning
2995  }
2996  }
2997  }
2998 
2999  //============================================================================
3000  // Method Description:
3008  [[nodiscard]] self_type min(Axis inAxis = Axis::NONE) const
3009  {
3011 
3012  const auto comparitor = [](dtype lhs, dtype rhs) noexcept -> bool { return lhs < rhs; };
3013 
3014  switch (inAxis)
3015  {
3016  case Axis::NONE:
3017  {
3018  self_type returnArray = { *stl_algorithms::min_element(cbegin(), cend(), comparitor) };
3019  return returnArray;
3020  }
3021  case Axis::COL:
3022  {
3023  self_type returnArray(1, shape_.rows);
3024  for (uint32 row = 0; row < shape_.rows; ++row)
3025  {
3026  returnArray(0, row) = *stl_algorithms::min_element(cbegin(row), cend(row), comparitor);
3027  }
3028 
3029  return returnArray;
3030  }
3031  case Axis::ROW:
3032  {
3033  return transpose().min(Axis::COL);
3034  }
3035  default:
3036  {
3037  THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
3038  return {}; // get rid of compiler warning
3039  }
3040  }
3041  }
3042 
3043  //============================================================================
3044  // Method Description:
3054  [[nodiscard]] self_type median(Axis inAxis = Axis::NONE) const
3055  {
3057 
3058  const auto comparitor = [](dtype lhs, dtype rhs) noexcept -> bool { return lhs < rhs; };
3059 
3060  if (size_ == 0)
3061  {
3062  THROW_RUNTIME_ERROR("Median is undefined for an array of size = 0.");
3063  }
3064 
3065  switch (inAxis)
3066  {
3067  case Axis::NONE:
3068  {
3069  self_type copyArray(*this);
3070 
3071  const size_type middleIdx = size_ / 2; // integer division
3072  stl_algorithms::nth_element(copyArray.begin(),
3073  copyArray.begin() + middleIdx,
3074  copyArray.end(),
3075  comparitor);
3076 
3077  dtype medianValue = copyArray.array_[middleIdx];
3078  if (size_ % 2 == 0)
3079  {
3080  const size_type lhsIndex = middleIdx - 1;
3081  stl_algorithms::nth_element(copyArray.begin(),
3082  copyArray.begin() + lhsIndex,
3083  copyArray.end(),
3084  comparitor);
3085  medianValue =
3086  (medianValue + copyArray.array_[lhsIndex]) / dtype{ 2 }; // potentially integer division, ok
3087  }
3088 
3089  return { medianValue };
3090  }
3091  case Axis::COL:
3092  {
3093  self_type copyArray(*this);
3094  self_type returnArray(1, shape_.rows);
3095 
3096  const bool isEven = shape_.cols % 2 == 0;
3097  for (uint32 row = 0; row < shape_.rows; ++row)
3098  {
3099  const uint32 middleIdx = shape_.cols / 2; // integer division
3100  stl_algorithms::nth_element(copyArray.begin(row),
3101  copyArray.begin(row) + middleIdx,
3102  copyArray.end(row),
3103  comparitor);
3104 
3105  dtype medianValue = copyArray(row, middleIdx);
3106  if (isEven)
3107  {
3108  const size_type lhsIndex = middleIdx - 1;
3109  stl_algorithms::nth_element(copyArray.begin(row),
3110  copyArray.begin(row) + lhsIndex,
3111  copyArray.end(row),
3112  comparitor);
3113  medianValue = (medianValue + copyArray(row, lhsIndex)) /
3114  dtype{ 2 }; // potentially integer division, ok
3115  }
3116 
3117  returnArray(0, row) = medianValue;
3118  }
3119 
3120  return returnArray;
3121  }
3122  case Axis::ROW:
3123  {
3124  return transpose().median(Axis::COL);
3125  }
3126  default:
3127  {
3128  THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
3129  return {}; // get rid of compiler warning
3130  }
3131  }
3132  }
3133 
3134  //============================================================================
3135  // Method Description:
3139  self_type& nans() noexcept
3140 
3141  {
3142  STATIC_ASSERT_FLOAT(dtype);
3143 
3145  return *this;
3146  }
3147 
3148  //============================================================================
3149  // Method Description:
3156  [[nodiscard]] uint64 nbytes() const noexcept
3157  {
3158  return static_cast<uint64>(sizeof(dtype) * size_);
3159  }
3160 
3161  //============================================================================
3162  // Method Description:
3171  [[nodiscard]] self_type newbyteorder(Endian inEndianess) const
3172  {
3173  STATIC_ASSERT_INTEGER(dtype);
3174 
3175  const bool nativeIsLittle = endian::isLittleEndian();
3176 
3177  switch (endianess_)
3178  {
3179  case Endian::NATIVE:
3180  {
3181  switch (inEndianess)
3182  {
3183  case Endian::NATIVE:
3184  {
3185  return NdArray(*this);
3186  }
3187  case Endian::BIG:
3188  {
3189  if (nativeIsLittle)
3190  {
3191  self_type outArray(shape_);
3192 
3193  stl_algorithms::transform(cbegin(), end(), outArray.begin(), endian::byteSwap<dtype>);
3194 
3195  outArray.endianess_ = Endian::BIG;
3196  return outArray;
3197  }
3198  else
3199  {
3200  auto outArray = NdArray(*this);
3201  outArray.endianess_ = Endian::BIG;
3202  return outArray;
3203  }
3204  }
3205  case Endian::LITTLE:
3206  {
3207  if (nativeIsLittle)
3208  {
3209  auto outArray = NdArray(*this);
3210  outArray.endianess_ = Endian::LITTLE;
3211  return outArray;
3212  }
3213  else
3214  {
3215  self_type outArray(shape_);
3216 
3217  stl_algorithms::transform(cbegin(), end(), outArray.begin(), endian::byteSwap<dtype>);
3218 
3219  outArray.endianess_ = Endian::LITTLE;
3220  return outArray;
3221  }
3222  }
3223  default:
3224  {
3225  THROW_INVALID_ARGUMENT_ERROR("Unimplemented endian type.");
3226  return {}; // get rid of compiler warning
3227  }
3228  }
3229  break;
3230  }
3231  case Endian::BIG:
3232  {
3233  switch (inEndianess)
3234  {
3235  case Endian::NATIVE:
3236  {
3237  if (nativeIsLittle)
3238  {
3239  self_type outArray(shape_);
3240 
3241  stl_algorithms::transform(cbegin(), end(), outArray.begin(), endian::byteSwap<dtype>);
3242 
3243  outArray.endianess_ = Endian::NATIVE;
3244  return outArray;
3245  }
3246  else
3247  {
3248  auto outArray = NdArray(*this);
3249  outArray.endianess_ = Endian::NATIVE;
3250  return outArray;
3251  }
3252  }
3253  case Endian::BIG:
3254  {
3255  return NdArray(*this);
3256  }
3257  case Endian::LITTLE:
3258  {
3259  self_type outArray(shape_);
3260 
3261  stl_algorithms::transform(cbegin(), end(), outArray.begin(), endian::byteSwap<dtype>);
3262 
3263  outArray.endianess_ = Endian::LITTLE;
3264  return outArray;
3265  }
3266  default:
3267  {
3268  THROW_INVALID_ARGUMENT_ERROR("Unimplemented endian type.");
3269  return {}; // get rid of compiler warning
3270  }
3271  }
3272  break;
3273  }
3274  case Endian::LITTLE:
3275  {
3276  switch (inEndianess)
3277  {
3278  case Endian::NATIVE:
3279  {
3280  if (nativeIsLittle)
3281  {
3282  auto outArray = NdArray(*this);
3283  outArray.endianess_ = Endian::NATIVE;
3284  return outArray;
3285  }
3286  else
3287  {
3288  self_type outArray(shape_);
3289 
3290  stl_algorithms::transform(cbegin(), end(), outArray.begin(), endian::byteSwap<dtype>);
3291 
3292  outArray.endianess_ = Endian::NATIVE;
3293  return outArray;
3294  }
3295  }
3296  case Endian::BIG:
3297  {
3298  self_type outArray(shape_);
3299 
3300  stl_algorithms::transform(cbegin(), end(), outArray.begin(), endian::byteSwap<dtype>);
3301 
3302  outArray.endianess_ = Endian::BIG;
3303  return outArray;
3304  }
3305  case Endian::LITTLE:
3306  {
3307  return NdArray(*this);
3308  }
3309  default:
3310  {
3311  THROW_INVALID_ARGUMENT_ERROR("Unimplemented endian type.");
3312  return {}; // get rid of compiler warning
3313  }
3314  }
3315  break;
3316  }
3317  default:
3318  {
3319  THROW_INVALID_ARGUMENT_ERROR("Unimplemented endian type.");
3320  return {}; // get rid of compiler warning
3321  }
3322  }
3323  }
3324 
3325  //============================================================================
3326  // Method Description:
3334  [[nodiscard]] NdArray<bool> none(Axis inAxis = Axis::NONE) const
3335  {
3337 
3338  const auto function = [](dtype i) -> bool { return !utils::essentiallyEqual(i, dtype{ 0 }); };
3339 
3340  switch (inAxis)
3341  {
3342  case Axis::NONE:
3343  {
3344  NdArray<bool> returnArray = { stl_algorithms::none_of(cbegin(), cend(), function) };
3345  return returnArray;
3346  }
3347  case Axis::COL:
3348  {
3349  NdArray<bool> returnArray(1, shape_.rows);
3350  for (uint32 row = 0; row < shape_.rows; ++row)
3351  {
3352  returnArray(0, row) = stl_algorithms::none_of(cbegin(row), cend(row), function);
3353  }
3354 
3355  return returnArray;
3356  }
3357  case Axis::ROW:
3358  {
3359  return transpose().none(Axis::COL);
3360  }
3361  default:
3362  {
3363  THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
3364  return {}; // get rid of compiler warning
3365  }
3366  }
3367  }
3368 
3369  //============================================================================
3370  // Method Description:
3379  [[nodiscard]] std::pair<NdArray<size_type>, NdArray<size_type>> nonzero() const;
3380 
3381  //============================================================================
3382  // Method Description:
3388  [[nodiscard]] size_type numCols() const noexcept
3389  {
3390  return shape_.cols;
3391  }
3392 
3393  //============================================================================
3394  // Method Description:
3400  [[nodiscard]] size_type numRows() const noexcept
3401  {
3402  return shape_.rows;
3403  }
3404 
3405  //============================================================================
3406  // Method Description:
3410  self_type& ones() noexcept
3411  {
3413 
3414  fill(dtype{ 1 });
3415  return *this;
3416  }
3417 
3418  //============================================================================
3419  // Method Description:
3424  bool ownsInternalData() noexcept
3425  {
3426  return ownsPtr_;
3427  }
3428 
3429  //============================================================================
3430  // Method Description:
3444  self_type& partition(size_type inKth, Axis inAxis = Axis::NONE)
3445  {
3447 
3448  const auto comparitor = [](dtype lhs, dtype rhs) noexcept -> bool
3449  { return lhs < rhs; }; // cppcheck-suppress returnTempReference
3450 
3451  switch (inAxis)
3452  {
3453  case Axis::NONE:
3454  {
3455  if (inKth >= size_)
3456  {
3457  std::string errStr = "kth(=" + utils::num2str(inKth);
3458  errStr += ") out of bounds (" + utils::num2str(size_) + ")";
3460  }
3461 
3462  stl_algorithms::nth_element(begin(), begin() + inKth, end(), comparitor);
3463  break;
3464  }
3465  case Axis::COL:
3466  {
3467  if (inKth >= shape_.cols)
3468  {
3469  std::string errStr = "kth(=" + utils::num2str(inKth);
3470  errStr += ") out of bounds (" + utils::num2str(shape_.cols) + ")";
3472  }
3473 
3474  for (uint32 row = 0; row < shape_.rows; ++row)
3475  {
3476  stl_algorithms::nth_element(begin(row), begin(row) + inKth, end(row), comparitor);
3477  }
3478  break;
3479  }
3480  case Axis::ROW:
3481  {
3482  if (inKth >= shape_.rows)
3483  {
3484  std::string errStr = "kth(=" + utils::num2str(inKth);
3485  errStr += ") out of bounds (" + utils::num2str(shape_.rows) + ")";
3487  }
3488 
3489  self_type transposedArray = transpose();
3490  for (uint32 row = 0; row < transposedArray.shape_.rows; ++row)
3491  {
3492  stl_algorithms::nth_element(transposedArray.begin(row),
3493  transposedArray.begin(row) + inKth,
3494  transposedArray.end(row),
3495  comparitor);
3496  }
3497  *this = transposedArray.transpose();
3498  break;
3499  }
3500  }
3501 
3502  return *this;
3503  }
3504 
3505  //============================================================================
3506  // Method Description:
3510  void print() const
3511  {
3513 
3514  std::cout << *this;
3515  }
3516 
3517  //============================================================================
3518  // Method Description:
3526  [[nodiscard]] self_type prod(Axis inAxis = Axis::NONE) const
3527  {
3529 
3530  switch (inAxis)
3531  {
3532  case Axis::NONE:
3533  {
3534  dtype product = std::accumulate(cbegin(), cend(), dtype{ 1 }, std::multiplies<dtype>());
3535  self_type returnArray = { product };
3536  return returnArray;
3537  }
3538  case Axis::COL:
3539  {
3540  self_type returnArray(1, shape_.rows);
3541  for (uint32 row = 0; row < shape_.rows; ++row)
3542  {
3543  returnArray(0, row) =
3544  std::accumulate(cbegin(row), cend(row), dtype{ 1 }, std::multiplies<dtype>());
3545  }
3546 
3547  return returnArray;
3548  }
3549  case Axis::ROW:
3550  {
3551  return transpose().prod(Axis::COL);
3552  }
3553  default:
3554  {
3555  THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
3556  return {}; // get rid of compiler warning
3557  }
3558  }
3559  }
3560 
3561  //============================================================================
3562  // Method Description:
3570  [[nodiscard]] self_type ptp(Axis inAxis = Axis::NONE) const
3571  {
3573 
3574  const auto comparitor = [](dtype lhs, dtype rhs) noexcept -> bool { return lhs < rhs; };
3575 
3576  switch (inAxis)
3577  {
3578  case Axis::NONE:
3579  {
3580  const auto result = stl_algorithms::minmax_element(cbegin(), cend(), comparitor);
3581  self_type returnArray = { *result.second - *result.first };
3582  return returnArray;
3583  }
3584  case Axis::COL:
3585  {
3586  self_type returnArray(1, shape_.rows);
3587  for (uint32 row = 0; row < shape_.rows; ++row)
3588  {
3589  const auto result = stl_algorithms::minmax_element(cbegin(row), cend(row), comparitor);
3590  returnArray(0, row) = *result.second - *result.first;
3591  }
3592 
3593  return returnArray;
3594  }
3595  case Axis::ROW:
3596  {
3597  return transpose().ptp(Axis::COL);
3598  }
3599  default:
3600  {
3601  THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
3602  return {}; // get rid of compiler warning
3603  }
3604  }
3605  }
3606 
3607  //============================================================================
3608  // Method Description:
3616  self_type& put(index_type inIndex, const value_type& inValue)
3617  {
3618  at(inIndex) = inValue;
3619 
3620  return *this;
3621  }
3622 
3623  //============================================================================
3624  // Method Description:
3633  self_type& put(index_type inRow, index_type inCol, const value_type& inValue)
3634  {
3635  at(inRow, inCol) = inValue;
3636 
3637  return *this;
3638  }
3639 
3640  //============================================================================
3641  // Method Description:
3650  template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
3651  self_type& put(const Indices& inIndices, const value_type& inValue)
3652  {
3653  for (auto index : inIndices)
3654  {
3655  put(index, inValue);
3656  }
3657 
3658  return *this;
3659  }
3660 
3661  //============================================================================
3662  // Method Description:
3671  template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
3672  self_type& put(const Indices& inIndices, const self_type& inValues)
3673  {
3674  if (inValues.isscalar())
3675  {
3676  return put(inIndices, inValues.item());
3677  }
3678  else if (inIndices.size() != inValues.size())
3679  {
3680  THROW_INVALID_ARGUMENT_ERROR("Input indices do not match values dimensions.");
3681  }
3682 
3683  size_type counter = 0;
3684  for (auto index : inIndices)
3685  {
3686  put(index, inValues[counter++]);
3687  }
3688 
3689  return *this;
3690  }
3691 
3692  //============================================================================
3693  // Method Description:
3702  self_type& put(const Slice& inSlice, const value_type& inValue)
3703  {
3704  return put(toIndices(inSlice, Axis::NONE), inValue);
3705  }
3706 
3707  //============================================================================
3708  // Method Description:
3717  self_type& put(const Slice& inSlice, const self_type& inValues)
3718  {
3719  return put(toIndices(inSlice, Axis::NONE), inValues);
3720  }
3721 
3722  //============================================================================
3723  // Method Description:
3733  template<typename RowIndices,
3734  typename ColIndices,
3737  self_type& put(const RowIndices& inRowIndices, const ColIndices& inColIndices, const value_type& inValue)
3738  {
3739  stl_algorithms::for_each(inRowIndices.begin(),
3740  inRowIndices.end(),
3741  [this, &inColIndices, &inValue](const auto row)
3742  {
3743  stl_algorithms::for_each(inColIndices.begin(),
3744  inColIndices.end(),
3745  [this, row, &inValue](const auto col)
3746  { this->put(row, col, inValue); });
3747  });
3748 
3749  return *this;
3750  }
3751 
3752  //============================================================================
3753  // Method Description:
3763  template<typename RowIndices, type_traits::ndarray_int_concept<RowIndices> = 0>
3764  self_type& put(const RowIndices& inRowIndices, const Slice& inColSlice, const value_type& inValue)
3765  {
3766  return put(inRowIndices, toIndices(inColSlice, Axis::COL), inValue);
3767  }
3768 
3769  //============================================================================
3770  // Method Description:
3780  template<typename ColIndices, type_traits::ndarray_int_concept<ColIndices> = 0>
3781  self_type& put(const Slice& inRowSlice, const ColIndices& inColIndices, const value_type& inValue)
3782  {
3783  return put(toIndices(inRowSlice, Axis::ROW), inColIndices, inValue);
3784  }
3785 
3786  //============================================================================
3787  // Method Description:
3797  self_type& put(const Slice& inRowSlice, const Slice& inColSlice, const value_type& inValue)
3798  {
3799  return put(toIndices(inRowSlice, Axis::ROW), toIndices(inColSlice, Axis::COL), inValue);
3800  }
3801 
3802  //============================================================================
3803  // Method Description:
3813  template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
3814  self_type& put(const Indices& inRowIndices, index_type inColIndex, const value_type& inValue)
3815  {
3816  const NdArray<index_type> colIndices = { inColIndex };
3817  return put(inRowIndices, colIndices, inValue);
3818  }
3819 
3820  //============================================================================
3821  // Method Description:
3831  self_type& put(const Slice& inRowSlice, index_type inColIndex, const value_type& inValue)
3832  {
3833  const NdArray<index_type> colIndices = { inColIndex };
3834  return put(toIndices(inRowSlice, Axis::ROW), colIndices, inValue);
3835  }
3836 
3837  //============================================================================
3838  // Method Description:
3848  template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
3849  self_type& put(index_type inRowIndex, const Indices& inColIndices, const value_type& inValue)
3850  {
3851  const NdArray<index_type> rowIndices = { inRowIndex };
3852  return put(rowIndices, inColIndices, inValue);
3853  }
3854 
3855  //============================================================================
3856  // Method Description:
3866  self_type& put(index_type inRowIndex, const Slice& inColSlice, const value_type& inValue)
3867  {
3868  const NdArray<index_type> rowIndices = { inRowIndex };
3869  return put(rowIndices, toIndices(inColSlice, Axis::COL), inValue);
3870  }
3871 
3872  //============================================================================
3873  // Method Description:
3883  template<typename RowIndices,
3884  typename ColIndices,
3887  self_type& put(const RowIndices& inRowIndices, const ColIndices& inColIndices, const self_type& inValues)
3888  {
3889  std::vector<size_type> indices;
3890  indices.reserve(inRowIndices.size() * inColIndices.size());
3891  std::for_each(inRowIndices.begin(),
3892  inRowIndices.end(),
3893  [this, &inColIndices, &indices](auto row)
3894  {
3895  if constexpr (std::is_signed_v<decltype(row)>)
3896  {
3897  if (row < 0)
3898  {
3899  row += shape_.rows;
3900  }
3901  // still
3902  if (row < 0)
3903  {
3904  THROW_INVALID_ARGUMENT_ERROR("row index exceeds matrix dimensions");
3905  }
3906  }
3907  std::for_each(inColIndices.begin(),
3908  inColIndices.end(),
3909  [this, row, &indices](auto col)
3910  {
3911  if constexpr (std::is_signed_v<decltype(col)>)
3912  {
3913  if (col < 0)
3914  {
3915  col += shape_.cols;
3916  }
3917  // still
3918  if (col < 0)
3919  {
3920  THROW_INVALID_ARGUMENT_ERROR(
3921  "col index exceeds matrix dimensions");
3922  }
3923  }
3924  indices.push_back(row * shape_.cols + col);
3925  });
3926  });
3927 
3928  return put(NdArray<size_type>(indices.data(), indices.size(), false), inValues);
3929  }
3930 
3931  //============================================================================
3932  // Method Description:
3942  template<typename RowIndices, type_traits::ndarray_int_concept<RowIndices> = 0>
3943  self_type& put(const RowIndices& inRowIndices, Slice inColSlice, const self_type& inValues)
3944  {
3945  return put(inRowIndices, toIndices(inColSlice, Axis::COL), inValues);
3946  }
3947 
3948  //============================================================================
3949  // Method Description:
3959  template<typename ColIndices, type_traits::ndarray_int_concept<ColIndices> = 0>
3960  self_type& put(Slice inRowSlice, const ColIndices& inColIndices, const self_type& inValues)
3961  {
3962  return put(toIndices(inRowSlice, Axis::ROW), inColIndices, inValues);
3963  }
3964 
3965  //============================================================================
3966  // Method Description:
3976  self_type& put(Slice inRowSlice, Slice inColSlice, const self_type& inValues)
3977  {
3978  return put(toIndices(inRowSlice, Axis::ROW), toIndices(inColSlice, Axis::COL), inValues);
3979  }
3980 
3981  //============================================================================
3982  // Method Description:
3992  template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
3993  self_type& put(const Indices& inRowIndices, index_type inColIndex, const self_type& inValues)
3994  {
3995  const NdArray<index_type> colIndices = { inColIndex };
3996  return put(inRowIndices, colIndices, inValues);
3997  }
3998 
3999  //============================================================================
4000  // Method Description:
4010  self_type& put(const Slice& inRowSlice, index_type inColIndex, const self_type& inValues)
4011  {
4012  const NdArray<index_type> colIndices = { inColIndex };
4013  return put(toIndices(inRowSlice, Axis::ROW), colIndices, inValues);
4014  }
4015 
4016  //============================================================================
4017  // Method Description:
4027  template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
4028  self_type& put(index_type inRowIndex, const Indices& inColIndices, const self_type& inValues)
4029  {
4030  const NdArray<index_type> rowIndices = { inRowIndex };
4031  return put(rowIndices, inColIndices, inValues);
4032  }
4033 
4034  //============================================================================
4035  // Method Description:
4045  self_type& put(index_type inRowIndex, const Slice& inColSlice, const self_type& inValues)
4046  {
4047  const NdArray<index_type> rowIndices = { inRowIndex };
4048  return put(rowIndices, toIndices(inColSlice, Axis::COL), inValues);
4049  }
4050 
4051  //============================================================================
4052  // Method Description:
4058  self_type& putMask(const NdArray<bool>& inMask, const value_type& inValue)
4059  {
4060  if (inMask.shape() != shape_)
4061  {
4062  THROW_INVALID_ARGUMENT_ERROR("input inMask must be the same shape as the array it is masking.");
4063  }
4064 
4065  return put(inMask.flatnonzero(), inValue);
4066  }
4067 
4068  //============================================================================
4069  // Method Description:
4075  self_type& putMask(const NdArray<bool>& inMask, const self_type& inValues)
4076  {
4077  if (inMask.shape() != shape_)
4078  {
4079  THROW_INVALID_ARGUMENT_ERROR("input inMask must be the same shape as the array it is masking.");
4080  }
4081 
4082  if (inValues.isscalar())
4083  {
4084  put(inMask.flatnonzero(), inValues.item());
4085  }
4086  else
4087  {
4088  put(inMask.flatnonzero(), inValues);
4089  }
4090 
4091  return *this;
4092  }
4093 
4094  //============================================================================
4095  // Method Description:
4103  {
4104  reshape(size_);
4105  return *this;
4106  }
4107 
4108  //============================================================================
4109  // Method Description:
4118  [[nodiscard]] self_type repeat(size_type inNumRows, size_type inNumCols) const
4119  {
4120  self_type returnArray(shape_.rows * inNumRows, shape_.cols * inNumCols);
4121 
4122  for (size_type row = 0; row < inNumRows; ++row)
4123  {
4124  for (size_type col = 0; col < inNumCols; ++col)
4125  {
4126  std::vector<size_type> indices(shape_.size());
4127 
4128  const size_type rowStart = row * shape_.rows;
4129  const size_type colStart = col * shape_.cols;
4130 
4131  const size_type rowEnd = (row + 1) * shape_.rows;
4132  const size_type colEnd = (col + 1) * shape_.cols;
4133 
4134  size_type counter = 0;
4135  for (size_type rowIdx = rowStart; rowIdx < rowEnd; ++rowIdx)
4136  {
4137  for (size_type colIdx = colStart; colIdx < colEnd; ++colIdx)
4138  {
4139  indices[counter++] = rowIdx * returnArray.shape_.cols + colIdx;
4140  }
4141  }
4142 
4143  returnArray.put(NdArray<size_type>(indices), *this);
4144  }
4145  }
4146 
4147  return returnArray;
4148  }
4149 
4150  //============================================================================
4151  // Method Description:
4159  [[nodiscard]] self_type repeat(const Shape& inRepeatShape) const
4160  {
4161  return repeat(inRepeatShape.rows, inRepeatShape.cols);
4162  }
4163 
4164  //============================================================================
4165  // Method Description:
4172  {
4174 
4175  stl_algorithms::replace(begin(), end(), oldValue, newValue);
4176  return *this;
4177  }
4178 
4179  //============================================================================
4180  // Method Description:
4191  {
4192  if (inSize != size_)
4193  {
4194  std::string errStr = "Cannot reshape array of size " + utils::num2str(size_) + " into shape ";
4195  errStr += "[" + utils::num2str(1) + ", " + utils::num2str(inSize) + "]";
4196  THROW_RUNTIME_ERROR(errStr);
4197  }
4198 
4199  shape_.rows = 1;
4200  shape_.cols = inSize;
4201 
4202  return *this;
4203  }
4204 
4205  //============================================================================
4206  // Method Description:
4217  self_type& reshape(index_type inNumRows, index_type inNumCols)
4218  {
4219  if (inNumRows < 0)
4220  {
4221  if (size_ % inNumCols == 0)
4222  {
4223  return reshape(size_ / inNumCols, inNumCols);
4224  }
4225 
4226  std::string errStr = "Cannot reshape array of size " + utils::num2str(size_) + " into a shape ";
4227  errStr += "with " + utils::num2str(inNumCols) + " columns";
4229  }
4230 
4231  if (inNumCols < 0)
4232  {
4233  if (size_ % inNumRows == 0)
4234  {
4235  return reshape(inNumRows, size_ / inNumRows);
4236  }
4237 
4238  std::string errStr = "Cannot reshape array of size " + utils::num2str(size_) + " into a shape ";
4239  errStr += "with " + utils::num2str(inNumRows) + " rows";
4241  }
4242 
4243  if (static_cast<size_type>(inNumRows * inNumCols) != size_)
4244  {
4245  std::string errStr = "Cannot reshape array of size " + utils::num2str(size_) + " into shape ";
4246  errStr += "[" + utils::num2str(inNumRows) + ", " + utils::num2str(inNumCols) + "]";
4248  }
4249 
4250  shape_.rows = static_cast<size_type>(inNumRows);
4251  shape_.cols = static_cast<size_type>(inNumCols);
4252 
4253  return *this;
4254  }
4255 
4256  //============================================================================
4257  // Method Description:
4267  self_type& reshape(const Shape& inShape)
4268  {
4269  return reshape(inShape.rows, inShape.cols);
4270  }
4271 
4272  //============================================================================
4273  // Method Description:
4282  self_type& resizeFast(size_type inNumRows, size_type inNumCols)
4283  {
4284  newArray(Shape(inNumRows, inNumCols));
4285  return *this;
4286  }
4287 
4288  //============================================================================
4289  // Method Description:
4297  self_type& resizeFast(const Shape& inShape)
4298  {
4299  return resizeFast(inShape.rows, inShape.cols);
4300  }
4301 
4302  //============================================================================
4303  // Method Description:
4314  self_type& resizeSlow(size_type inNumRows, size_type inNumCols)
4315  {
4316  std::vector<dtype> oldData(size_);
4317  stl_algorithms::copy(begin(), end(), oldData.begin());
4318 
4319  const Shape inShape(inNumRows, inNumCols);
4320  const Shape oldShape = shape_;
4321 
4322  newArray(inShape);
4323 
4324  for (uint32 row = 0; row < inShape.rows; ++row)
4325  {
4326  for (uint32 col = 0; col < inShape.cols; ++col)
4327  {
4328  if (row >= oldShape.rows || col >= oldShape.cols)
4329  {
4330  operator()(row, col) = dtype{ 0 }; // zero fill
4331  }
4332  else
4333  {
4334  operator()(row, col) = oldData[row * oldShape.cols + col];
4335  }
4336  }
4337  }
4338 
4339  return *this;
4340  }
4341 
4342  //============================================================================
4343  // Method Description:
4353  self_type& resizeSlow(const Shape& inShape)
4354  {
4355  return resizeSlow(inShape.rows, inShape.cols);
4356  }
4357 
4358  //============================================================================
4359  // Method Description:
4368  [[nodiscard]] self_type round(uint8 inNumDecimals = 0) const
4369  {
4370  STATIC_ASSERT_FLOAT(dtype);
4371 
4372  self_type returnArray(shape_);
4373  const double multFactor = utils::power(10., inNumDecimals);
4374  const auto function = [multFactor](dtype value) noexcept -> dtype
4375  { return static_cast<dtype>(std::nearbyint(static_cast<double>(value) * multFactor) / multFactor); };
4376 
4377  stl_algorithms::transform(cbegin(), cend(), returnArray.begin(), function);
4378 
4379  return returnArray;
4380  }
4381 
4382  //============================================================================
4383  // Method Description:
4389  [[nodiscard]] self_type row(size_type inRow)
4390  {
4391  return self_type(cbegin(inRow), cend(inRow));
4392  }
4393 
4394  //============================================================================
4395  // Method Description:
4402  [[nodiscard]] Shape shape() const noexcept
4403  {
4404  return shape_;
4405  }
4406 
4407  //============================================================================
4408  // Method Description:
4415  [[nodiscard]] size_type size() const noexcept
4416  {
4417  return size_;
4418  }
4419 
4420  //============================================================================
4421  // Method Description:
4429  self_type& sort(Axis inAxis = Axis::NONE)
4430  {
4432 
4433  const auto comparitor = [](dtype lhs, dtype rhs) noexcept -> bool
4434  { return lhs < rhs; }; // cppcheck-suppress returnTempReference
4435 
4436  switch (inAxis)
4437  {
4438  case Axis::NONE:
4439  {
4440  stl_algorithms::sort(begin(), end(), comparitor);
4441  break;
4442  }
4443  case Axis::COL:
4444  {
4445  for (uint32 row = 0; row < shape_.rows; ++row)
4446  {
4447  stl_algorithms::sort(begin(row), end(row), comparitor);
4448  }
4449  break;
4450  }
4451  case Axis::ROW:
4452  {
4453  self_type transposedArray = transpose();
4454  for (uint32 row = 0; row < transposedArray.shape_.rows; ++row)
4455  {
4456  stl_algorithms::sort(transposedArray.begin(row), transposedArray.end(row), comparitor);
4457  }
4458 
4459  *this = transposedArray.transpose();
4460  break;
4461  }
4462  }
4463 
4464  return *this;
4465  }
4466 
4467  //============================================================================
4468  // Method Description:
4473  [[nodiscard]] std::string str() const
4474  {
4476 
4477  std::string out;
4478  out += "[";
4479  for (uint32 row = 0; row < shape_.rows; ++row)
4480  {
4481  out += "[";
4482  for (uint32 col = 0; col < shape_.cols; ++col)
4483  {
4484  out += utils::value2str(operator()(row, col)) + ", ";
4485  }
4486 
4487  if (row == shape_.rows - 1)
4488  {
4489  out += "]";
4490  }
4491  else
4492  {
4493  out += "]\n";
4494  }
4495  }
4496  out += "]\n";
4497  return out;
4498  }
4499 
4500  //============================================================================
4501  // Method Description:
4509  [[nodiscard]] self_type sum(Axis inAxis = Axis::NONE) const
4510  {
4512 
4513  switch (inAxis)
4514  {
4515  case Axis::NONE:
4516  {
4517  self_type returnArray = { std::accumulate(cbegin(), cend(), dtype{ 0 }) };
4518  return returnArray;
4519  }
4520  case Axis::COL:
4521  {
4522  self_type returnArray(1, shape_.rows);
4523  for (uint32 row = 0; row < shape_.rows; ++row)
4524  {
4525  returnArray(0, row) = std::accumulate(cbegin(row), cend(row), dtype{ 0 });
4526  }
4527 
4528  return returnArray;
4529  }
4530  case Axis::ROW:
4531  {
4532  return transpose().sum(Axis::COL);
4533  }
4534  default:
4535  {
4536  THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
4537  return {}; // get rid of compiler warning
4538  }
4539  }
4540  }
4541 
4542  //============================================================================
4543  // Method Description:
4550  [[nodiscard]] self_type swapaxes() const
4551  {
4552  return transpose();
4553  }
4554 
4555  //============================================================================
4556  // Method Description:
4563  self_type& swapCols(index_type colIdx1, index_type colIdx2) noexcept
4564  {
4565  for (index_type row = 0; row < static_cast<index_type>(shape_.rows); ++row)
4566  {
4567  std::swap(operator()(row, colIdx1), operator()(row, colIdx2));
4568  }
4569 
4570  return *this;
4571  }
4572 
4573  //============================================================================
4574  // Method Description:
4581  self_type& swapRows(index_type rowIdx1, index_type rowIdx2) noexcept
4582  {
4583  for (index_type col = 0; col < static_cast<index_type>(shape_.cols); ++col)
4584  {
4585  std::swap(operator()(rowIdx1, col), operator()(rowIdx2, col));
4586  }
4587 
4588  return *this;
4589  }
4590 
4591  //============================================================================
4592  // Method Description:
4602  void tofile(const std::string& inFilename) const
4603  {
4604  dump(inFilename);
4605  }
4606 
4607  //============================================================================
4608  // Method Description:
4619  void tofile(const std::string& inFilename, const char inSep) const
4620  {
4622 
4623  std::filesystem::path f(inFilename);
4624  if (!f.has_extension())
4625  {
4626  f.replace_extension("txt");
4627  }
4628 
4629  std::ofstream ofile(f.c_str());
4630  if (!ofile.good())
4631  {
4632  THROW_RUNTIME_ERROR("Input file could not be opened:\n\t" + inFilename);
4633  }
4634 
4635  size_type counter = 0;
4636  for (auto value : *this)
4637  {
4638  ofile << value;
4639  if (counter++ != size_ - 1)
4640  {
4641  ofile << inSep;
4642  }
4643  }
4644  ofile.close();
4645  }
4646 
4647  //============================================================================
4648  // Method Description:
4656  [[nodiscard]] NdArray<size_type> toIndices(Slice inSlice, Axis inAxis = Axis::NONE) const
4657  {
4658  size_type numElements = 0;
4659  switch (inAxis)
4660  {
4661  case Axis::NONE:
4662  {
4663  numElements = inSlice.numElements(size_);
4664  break;
4665  }
4666  case Axis::ROW:
4667  {
4668  numElements = inSlice.numElements(shape_.rows);
4669  break;
4670  }
4671  case Axis::COL:
4672  {
4673  numElements = inSlice.numElements(shape_.cols);
4674  break;
4675  }
4676  default:
4677  {
4678  // not actually possible, getting rid of compiler warning
4679  THROW_INVALID_ARGUMENT_ERROR("Invalid 'inAxis' option");
4680  }
4681  }
4682 
4683  if (numElements == 0)
4684  {
4685  return {};
4686  }
4687 
4688  NdArray<size_type> indices(1, numElements);
4689  indices[0] = static_cast<size_type>(inSlice.start);
4690  for (size_type i = 1; i < indices.size(); ++i)
4691  {
4692  indices[static_cast<index_type>(i)] = static_cast<size_type>(
4693  indices[static_cast<index_type>(i - size_type{ 1 })] + static_cast<size_type>(inSlice.step));
4694  }
4695 
4696  return indices;
4697  }
4698 
4699  //============================================================================
4700  // Method Description:
4705  [[nodiscard]] std::vector<dtype> toStlVector() const
4706  {
4707  return std::vector<dtype>(cbegin(), cend());
4708  }
4709 
4710  //============================================================================
4711  // Method Description:
4722  [[nodiscard]] value_type trace(size_type inOffset = 0, Axis inAxis = Axis::ROW) const noexcept
4723  {
4725 
4726  size_type rowStart = 0;
4727  size_type colStart = 0;
4728  switch (inAxis)
4729  {
4730  case Axis::ROW:
4731  {
4732  rowStart += inOffset;
4733  break;
4734  }
4735  case Axis::COL:
4736  {
4737  colStart += inOffset;
4738  break;
4739  }
4740  default:
4741  {
4742  // if the user input NONE, override back to ROW
4743  inAxis = Axis::ROW;
4744  break;
4745  }
4746  }
4747 
4748  if (rowStart >= shape_.rows || colStart >= shape_.cols)
4749  {
4750  return dtype{ 0 };
4751  }
4752 
4753  size_type col = colStart;
4754  dtype sum = 0;
4755  for (size_type row = rowStart; row < shape_.rows; ++row)
4756  {
4757  if (col >= shape_.cols)
4758  {
4759  break;
4760  }
4761  sum += operator()(row, col++);
4762  }
4763 
4764  return sum;
4765  }
4766 
4767  //============================================================================
4768  // Method Description:
4775  [[nodiscard]] self_type transpose() const
4776  {
4777  self_type transArray(shape_.cols, shape_.rows);
4778  for (uint32 row = 0; row < shape_.rows; ++row)
4779  {
4780  for (uint32 col = 0; col < shape_.cols; ++col)
4781  {
4782  transArray(col, row) = operator()(row, col);
4783  }
4784  }
4785  return transArray;
4786  }
4787 
4788  //============================================================================
4789  // Method Description:
4793  self_type& zeros() noexcept
4794  {
4796 
4797  fill(dtype{ 0 });
4798  return *this;
4799  }
4800 
4801  private:
4802  //====================================Attributes==============================
4803  allocator_type allocator_{};
4804  Shape shape_{ 0, 0 };
4805  size_type size_{ 0 };
4806  Endian endianess_{ Endian::NATIVE };
4807  pointer array_{ nullptr };
4808  bool ownsPtr_{ false };
4809 
4810  //============================================================================
4811  // Method Description:
4814  void deleteArray() noexcept
4815  {
4816  if (ownsPtr_ && array_ != nullptr)
4817  {
4818  allocator_.deallocate(array_, size_);
4819  }
4820 
4821  array_ = nullptr;
4822  shape_.rows = shape_.cols = 0;
4823  size_ = 0;
4824  ownsPtr_ = false;
4825  endianess_ = Endian::NATIVE;
4826  }
4827 
4828  //============================================================================
4829  // Method Description:
4832  void newArray()
4833  {
4834  if (size_ > 0)
4835  {
4836  array_ = allocator_.allocate(size_);
4837  ownsPtr_ = true;
4838  }
4839  }
4840 
4841  //============================================================================
4842  // Method Description:
4847  void newArray(const Shape& inShape)
4848  {
4849  deleteArray();
4850 
4851  shape_ = inShape;
4852  size_ = inShape.size();
4853  newArray();
4854  }
4855  };
4856 
4857  // NOTE: this needs to be defined outside of the class to get rid of a compiler
4858  // error in Visual Studio
4859  template<typename dtype, class Alloc_>
4860  [[nodiscard]] std::pair<NdArray<uint32>, NdArray<uint32>> NdArray<dtype, Alloc_>::nonzero() const
4861  {
4863 
4864  std::vector<size_type> rowIndices;
4865  std::vector<size_type> colIndices;
4866 
4867  for (uint32 row = 0; row < shape_.rows; ++row)
4868  {
4869  for (uint32 col = 0; col < shape_.cols; ++col)
4870  {
4871  if (!utils::essentiallyEqual(operator()(row, col), dtype{ 0 }))
4872  {
4873  rowIndices.push_back(row);
4874  colIndices.push_back(col);
4875  }
4876  }
4877  }
4878 
4879  return std::make_pair(NdArray<size_type>(rowIndices), NdArray<size_type>(colIndices));
4880  }
4881 } // 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:818
Custom column const_iterator for NdArray.
Definition: NdArrayIterators.hpp:492
Custom const_iterator for NdArray.
Definition: NdArrayIterators.hpp:42
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:1516
size_type dimSize(Axis inAxis) const noexcept
Definition: NdArrayCore.hpp:2607
self_type row(size_type inRow)
Definition: NdArrayCore.hpp:4389
NdArray< dtypeOut > astype() const
Definition: NdArrayCore.hpp:2124
self_type operator[](Slice inSlice) const
Definition: NdArrayCore.hpp:766
self_type & fill(value_type inFillValue) noexcept
Definition: NdArrayCore.hpp:2731
self_type max(Axis inAxis=Axis::NONE) const
Definition: NdArrayCore.hpp:2964
size_type size() const noexcept
Definition: NdArrayCore.hpp:4415
self_type & resizeFast(size_type inNumRows, size_type inNumCols)
Definition: NdArrayCore.hpp:4282
self_type & zeros() noexcept
Definition: NdArrayCore.hpp:4793
reverse_iterator rbegin() noexcept
Definition: NdArrayCore.hpp:1412
self_type at(index_type inRowIndex, const Slice &inColSlice) const
Definition: NdArrayCore.hpp:1140
self_type & reshape(size_type inSize)
Definition: NdArrayCore.hpp:4190
self_type & put(const Indices &inRowIndices, index_type inColIndex, const self_type &inValues)
Definition: NdArrayCore.hpp:3993
NdArray< bool > issorted(Axis inAxis=Axis::NONE) const
Definition: NdArrayCore.hpp:2891
const_iterator cbegin() const noexcept
Definition: NdArrayCore.hpp:1308
self_type at(const RowIndices &rowIndices, const ColIndices &colIndices) const
Definition: NdArrayCore.hpp:1216
self_type & put(const Slice &inRowSlice, index_type inColIndex, const self_type &inValues)
Definition: NdArrayCore.hpp:4010
self_type & put(const Indices &inRowIndices, index_type inColIndex, const value_type &inValue)
Definition: NdArrayCore.hpp:3814
const_column_iterator ccolbegin(size_type inCol) const
Definition: NdArrayCore.hpp:1397
self_type & put(index_type inRowIndex, const Slice &inColSlice, const self_type &inValues)
Definition: NdArrayCore.hpp:4045
NdArray< bool > any(Axis inAxis=Axis::NONE) const
Definition: NdArrayCore.hpp:1922
self_type & put(index_type inRowIndex, const Indices &inColIndices, const value_type &inValue)
Definition: NdArrayCore.hpp:3849
const_pointer data() const noexcept
Definition: NdArrayCore.hpp:2533
iterator end() noexcept
Definition: NdArrayCore.hpp:1566
NdArray(std::vector< dtype > &inVector, bool copy=true)
Definition: NdArrayCore.hpp:331
self_type & ones() noexcept
Definition: NdArrayCore.hpp:3410
self_type & put(index_type inIndex, const value_type &inValue)
Definition: NdArrayCore.hpp:3616
reference at(index_type inRowIndex, index_type inColIndex)
Definition: NdArrayCore.hpp:1011
self_type & resizeFast(const Shape &inShape)
Definition: NdArrayCore.hpp:4297
self_type & swapCols(index_type colIdx1, index_type colIdx2) noexcept
Definition: NdArrayCore.hpp:4563
self_type repeat(const Shape &inRepeatShape) const
Definition: NdArrayCore.hpp:4159
self_type at(Slice rowSlice, const Indices &colIndices) const
Definition: NdArrayCore.hpp:1199
std::vector< dtype > toStlVector() const
Definition: NdArrayCore.hpp:4705
reference back(size_type row)
Definition: NdArrayCore.hpp:2263
iterator end(size_type inRow)
Definition: NdArrayCore.hpp:1578
self_type column(size_type inColumn)
Definition: NdArrayCore.hpp:2355
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:923
void tofile(const std::string &inFilename, const char inSep) const
Definition: NdArrayCore.hpp:4619
const_column_iterator ccolbegin() const noexcept
Definition: NdArrayCore.hpp:1385
NdArray< size_type > argmin(Axis inAxis=Axis::NONE) const
Definition: NdArrayCore.hpp:2014
typename AllocTraits::pointer pointer
Definition: NdArrayCore.hpp:151
self_type transpose() const
Definition: NdArrayCore.hpp:4775
reverse_iterator rbegin(size_type inRow)
Definition: NdArrayCore.hpp:1424
self_type & ravel()
Definition: NdArrayCore.hpp:4102
Shape shape() const noexcept
Definition: NdArrayCore.hpp:4402
NdArray< size_type > toIndices(Slice inSlice, Axis inAxis=Axis::NONE) const
Definition: NdArrayCore.hpp:4656
const_reverse_column_iterator rcolend() const noexcept
Definition: NdArrayCore.hpp:1824
const dtype & const_reference
Definition: NdArrayCore.hpp:154
bool issquare() const noexcept
Definition: NdArrayCore.hpp:2932
bool isflat() const noexcept
Definition: NdArrayCore.hpp:2868
Endian endianess() const noexcept
Definition: NdArrayCore.hpp:2715
self_type dot(const self_type &inOtherArray) const
Definition: NdArrayCore.hpp:2642
void tofile(const std::string &inFilename) const
Definition: NdArrayCore.hpp:4602
const_reverse_column_iterator crcolbegin() const noexcept
Definition: NdArrayCore.hpp:1539
const_reverse_column_iterator crcolend(size_type inCol) const
Definition: NdArrayCore.hpp:1859
size_type numCols() const noexcept
Definition: NdArrayCore.hpp:3388
column_iterator colbegin(size_type inCol)
Definition: NdArrayCore.hpp:1347
NdArray< bool > none(Axis inAxis=Axis::NONE) const
Definition: NdArrayCore.hpp:3334
self_type median(Axis inAxis=Axis::NONE) const
Definition: NdArrayCore.hpp:3054
const_reference at(index_type inRowIndex, index_type inColIndex) const
Definition: NdArrayCore.hpp:1024
self_type at(const Slice &inSlice) const
Definition: NdArrayCore.hpp:1054
pointer data() noexcept
Definition: NdArrayCore.hpp:2523
bool isempty() const noexcept
Definition: NdArrayCore.hpp:2855
column_iterator colbegin() noexcept
Definition: NdArrayCore.hpp:1335
const_reference front(size_type row) const
Definition: NdArrayCore.hpp:2805
reverse_column_iterator rcolend(size_type inCol)
Definition: NdArrayCore.hpp:1809
self_type & put(const Slice &inRowSlice, const Slice &inColSlice, const value_type &inValue)
Definition: NdArrayCore.hpp:3797
self_type prod(Axis inAxis=Axis::NONE) const
Definition: NdArrayCore.hpp:3526
NdArray(Iterator inFirst, Iterator inLast)
Definition: NdArrayCore.hpp:487
reference at(index_type inIndex)
Definition: NdArrayCore.hpp:977
reverse_column_iterator rcolbegin() noexcept
Definition: NdArrayCore.hpp:1489
self_type & reshape(const Shape &inShape)
Definition: NdArrayCore.hpp:4267
self_type at(const Indices &inIndices) const
Definition: NdArrayCore.hpp:1084
const_iterator cbegin(size_type inRow) const
Definition: NdArrayCore.hpp:1320
const_column_iterator ccolend(size_type inCol) const
Definition: NdArrayCore.hpp:1782
self_type at(index_type rowIndex, const Indices &colIndices) const
Definition: NdArrayCore.hpp:1184
const_iterator cend(size_type inRow) const
Definition: NdArrayCore.hpp:1628
self_type & reshape(index_type inNumRows, index_type inNumCols)
Definition: NdArrayCore.hpp:4217
self_type getByIndices(const NdArray< size_type > &inIndices) const
Definition: NdArrayCore.hpp:2828
const_reverse_column_iterator rcolend(size_type inCol) const
Definition: NdArrayCore.hpp:1836
const_iterator end(size_type inRow) const
Definition: NdArrayCore.hpp:1605
self_type flatten() const
Definition: NdArrayCore.hpp:2770
reference back() noexcept
Definition: NdArrayCore.hpp:2241
const_reverse_column_iterator crcolend() const noexcept
Definition: NdArrayCore.hpp:1847
const_reference back(size_type row) const
Definition: NdArrayCore.hpp:2252
reverse_column_iterator rcolbegin(size_type inCol)
Definition: NdArrayCore.hpp:1501
NdArray(const std::deque< std::deque< dtype >> &in2dDeque)
Definition: NdArrayCore.hpp:435
iterator begin(size_type inRow)
Definition: NdArrayCore.hpp:1270
const_reverse_iterator rend() const noexcept
Definition: NdArrayCore.hpp:1670
self_type copy() const
Definition: NdArrayCore.hpp:2409
self_type round(uint8 inNumDecimals=0) const
Definition: NdArrayCore.hpp:4368
self_type swapaxes() const
Definition: NdArrayCore.hpp:4550
const_reverse_column_iterator rcolbegin(size_type inCol) const
Definition: NdArrayCore.hpp:1528
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:3781
const_iterator end() const noexcept
Definition: NdArrayCore.hpp:1593
bool ownsInternalData() noexcept
Definition: NdArrayCore.hpp:3424
self_type operator[](const NdArray< bool > &inMask) const
Definition: NdArrayCore.hpp:778
column_iterator colend() noexcept
Definition: NdArrayCore.hpp:1720
NdArray(std::initializer_list< dtype > inList)
Definition: NdArrayCore.hpp:221
self_type & operator=(self_type &&rhs) noexcept
Definition: NdArrayCore.hpp:674
self_type at(const Indices &rowIndices, Slice colSlice) const
Definition: NdArrayCore.hpp:1170
self_type & put(const Slice &inSlice, const self_type &inValues)
Definition: NdArrayCore.hpp:3717
const_reference back() const noexcept
Definition: NdArrayCore.hpp:2230
self_type & operator=(const self_type &rhs)
Definition: NdArrayCore.hpp:633
std::pair< NdArray< size_type >, NdArray< size_type > > nonzero() const
Definition: NdArrayCore.hpp:4860
self_type diagonal(index_type inOffset=0, Axis inAxis=Axis::ROW) const
Definition: NdArrayCore.hpp:2562
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:1126
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:3633
uint64 nbytes() const noexcept
Definition: NdArrayCore.hpp:3156
self_type & put(const RowIndices &inRowIndices, const ColIndices &inColIndices, const self_type &inValues)
Definition: NdArrayCore.hpp:3887
self_type & putMask(const NdArray< bool > &inMask, const self_type &inValues)
Definition: NdArrayCore.hpp:4075
self_type at(const NdArray< bool > &inMask) const
Definition: NdArrayCore.hpp:1066
NdArray(const std::list< dtype > &inList)
Definition: NdArrayCore.hpp:467
NdArray()=default
const_reference front() const noexcept
Definition: NdArrayCore.hpp:2783
~NdArray() noexcept
Definition: NdArrayCore.hpp:621
Slice rSlice(index_type inStartIdx=0, size_type inStepSize=1) const
Definition: NdArrayCore.hpp:965
reference front() noexcept
Definition: NdArrayCore.hpp:2794
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:3651
void print() const
Definition: NdArrayCore.hpp:3510
self_type & byteswap() noexcept
Definition: NdArrayCore.hpp:2276
const_reverse_column_iterator crcolbegin(size_type inCol) const
Definition: NdArrayCore.hpp:1551
self_type & put(const RowIndices &inRowIndices, const ColIndices &inColIndices, const value_type &inValue)
Definition: NdArrayCore.hpp:3737
size_type numRows() const noexcept
Definition: NdArrayCore.hpp:3400
reverse_iterator rend(size_type inRow)
Definition: NdArrayCore.hpp:1655
NdArray(size_type inSquareSize)
Definition: NdArrayCore.hpp:181
self_type at(const Indices &rowIndices, index_type colIndex) const
Definition: NdArrayCore.hpp:1155
reverse_iterator rend() noexcept
Definition: NdArrayCore.hpp:1643
const_reverse_iterator rend(size_type inRow) const
Definition: NdArrayCore.hpp:1682
typename AllocTraits::const_pointer const_pointer
Definition: NdArrayCore.hpp:152
const_reverse_iterator crbegin() const noexcept
Definition: NdArrayCore.hpp:1462
const_column_iterator colend(size_type inCol) const
Definition: NdArrayCore.hpp:1759
self_type & operator=(value_type inValue) noexcept
Definition: NdArrayCore.hpp:657
self_type & put(const RowIndices &inRowIndices, Slice inColSlice, const self_type &inValues)
Definition: NdArrayCore.hpp:3943
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:3831
self_type & put(Slice inRowSlice, const ColIndices &inColIndices, const self_type &inValues)
Definition: NdArrayCore.hpp:3960
NdArray(const std::vector< std::vector< dtype >> &in2dVector)
Definition: NdArrayCore.hpp:356
const_reverse_iterator rbegin(size_type inRow) const
Definition: NdArrayCore.hpp:1451
self_type operator[](const Indices &inIndices) const
Definition: NdArrayCore.hpp:792
const_iterator cend() const noexcept
Definition: NdArrayCore.hpp:1616
self_type & put(index_type inRowIndex, const Slice &inColSlice, const value_type &inValue)
Definition: NdArrayCore.hpp:3866
std::string str() const
Definition: NdArrayCore.hpp:4473
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:2475
self_type & put(Slice inRowSlice, Slice inColSlice, const self_type &inValues)
Definition: NdArrayCore.hpp:3976
reference front(size_type row)
Definition: NdArrayCore.hpp:2816
self_type & nans() noexcept
Definition: NdArrayCore.hpp:3139
self_type & partition(size_type inKth, Axis inAxis=Axis::NONE)
Definition: NdArrayCore.hpp:3444
self_type repeat(size_type inNumRows, size_type inNumCols) const
Definition: NdArrayCore.hpp:4118
NdArray< size_type > argmax(Axis inAxis=Axis::NONE) const
Definition: NdArrayCore.hpp:1967
NdArray(pointer inPtr, size_type numRows, size_type numCols, BoolType takeOwnership) noexcept
Definition: NdArrayCore.hpp:572
NdArray< size_type > flatnonzero() const
Definition: NdArrayCore.hpp:2744
const_iterator begin(size_type inRow) const
Definition: NdArrayCore.hpp:1297
iterator begin() noexcept
Definition: NdArrayCore.hpp:1258
self_type & put(const RowIndices &inRowIndices, const Slice &inColSlice, const value_type &inValue)
Definition: NdArrayCore.hpp:3764
const_column_iterator colbegin() const noexcept
Definition: NdArrayCore.hpp:1362
bool isscalar() const noexcept
Definition: NdArrayCore.hpp:2879
std::reverse_iterator< column_iterator > reverse_column_iterator
Definition: NdArrayCore.hpp:166
self_type operator()(Slice inRowSlice, Slice inColSlice) const
Definition: NdArrayCore.hpp:813
self_type newbyteorder(Endian inEndianess) const
Definition: NdArrayCore.hpp:3171
value_type item() const
Definition: NdArrayCore.hpp:2945
const_reference at(index_type inIndex) const
Definition: NdArrayCore.hpp:989
const_column_iterator colend() const noexcept
Definition: NdArrayCore.hpp:1747
self_type operator()(const Indices &rowIndices, index_type colIndex) const
Definition: NdArrayCore.hpp:858
self_type at(const Slice &inRowSlice, const Slice &inColSlice) const
Definition: NdArrayCore.hpp:1113
self_type operator()(Slice inRowSlice, index_type inColIndex) const
Definition: NdArrayCore.hpp:827
const_reverse_iterator crend() const noexcept
Definition: NdArrayCore.hpp:1693
self_type & sort(Axis inAxis=Axis::NONE)
Definition: NdArrayCore.hpp:4429
self_type operator()(index_type rowIndex, const Indices &colIndices) const
Definition: NdArrayCore.hpp:889
NdArray< dtype, Allocator > self_type
Definition: NdArrayCore.hpp:148
const_column_iterator colbegin(size_type inCol) const
Definition: NdArrayCore.hpp:1374
self_type cumprod(Axis inAxis=Axis::NONE) const
Definition: NdArrayCore.hpp:2423
NdArray< bool > contains(value_type inValue, Axis inAxis=Axis::NONE) const
Definition: NdArrayCore.hpp:2368
const_column_iterator ccolend() const noexcept
Definition: NdArrayCore.hpp:1770
reference operator()(index_type inRowIndex, index_type inColIndex) noexcept
Definition: NdArrayCore.hpp:730
self_type operator()(index_type inRowIndex, Slice inColSlice) const
Definition: NdArrayCore.hpp:842
reverse_column_iterator rcolend() noexcept
Definition: NdArrayCore.hpp:1797
NdArray(std::array< dtype, ArraySize > &inArray, bool copy=true)
Definition: NdArrayCore.hpp:274
const_reverse_iterator rbegin() const noexcept
Definition: NdArrayCore.hpp:1439
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:4171
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:3672
void dump(const std::string &inFilename) const
Definition: NdArrayCore.hpp:2688
dtype & reference
Definition: NdArrayCore.hpp:153
value_type trace(size_type inOffset=0, Axis inAxis=Axis::ROW) const noexcept
Definition: NdArrayCore.hpp:4722
pointer dataRelease() noexcept
Definition: NdArrayCore.hpp:2545
self_type ptp(Axis inAxis=Axis::NONE) const
Definition: NdArrayCore.hpp:3570
self_type & put(const Slice &inSlice, const value_type &inValue)
Definition: NdArrayCore.hpp:3702
self_type clip(value_type inMin, value_type inMax) const
Definition: NdArrayCore.hpp:2316
self_type getByMask(const NdArray< bool > &inMask) const
Definition: NdArrayCore.hpp:2842
self_type & swapRows(index_type rowIdx1, index_type rowIdx2) noexcept
Definition: NdArrayCore.hpp:4581
uint32 size_type
Definition: NdArrayCore.hpp:155
const_iterator begin() const noexcept
Definition: NdArrayCore.hpp:1285
column_iterator colend(size_type inCol)
Definition: NdArrayCore.hpp:1732
const_reference operator[](index_type inIndex) const noexcept
Definition: NdArrayCore.hpp:712
self_type operator()(Slice rowSlice, const Indices &colIndices) const
Definition: NdArrayCore.hpp:905
const_reference operator()(index_type inRowIndex, index_type inColIndex) const noexcept
Definition: NdArrayCore.hpp:743
self_type min(Axis inAxis=Axis::NONE) const
Definition: NdArrayCore.hpp:3008
dtype value_type
Definition: NdArrayCore.hpp:149
reference operator[](index_type inIndex) noexcept
Definition: NdArrayCore.hpp:700
Slice cSlice(index_type inStartIdx=0, size_type inStepSize=1) const
Definition: NdArrayCore.hpp:951
self_type & put(index_type inRowIndex, const Indices &inColIndices, const self_type &inValues)
Definition: NdArrayCore.hpp:4028
NdArray< size_type > argsort(Axis inAxis=Axis::NONE) const
Definition: NdArrayCore.hpp:2060
const_reverse_iterator crend(size_type inRow) const
Definition: NdArrayCore.hpp:1705
const_reverse_iterator crbegin(size_type inRow) const
Definition: NdArrayCore.hpp:1474
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:4509
self_type operator()(const Indices &rowIndices, Slice colSlice) const
Definition: NdArrayCore.hpp:874
NdArray< bool > all(Axis inAxis=Axis::NONE) const
Definition: NdArrayCore.hpp:1878
self_type & resizeSlow(size_type inNumRows, size_type inNumCols)
Definition: NdArrayCore.hpp:4314
self_type & resizeSlow(const Shape &inShape)
Definition: NdArrayCore.hpp:4353
self_type & putMask(const NdArray< bool > &inMask, const value_type &inValue)
Definition: NdArrayCore.hpp:4058
Custom iterator for NdArray.
Definition: NdArrayIterators.hpp:318
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: Constants.hpp:41
const double nan
NaN.
Definition: Constants.hpp:40
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: Coordinate.hpp:45
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