NumCpp  2.12.1
A Templatized Header Only C++ Implementation of the Python NumPy Library
NdArrayCore.hpp
Go to the documentation of this file.
1
28#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
50#include "NumCpp/Core/Enums.hpp"
57#include "NumCpp/Core/Shape.hpp"
58#include "NumCpp/Core/Slice.hpp"
59#include "NumCpp/Core/Types.hpp"
65#include "NumCpp/Utils/sqr.hpp"
67
68namespace nc
69{
70 namespace type_traits
71 {
72 //============================================================================
73 // Class Description:
76 template<typename>
77 struct is_ndarray_int : std::false_type
78 {
79 };
80
81 //============================================================================
82 // Class Description:
85
86 template<typename dtype, typename Allocator>
87 struct is_ndarray_int<NdArray<dtype, Allocator>>
88 {
89 static constexpr bool value = std::is_integral_v<dtype>;
90 };
91
92 //============================================================================
93 // Class Description:
96 template<typename T>
98
99 //============================================================================
100 // Class Description:
103 template<typename>
104 struct is_ndarray_signed_int : std::false_type
105 {
106 };
107
108 //============================================================================
109 // Class Description:
112
113 template<typename dtype, typename Allocator>
114 struct is_ndarray_signed_int<NdArray<dtype, Allocator>>
115 {
116 static constexpr bool value = std::is_signed_v<dtype>;
117 };
118
119 //============================================================================
120 // Class Description:
123 template<typename T>
125
126 //============================================================================
127 // Class Description:
130 template<typename T>
131 using ndarray_int_concept = std::enable_if_t<is_ndarray_int_v<T>, int>;
132 } // namespace type_traits
133
134 //================================================================================
135 // Class Description:
137 template<typename dtype, class Allocator = std::allocator<dtype>>
139 {
140 private:
141 STATIC_ASSERT_VALID_DTYPE(dtype);
142 static_assert(std::is_same_v<dtype, typename Allocator::value_type>,
143 "value_type and Allocator::value_type must match");
144
145 using AllocType = typename std::allocator_traits<Allocator>::template rebind_alloc<dtype>;
146 using AllocTraits = std::allocator_traits<AllocType>;
147
148 public:
150 using value_type = dtype;
151 using allocator_type = Allocator;
152 using pointer = typename AllocTraits::pointer;
153 using const_pointer = typename AllocTraits::const_pointer;
154 using reference = dtype&;
155 using const_reference = const dtype&;
158 using difference_type = typename AllocTraits::difference_type;
159
162 using reverse_iterator = std::reverse_iterator<iterator>;
163 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
164
167 using reverse_column_iterator = std::reverse_iterator<column_iterator>;
168 using const_reverse_column_iterator = std::reverse_iterator<const_column_iterator>;
169
170 //============================================================================
171 // Method Description:
174 NdArray() = default;
175
176 //============================================================================
177 // Method Description:
182 explicit NdArray(size_type inSquareSize) :
183 shape_{ inSquareSize, inSquareSize },
184 size_{ inSquareSize * inSquareSize }
185 {
186 newArray();
187 }
188
189 //============================================================================
190 // Method Description:
196 NdArray(size_type inNumRows, size_type inNumCols) :
197 shape_{ inNumRows, inNumCols },
198 size_{ inNumRows * inNumCols }
199 {
200 newArray();
201 }
202
203 //============================================================================
204 // Method Description:
209 explicit NdArray(const Shape& inShape) :
210 shape_{ inShape },
211 size_{ shape_.size() }
212 {
213 newArray();
214 }
215
216 //============================================================================
217 // Method Description:
222 NdArray(std::initializer_list<dtype> inList) :
223 shape_{ 1, static_cast<uint32>(inList.size()) },
224 size_{ shape_.size() }
225 {
226 newArray();
227 if (size_ > 0)
228 {
229 stl_algorithms::copy(inList.begin(), inList.end(), begin());
230 }
231 }
232
233 //============================================================================
234 // Method Description:
239 NdArray(const std::initializer_list<std::initializer_list<dtype>>& inList) :
240 shape_{ static_cast<uint32>(inList.size()), 0 }
241 {
242 for (const auto& list : inList)
243 {
244 if (shape_.cols == 0)
245 {
246 shape_.cols = static_cast<uint32>(list.size());
247 }
248 else if (list.size() != shape_.cols)
249 {
251 "All rows of the initializer list needs to have the same number of elements");
252 }
253 }
254
255 size_ = shape_.size();
256 newArray();
257 uint32 row = 0;
258 for (const auto& list : inList)
259 {
260 const auto ptr = begin() += row * shape_.cols;
261 stl_algorithms::copy(list.begin(), list.end(), ptr);
262 ++row;
263 }
264 }
265
266 //============================================================================
267 // 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, PointerPolicy policy = PointerPolicy::COPY) :
275 shape_{ 1, static_cast<uint32>(ArraySize) },
276 size_{ shape_.size() }
277 {
278 switch (policy)
279 {
281 {
282 newArray();
283 if (size_ > 0)
284 {
285 stl_algorithms::copy(inArray.begin(), inArray.end(), begin());
286 }
287 break;
288 }
290 {
291 array_ = inArray.data();
292 ownsPtr_ = false;
293 break;
294 }
295 default:
296 {
297 THROW_RUNTIME_ERROR("Unimplemented PointerPolicy type");
298 }
299 }
300 }
301
302 //============================================================================
303 // Method Description:
309 template<size_t Dim0Size, size_t Dim1Size>
310 NdArray(std::array<std::array<dtype, Dim1Size>, Dim0Size>& in2dArray,
312 shape_{ static_cast<uint32>(Dim0Size), static_cast<uint32>(Dim1Size) },
313 size_{ shape_.size() }
314 {
315 switch (policy)
316 {
318 {
319 newArray();
320 if (size_ > 0)
321 {
322 const auto start = in2dArray.front().begin();
323 stl_algorithms::copy(start, start + size_, begin());
324 }
325 break;
326 }
328 {
329 array_ = in2dArray.front().data();
330 ownsPtr_ = false;
331 break;
332 }
333 default:
334 {
335 THROW_RUNTIME_ERROR("Unimplemented PointerPolicy type");
336 }
337 }
338 }
339
340 //============================================================================
341 // Method Description:
347 template<std::enable_if_t<is_valid_dtype_v<dtype>, int> = 0>
348 NdArray(std::vector<dtype>& inVector, PointerPolicy policy = PointerPolicy::COPY) :
349 shape_{ 1, static_cast<uint32>(inVector.size()) },
350 size_{ shape_.size() }
351 {
352 switch (policy)
353 {
355 {
356 newArray();
357 if (size_ > 0)
358 {
359 stl_algorithms::copy(inVector.begin(), inVector.end(), begin());
360 }
361 break;
362 }
364 {
365 array_ = inVector.data();
366 ownsPtr_ = false;
367 break;
368 }
369 default:
370 {
371 THROW_RUNTIME_ERROR("Unimplemented PointerPolicy type");
372 }
373 }
374 }
375
376 //============================================================================
377 // Method Description:
382 explicit NdArray(const std::vector<std::vector<dtype>>& in2dVector) :
383 shape_{ static_cast<uint32>(in2dVector.size()), 0 }
384 {
385 for (const auto& row : in2dVector)
386 {
387 if (shape_.cols == 0)
388 {
389 shape_.cols = static_cast<uint32>(row.size());
390 }
391 else if (row.size() != shape_.cols)
392 {
393 THROW_INVALID_ARGUMENT_ERROR("All rows of the 2d vector need to have the same number of elements");
394 }
395 }
396
397 size_ = shape_.size();
398
399 newArray();
400 auto currentPosition = begin();
401 for (const auto& row : in2dVector)
402 {
403 stl_algorithms::copy(row.begin(), row.end(), currentPosition);
404 currentPosition += shape_.cols;
405 }
406 }
407
408 //============================================================================
409 // Method Description:
415 template<size_t Dim1Size>
416 NdArray(std::vector<std::array<dtype, Dim1Size>>& in2dArray, PointerPolicy policy = PointerPolicy::COPY) :
417 shape_{ static_cast<uint32>(in2dArray.size()), static_cast<uint32>(Dim1Size) },
418 size_{ shape_.size() }
419 {
420 switch (policy)
421 {
423 {
424 newArray();
425 if (size_ > 0)
426 {
427 const auto start = in2dArray.front().begin();
428 stl_algorithms::copy(start, start + size_, begin());
429 }
430 break;
431 }
433 {
434 array_ = in2dArray.front().data();
435 ownsPtr_ = false;
436 break;
437 }
438 default:
439 {
440 THROW_RUNTIME_ERROR("Unimplemented PointerPolicy type");
441 }
442 }
443 }
444
445 //============================================================================
446 // Method Description:
451 template<std::enable_if_t<is_valid_dtype_v<dtype>, int> = 0>
452 explicit NdArray(const std::deque<dtype>& inDeque) :
453 shape_{ 1, static_cast<uint32>(inDeque.size()) },
454 size_{ shape_.size() }
455 {
456 newArray();
457 if (size_ > 0)
458 {
459 stl_algorithms::copy(inDeque.begin(), inDeque.end(), begin());
460 }
461 }
462
463 //============================================================================
464 // Method Description:
469 explicit NdArray(const std::deque<std::deque<dtype>>& in2dDeque) :
470 shape_{ static_cast<uint32>(in2dDeque.size()), 0 }
471 {
472 for (const auto& row : in2dDeque)
473 {
474 if (shape_.cols == 0)
475 {
476 shape_.cols = static_cast<uint32>(row.size());
477 }
478 else if (row.size() != shape_.cols)
479 {
480 THROW_INVALID_ARGUMENT_ERROR("All rows of the 2d vector need to have the same number of elements");
481 }
482 }
483
484 size_ = shape_.size();
485
486 newArray();
487 auto currentPosition = begin();
488 for (const auto& row : in2dDeque)
489 {
490 stl_algorithms::copy(row.begin(), row.end(), currentPosition);
491 currentPosition += shape_.cols;
492 }
493 }
494
495 //============================================================================
496 // Method Description:
501 explicit NdArray(const std::list<dtype>& inList) :
502 shape_{ 1, static_cast<uint32>(inList.size()) },
503 size_{ shape_.size() }
504 {
505 newArray();
506 if (size_ > 0)
507 {
508 stl_algorithms::copy(inList.begin(), inList.end(), begin());
509 }
510 }
511
512 //============================================================================
513 // Method Description:
519 template<typename Iterator,
520 std::enable_if_t<std::is_same_v<typename std::iterator_traits<Iterator>::value_type, dtype>, int> = 0>
521 NdArray(Iterator inFirst, Iterator inLast) :
522 shape_{ 1, static_cast<uint32>(std::distance(inFirst, inLast)) },
523 size_{ shape_.size() }
524 {
525 newArray();
526 if (size_ > 0)
527 {
528 stl_algorithms::copy(inFirst, inLast, begin());
529 }
530 }
531
532 //============================================================================
533 // Method Description:
539 template<typename UIntType,
540 std::enable_if_t<std::is_integral_v<UIntType> && !std::is_same_v<UIntType, bool>, int> = 0>
541 NdArray(const_pointer inPtr, UIntType size) :
542 NdArray(inPtr, 1, size)
543 {
544 }
545
546 //============================================================================
547 // Method Description:
554 template<typename UIntType1,
555 typename UIntType2,
556 std::enable_if_t<std::is_integral_v<UIntType1> && !std::is_same_v<UIntType1, bool>, int> = 0,
557 std::enable_if_t<std::is_integral_v<UIntType2> && !std::is_same_v<UIntType2, bool>, int> = 0>
558 NdArray(const_pointer inPtr, UIntType1 numRows, UIntType2 numCols) :
559 shape_(numRows, numCols),
560 size_{ shape_.size() }
561 {
562 newArray();
563 if (inPtr != nullptr && size_ > 0)
564 {
565 stl_algorithms::copy(inPtr, inPtr + size_, begin());
566 }
567 }
568
569 //============================================================================
570 // Method Description:
578 template<typename UIntType,
579 std::enable_if_t<std::is_integral_v<UIntType> && !std::is_same_v<UIntType, bool>, int> = 0>
580 NdArray(pointer inPtr, UIntType size, PointerPolicy policy) :
581 NdArray(inPtr, 1, size, policy)
582 {
583 }
584
585 //============================================================================
586 // Method Description:
595 template<typename UIntType1,
596 typename UIntType2,
597 std::enable_if_t<std::is_integral_v<UIntType1> && !std::is_same_v<UIntType1, bool>, int> = 0,
598 std::enable_if_t<std::is_integral_v<UIntType2> && !std::is_same_v<UIntType2, bool>, int> = 0>
599 NdArray(pointer inPtr, UIntType1 numRows, UIntType2 numCols, PointerPolicy policy) :
600 shape_(numRows, numCols),
601 size_{ shape_.size() }
602 {
603 switch (policy)
604 {
606 {
607 newArray();
608 if (inPtr != nullptr && size_ > 0)
609 {
610 stl_algorithms::copy(inPtr, inPtr + size_, begin());
611 }
612 break;
613 }
615 {
616 array_ = inPtr;
617 ownsPtr_ = false;
618 break;
619 }
620 default:
621 {
622 THROW_RUNTIME_ERROR("Unimplemented PointerPolicy type");
623 }
624 }
625 }
626
627 //============================================================================
628 // Method Description:
633 NdArray(const self_type& inOtherArray) :
634 shape_{ inOtherArray.shape_ },
635 size_{ inOtherArray.size_ },
636 endianess_{ inOtherArray.endianess_ }
637 {
638 newArray();
639 if (size_ > 0)
640 {
641 stl_algorithms::copy(inOtherArray.cbegin(), inOtherArray.cend(), begin());
642 }
643 }
644
645 //============================================================================
646 // Method Description:
651 NdArray(self_type&& inOtherArray) noexcept :
652 shape_{ inOtherArray.shape_ },
653 size_{ inOtherArray.size_ },
654 endianess_{ inOtherArray.endianess_ },
655 array_{ inOtherArray.array_ },
656 ownsPtr_{ inOtherArray.ownsPtr_ }
657 {
658 inOtherArray.shape_.rows = inOtherArray.shape_.cols = 0;
659 inOtherArray.size_ = 0;
660 inOtherArray.ownsPtr_ = false;
661 inOtherArray.array_ = nullptr;
662 }
663
664 //============================================================================
665 // Method Description:
668 ~NdArray() noexcept
669 {
670 deleteArray();
671 }
672
673 //============================================================================
674 // Method Description:
678 explicit operator bool() const noexcept
679 {
680 return isempty();
681 }
682
683 //============================================================================
684 // Method Description:
691 {
692 if (&rhs != this)
693 {
694 if (rhs.size_ > 0)
695 {
696 newArray(rhs.shape_);
697 endianess_ = rhs.endianess_;
698
699 stl_algorithms::copy(rhs.cbegin(), rhs.cend(), begin());
700 }
701 }
702
703 return *this;
704 }
705
706 //============================================================================
707 // Method Description:
714 self_type& operator=(value_type inValue) noexcept
715 {
716 if (array_ != nullptr)
717 {
718 stl_algorithms::fill(begin(), end(), inValue);
719 }
720
721 return *this;
722 }
723
724 //============================================================================
725 // Method Description:
732 {
733 if (&rhs != this)
734 {
735 deleteArray();
736 shape_ = rhs.shape_;
737 size_ = rhs.size_;
738 endianess_ = rhs.endianess_;
739 array_ = rhs.array_;
740 ownsPtr_ = rhs.ownsPtr_;
741
742 rhs.shape_.rows = rhs.shape_.cols = rhs.size_ = 0;
743 rhs.array_ = nullptr;
744 rhs.ownsPtr_ = false;
745 }
746
747 return *this;
748 }
749
750 //============================================================================
751 // Method Description:
758 {
759 return const_cast<reference>(const_cast<const self_type*>(this)->operator[](inIndex));
760 }
761
762 //============================================================================
763 // Method Description:
769 [[nodiscard]] const_reference operator[](index_type inIndex) const noexcept
770 {
771 if (inIndex < 0)
772 {
773 inIndex += size_;
774 }
775
776 return array_[inIndex];
777 }
778
779 //============================================================================
780 // Method Description:
787 reference operator()(index_type inRowIndex, index_type inColIndex) noexcept
788 {
789 return const_cast<reference>(const_cast<const self_type*>(this)->operator()(inRowIndex, inColIndex));
790 }
791
792 //============================================================================
793 // Method Description:
800 [[nodiscard]] const_reference operator()(index_type inRowIndex, index_type inColIndex) const noexcept
801 {
802 if (inRowIndex < 0)
803 {
804 inRowIndex += shape_.rows;
805 }
806
807 if (inColIndex < 0)
808 {
809 inColIndex += shape_.cols;
810 }
811
812 return array_[inRowIndex * shape_.cols + inColIndex];
813 }
814
815 //============================================================================
816 // Method Description:
823 [[nodiscard]] self_type operator[](Slice inSlice) const
824 {
825 return operator[](toIndices(inSlice, Axis::NONE));
826 }
827
828 //============================================================================
829 // Method Description:
835 [[nodiscard]] self_type operator[](const NdArray<bool>& inMask) const
836 {
837 return operator[](inMask.flatnonzero());
838 }
839
840 //============================================================================
841 // Method Description:
848 template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
849 [[nodiscard]] self_type operator[](const Indices& inIndices) const
850 {
851 auto outArray = self_type(1, static_cast<size_type>(inIndices.size()));
852 size_type i = 0;
853 for (auto& index : inIndices)
854 {
855 outArray[i++] = operator[](static_cast<index_type>(index));
856 }
857
858 return outArray;
859 }
860
861 //============================================================================
862 // Method Description:
870 [[nodiscard]] self_type operator()(Slice inRowSlice, Slice inColSlice) const
871 {
872 return operator()(toIndices(inRowSlice, Axis::ROW), toIndices(inColSlice, Axis::COL));
873 }
874
875 //============================================================================
876 // Method Description:
884 [[nodiscard]] self_type operator()(Slice inRowSlice, index_type inColIndex) const
885 {
886 const NdArray<index_type> colIndices = { inColIndex };
887 return operator()(toIndices(inRowSlice, Axis::ROW), colIndices);
888 }
889
890 //============================================================================
891 // Method Description:
899 [[nodiscard]] self_type operator()(index_type inRowIndex, Slice inColSlice) const
900 {
901 const NdArray<index_type> rowIndices = { inRowIndex };
902 return operator()(rowIndices, toIndices(inColSlice, Axis::COL));
903 }
904
905 //============================================================================
906 // Method Description:
914 template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
915 [[nodiscard]] self_type operator()(const Indices& rowIndices, index_type colIndex) const
916 {
917 const NdArray<index_type> colIndices = { colIndex };
918 return operator()(rowIndices, colIndices);
919 }
920
921 //============================================================================
922 // Method Description:
930 template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
931 [[nodiscard]] self_type operator()(const Indices& rowIndices, Slice colSlice) const
932 {
933 return operator()(rowIndices, toIndices(colSlice, Axis::COL));
934 }
935
936 //============================================================================
937 // Method Description:
945 template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
946 [[nodiscard]] self_type operator()(index_type rowIndex, const Indices& colIndices) const
947 {
948 const NdArray<index_type> rowIndices = { rowIndex };
949 return operator()(rowIndices, colIndices);
950 }
951
952 //============================================================================
953 // Method Description:
961 template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
962 [[nodiscard]] self_type operator()(Slice rowSlice, const Indices& colIndices) const
963 {
964 return operator()(toIndices(rowSlice, Axis::ROW), colIndices);
965 }
966
967 //============================================================================
968 // Method Description:
976 template<typename RowIndices,
977 typename ColIndices,
980 [[nodiscard]] self_type operator()(const RowIndices& rowIndices, const ColIndices& colIndices) const
981 {
982 self_type returnArray(rowIndices.size(), colIndices.size());
983
984 size_type rowCounter = 0;
985 for (auto rowIter = rowIndices.begin(); rowIter != rowIndices.end(); ++rowIter)
986 {
987 size_type colCounter = 0;
988 for (auto colIter = colIndices.begin(); colIter != colIndices.end(); ++colIter)
989 {
990 returnArray(rowCounter, colCounter++) = operator()(*rowIter, *colIter);
991 }
992
993 ++rowCounter;
994 }
995
996 return returnArray;
997 }
998
999 //============================================================================
1000 // Method Description:
1008 [[nodiscard]] Slice cSlice(index_type inStartIdx = 0, size_type inStepSize = 1) const
1009 {
1010 return Slice(inStartIdx, shape_.cols, inStepSize); // NOLINT(modernize-return-braced-init-list)
1011 }
1012
1013 //============================================================================
1014 // Method Description:
1022 [[nodiscard]] Slice rSlice(index_type inStartIdx = 0, size_type inStepSize = 1) const
1023 {
1024 return Slice(inStartIdx, shape_.rows, inStepSize); // NOLINT(modernize-return-braced-init-list)
1025 }
1026
1027 //============================================================================
1028 // Method Description:
1035 {
1036 return const_cast<reference>(const_cast<const self_type*>(this)->at(inIndex));
1037 }
1038
1039 //============================================================================
1040 // Method Description:
1046 [[nodiscard]] const_reference at(index_type inIndex) const
1047 {
1048 // this doesn't allow for calling the first element as -size_...
1049 // but why would you really want to do that anyway?
1050 if (std::abs(inIndex) > static_cast<int64>(size_ - 1))
1051 {
1052 std::string errStr = "Input index " + utils::num2str(inIndex);
1053 errStr += " is out of bounds for array of size " + utils::num2str(size_) + ".";
1055 }
1056
1057 return operator[](inIndex); // cppcheck-suppress returnTempReference
1058 }
1059
1060 //============================================================================
1061 // Method Description:
1068 reference at(index_type inRowIndex, index_type inColIndex)
1069 {
1070 return const_cast<reference>(const_cast<const self_type*>(this)->at(inRowIndex, inColIndex));
1071 }
1072
1073 //============================================================================
1074 // Method Description:
1081 [[nodiscard]] const_reference at(index_type inRowIndex, index_type inColIndex) const
1082 {
1083 // this doesn't allow for calling the first element as -size_...
1084 // but why would you really want to do that anyway?
1085 if (std::abs(inRowIndex) > static_cast<index_type>(shape_.rows - 1))
1086 {
1087 std::string errStr = "Row index " + utils::num2str(inRowIndex);
1088 errStr += " is out of bounds for array of size " + utils::num2str(shape_.rows) + ".";
1090 }
1091
1092 // this doesn't allow for calling the first element as -size_...
1093 // but why would you really want to do that anyway?
1094 if (std::abs(inColIndex) > static_cast<index_type>(shape_.cols - 1))
1095 {
1096 std::string errStr = "Column index " + utils::num2str(inColIndex);
1097 errStr += " is out of bounds for array of size " + utils::num2str(shape_.cols) + ".";
1099 }
1100
1101 return operator()(inRowIndex, inColIndex); // cppcheck-suppress returnTempReference
1102 }
1103
1104 //============================================================================
1105 // Method Description:
1111 [[nodiscard]] self_type at(const Slice& inSlice) const
1112 {
1113 return at(toIndices(inSlice, Axis::NONE));
1114 }
1115
1116 //============================================================================
1117 // Method Description:
1123 [[nodiscard]] self_type at(const NdArray<bool>& inMask) const
1124 {
1125 if (inMask.shape() != shape_)
1126 {
1127 THROW_INVALID_ARGUMENT_ERROR("Input mask must have the same dimensions as array.");
1128 }
1129
1130 return operator[](inMask);
1131 }
1132
1133 //============================================================================
1134 // Method Description:
1140 template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
1141 [[nodiscard]] self_type at(const Indices& inIndices) const
1142 {
1143 stl_algorithms::for_each(inIndices.begin(),
1144 inIndices.end(),
1145 [this](auto index)
1146 {
1147 auto indexSigned = static_cast<index_type>(index);
1148 if (indexSigned < 0)
1149 {
1150 indexSigned += size_;
1151 }
1152
1153 if (indexSigned < 0 || indexSigned > static_cast<index_type>(size_ - 1))
1154 {
1155 THROW_INVALID_ARGUMENT_ERROR("Index exceeds matrix dimensions");
1156 }
1157 });
1158
1159 return operator[](inIndices);
1160 }
1161
1162 //============================================================================
1163 // Method Description:
1170 [[nodiscard]] self_type at(const Slice& inRowSlice, const Slice& inColSlice) const
1171 {
1172 return at(toIndices(inRowSlice, Axis::ROW), toIndices(inColSlice, Axis::COL));
1173 }
1174
1175 //============================================================================
1176 // Method Description:
1183 [[nodiscard]] self_type at(const Slice& inRowSlice, index_type inColIndex) const
1184 {
1185 const NdArray<index_type> colIndices = { inColIndex };
1186 return at(toIndices(inRowSlice, Axis::ROW), colIndices);
1187 }
1188
1189 //============================================================================
1190 // Method Description:
1197 [[nodiscard]] self_type at(index_type inRowIndex, const Slice& inColSlice) const
1198 {
1199 const NdArray<index_type> rowIndices = { inRowIndex };
1200 return at(rowIndices, toIndices(inColSlice, Axis::COL));
1201 }
1202
1203 //============================================================================
1204 // Method Description:
1211 template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
1212 [[nodiscard]] self_type at(const Indices& rowIndices, index_type colIndex) const
1213 {
1214 const NdArray<index_type> colIndices = { colIndex };
1215 return at(rowIndices, colIndices);
1216 }
1217
1218 //============================================================================
1219 // Method Description:
1226 template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
1227 [[nodiscard]] self_type at(const Indices& rowIndices, Slice colSlice) const
1228 {
1229 return at(rowIndices, toIndices(colSlice, Axis::COL));
1230 }
1231
1232 //============================================================================
1233 // Method Description:
1240 template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
1241 [[nodiscard]] self_type at(index_type rowIndex, const Indices& colIndices) const
1242 {
1243 const NdArray<index_type> rowIndices = { rowIndex };
1244 return at(rowIndices, colIndices);
1245 }
1246
1247 //============================================================================
1248 // Method Description:
1255 template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
1256 [[nodiscard]] self_type at(Slice rowSlice, const Indices& colIndices) const
1257 {
1258 return at(toIndices(rowSlice, Axis::ROW), colIndices);
1259 }
1260
1261 //============================================================================
1262 // Method Description:
1269 template<typename RowIndices,
1270 typename ColIndices,
1273 [[nodiscard]] self_type at(const RowIndices& rowIndices, const ColIndices& colIndices) const
1274 {
1275 stl_algorithms::for_each(rowIndices.begin(),
1276 rowIndices.end(),
1277 [this](auto row)
1278 {
1279 auto rowSigned = static_cast<index_type>(row);
1280 if (rowSigned < 0)
1281 {
1282 rowSigned += shape_.rows;
1283 }
1284
1285 if (rowSigned < 0 || rowSigned > static_cast<index_type>(shape_.rows - 1))
1286 {
1287 THROW_INVALID_ARGUMENT_ERROR("Row index exceeds matrix dimensions");
1288 }
1289 });
1290
1291 stl_algorithms::for_each(colIndices.begin(),
1292 colIndices.end(),
1293 [this](auto col)
1294 {
1295 auto colSigned = static_cast<index_type>(col);
1296 if (colSigned < 0)
1297 {
1298 colSigned += shape_.cols;
1299 }
1300
1301 if (colSigned < 0 || colSigned > static_cast<index_type>(shape_.cols - 1))
1302 {
1303 THROW_INVALID_ARGUMENT_ERROR("Column index exceeds matrix dimensions");
1304 }
1305 });
1306
1307 return operator()(rowIndices, colIndices);
1308 }
1309
1310 //============================================================================
1311 // Method Description:
1315 [[nodiscard]] iterator begin() noexcept
1316 {
1317 return iterator(array_);
1318 }
1319
1320 //============================================================================
1321 // Method Description:
1327 [[nodiscard]] iterator begin(size_type inRow)
1328 {
1329 if (inRow >= shape_.rows)
1330 {
1331 THROW_INVALID_ARGUMENT_ERROR("input row is greater than the number of rows in the array.");
1332 }
1333
1334 return begin() += (inRow * shape_.cols);
1335 }
1336
1337 //============================================================================
1338 // Method Description:
1342 [[nodiscard]] const_iterator begin() const noexcept
1343 {
1344 return cbegin();
1345 }
1346
1347 //============================================================================
1348 // Method Description:
1354 [[nodiscard]] const_iterator begin(size_type inRow) const
1355 {
1356 return cbegin(inRow);
1357 }
1358
1359 //============================================================================
1360 // Method Description:
1365 [[nodiscard]] const_iterator cbegin() const noexcept
1366 {
1367 return const_iterator(array_);
1368 }
1369
1370 //============================================================================
1371 // Method Description:
1377 [[nodiscard]] const_iterator cbegin(size_type inRow) const
1378 {
1379 if (inRow >= shape_.rows)
1380 {
1381 THROW_INVALID_ARGUMENT_ERROR("input row is greater than the number of rows in the array.");
1382 }
1383
1384 return cbegin() += (inRow * shape_.cols);
1385 }
1386
1387 //============================================================================
1388 // Method Description:
1392 [[nodiscard]] column_iterator colbegin() noexcept
1393 {
1394 return column_iterator(array_, shape_.rows, shape_.cols);
1395 }
1396
1397 //============================================================================
1398 // Method Description:
1405 {
1406 if (inCol >= shape_.cols)
1407 {
1408 THROW_INVALID_ARGUMENT_ERROR("input col is greater than the number of cols in the array.");
1409 }
1410
1411 return colbegin() += (inCol * shape_.rows);
1412 }
1413
1414 //============================================================================
1415 // Method Description:
1419 [[nodiscard]] const_column_iterator colbegin() const noexcept
1420 {
1421 return ccolbegin();
1422 }
1423
1424 //============================================================================
1425 // Method Description:
1431 [[nodiscard]] const_column_iterator colbegin(size_type inCol) const
1432 {
1433 return ccolbegin(inCol);
1434 }
1435
1436 //============================================================================
1437 // Method Description:
1442 [[nodiscard]] const_column_iterator ccolbegin() const noexcept
1443 {
1444 return const_column_iterator(array_, shape_.rows, shape_.cols);
1445 }
1446
1447 //============================================================================
1448 // Method Description:
1454 [[nodiscard]] const_column_iterator ccolbegin(size_type inCol) const
1455 {
1456 if (inCol >= shape_.cols)
1457 {
1458 THROW_INVALID_ARGUMENT_ERROR("input col is greater than the number of cols in the array.");
1459 }
1460
1461 return ccolbegin() += (inCol * shape_.rows);
1462 }
1463
1464 //============================================================================
1465 // Method Description:
1469 [[nodiscard]] reverse_iterator rbegin() noexcept
1470 {
1471 return reverse_iterator(end());
1472 }
1473
1474 //============================================================================
1475 // Method Description:
1481 [[nodiscard]] reverse_iterator rbegin(size_type inRow)
1482 {
1483 if (inRow >= shape_.rows)
1484 {
1485 THROW_INVALID_ARGUMENT_ERROR("input row is greater than the number of rows in the array.");
1486 }
1487
1488 return rbegin() += (shape_.rows - inRow - 1) * shape_.cols;
1489 }
1490
1491 //============================================================================
1492 // Method Description:
1496 [[nodiscard]] const_reverse_iterator rbegin() const noexcept
1497 {
1498 return crbegin();
1499 }
1500
1501 //============================================================================
1502 // Method Description:
1508 [[nodiscard]] const_reverse_iterator rbegin(size_type inRow) const
1509 {
1510 return crbegin(inRow);
1511 }
1512
1513 //============================================================================
1514 // Method Description:
1519 [[nodiscard]] const_reverse_iterator crbegin() const noexcept
1520 {
1521 return const_reverse_iterator(cend());
1522 }
1523
1524 //============================================================================
1525 // Method Description:
1531 [[nodiscard]] const_reverse_iterator crbegin(size_type inRow) const
1532 {
1533 if (inRow >= shape_.rows)
1534 {
1535 THROW_INVALID_ARGUMENT_ERROR("input row is greater than the number of rows in the array.");
1536 }
1537
1538 return crbegin() += (shape_.rows - inRow - 1) * shape_.cols;
1539 }
1540
1541 //============================================================================
1542 // Method Description:
1546 [[nodiscard]] reverse_column_iterator rcolbegin() noexcept
1547 {
1548 return reverse_column_iterator(colend());
1549 }
1550
1551 //============================================================================
1552 // Method Description:
1559 {
1560 if (inCol >= shape_.cols)
1561 {
1562 THROW_INVALID_ARGUMENT_ERROR("input col is greater than the number of cols in the array.");
1563 }
1564
1565 return rcolbegin() += (shape_.cols - inCol - 1) * shape_.rows;
1566 }
1567
1568 //============================================================================
1569 // Method Description:
1573 [[nodiscard]] const_reverse_column_iterator rcolbegin() const noexcept
1574 {
1575 return crcolbegin();
1576 }
1577
1578 //============================================================================
1579 // Method Description:
1586 {
1587 return crcolbegin(inCol);
1588 }
1589
1590 //============================================================================
1591 // Method Description:
1596 [[nodiscard]] const_reverse_column_iterator crcolbegin() const noexcept
1597 {
1598 return const_reverse_column_iterator(ccolend());
1599 }
1600
1601 //============================================================================
1602 // Method Description:
1609 {
1610 if (inCol >= shape_.cols)
1611 {
1612 THROW_INVALID_ARGUMENT_ERROR("input col is greater than the number of cols in the array.");
1613 }
1614
1615 return crcolbegin() += (shape_.cols - inCol - 1) * shape_.rows;
1616 }
1617
1618 //============================================================================
1619 // Method Description:
1623 [[nodiscard]] iterator end() noexcept
1624 {
1625 return begin() += size_;
1626 }
1627
1628 //============================================================================
1629 // Method Description:
1635 [[nodiscard]] iterator end(size_type inRow)
1636 {
1637 if (inRow >= shape_.rows)
1638 {
1639 THROW_INVALID_ARGUMENT_ERROR("input row is greater than the number of rows in the array.");
1640 }
1641
1642 return begin(inRow) += shape_.cols;
1643 }
1644
1645 //============================================================================
1646 // Method Description:
1650 [[nodiscard]] const_iterator end() const noexcept
1651 {
1652 return cend();
1653 }
1654
1655 //============================================================================
1656 // Method Description:
1662 [[nodiscard]] const_iterator end(size_type inRow) const
1663 {
1664 return cend(inRow);
1665 }
1666
1667 //============================================================================
1668 // Method Description:
1673 [[nodiscard]] const_iterator cend() const noexcept
1674 {
1675 return cbegin() += size_;
1676 }
1677
1678 //============================================================================
1679 // Method Description:
1685 [[nodiscard]] const_iterator cend(size_type inRow) const
1686 {
1687 if (inRow >= shape_.rows)
1688 {
1689 THROW_INVALID_ARGUMENT_ERROR("input row is greater than the number of rows in the array.");
1690 }
1691
1692 return cbegin(inRow) += shape_.cols;
1693 }
1694
1695 //============================================================================
1696 // Method Description:
1700 [[nodiscard]] reverse_iterator rend() noexcept
1701 {
1702 return rbegin() += size_;
1703 }
1704
1705 //============================================================================
1706 // Method Description:
1712 [[nodiscard]] reverse_iterator rend(size_type inRow)
1713 {
1714 if (inRow >= shape_.rows)
1715 {
1716 THROW_INVALID_ARGUMENT_ERROR("input row is greater than the number of rows in the array.");
1717 }
1718
1719 return rbegin(inRow) += shape_.cols;
1720 }
1721
1722 //============================================================================
1723 // Method Description:
1727 [[nodiscard]] const_reverse_iterator rend() const noexcept
1728 {
1729 return crend();
1730 }
1731
1732 //============================================================================
1733 // Method Description:
1739 [[nodiscard]] const_reverse_iterator rend(size_type inRow) const
1740 {
1741 return crend(inRow);
1742 }
1743
1744 //============================================================================
1745 // Method Description:
1750 [[nodiscard]] const_reverse_iterator crend() const noexcept
1751 {
1752 return crbegin() += size_;
1753 }
1754
1755 //============================================================================
1756 // Method Description:
1762 [[nodiscard]] const_reverse_iterator crend(size_type inRow) const
1763 {
1764 if (inRow >= shape_.rows)
1765 {
1766 THROW_INVALID_ARGUMENT_ERROR("input row is greater than the number of rows in the array.");
1767 }
1768
1769 return crbegin(inRow) += shape_.cols;
1770 }
1771
1772 //============================================================================
1773 // Method Description:
1777 [[nodiscard]] column_iterator colend() noexcept
1778 {
1779 return colbegin() += size_;
1780 }
1781
1782 //============================================================================
1783 // Method Description:
1789 [[nodiscard]] column_iterator colend(size_type inCol)
1790 {
1791 if (inCol >= shape_.cols)
1792 {
1793 THROW_INVALID_ARGUMENT_ERROR("input col is greater than the number of cols in the array.");
1794 }
1795
1796 return colbegin(inCol) += shape_.rows;
1797 }
1798
1799 //============================================================================
1800 // Method Description:
1804 [[nodiscard]] const_column_iterator colend() const noexcept
1805 {
1806 return ccolend();
1807 }
1808
1809 //============================================================================
1810 // Method Description:
1816 [[nodiscard]] const_column_iterator colend(size_type inCol) const
1817 {
1818 return ccolend(inCol);
1819 }
1820
1821 //============================================================================
1822 // Method Description:
1827 [[nodiscard]] const_column_iterator ccolend() const noexcept
1828 {
1829 return ccolbegin() += size_;
1830 }
1831
1832 //============================================================================
1833 // Method Description:
1839 [[nodiscard]] const_column_iterator ccolend(size_type inCol) const
1840 {
1841 if (inCol >= shape_.cols)
1842 {
1843 THROW_INVALID_ARGUMENT_ERROR("input col is greater than the number of cols in the array.");
1844 }
1845
1846 return ccolbegin(inCol) += shape_.rows;
1847 }
1848
1849 //============================================================================
1850 // Method Description:
1854 [[nodiscard]] reverse_column_iterator rcolend() noexcept
1855 {
1856 return rcolbegin() += size_;
1857 }
1858
1859 //============================================================================
1860 // Method Description:
1867 {
1868 if (inCol >= shape_.cols)
1869 {
1870 THROW_INVALID_ARGUMENT_ERROR("input col is greater than the number of cols in the array.");
1871 }
1872
1873 return rcolbegin(inCol) += shape_.rows;
1874 }
1875
1876 //============================================================================
1877 // Method Description:
1881 [[nodiscard]] const_reverse_column_iterator rcolend() const noexcept
1882 {
1883 return crcolend();
1884 }
1885
1886 //============================================================================
1887 // Method Description:
1894 {
1895 return crcolend(inCol);
1896 }
1897
1898 //============================================================================
1899 // Method Description:
1904 [[nodiscard]] const_reverse_column_iterator crcolend() const noexcept
1905 {
1906 return crcolbegin() += size_;
1907 }
1908
1909 //============================================================================
1910 // Method Description:
1917 {
1918 if (inCol >= shape_.cols)
1919 {
1920 THROW_INVALID_ARGUMENT_ERROR("input col is greater than the number of cols in the array.");
1921 }
1922
1923 return crcolbegin(inCol) += shape_.rows;
1924 }
1925
1926 //============================================================================
1927 // Method Description:
1935 [[nodiscard]] NdArray<bool> all(Axis inAxis = Axis::NONE) const
1936 {
1938
1939 const auto function = [](dtype i) -> bool { return !utils::essentiallyEqual(i, dtype{ 0 }); };
1940
1941 switch (inAxis)
1942 {
1943 case Axis::NONE:
1944 {
1945 NdArray<bool> returnArray = { stl_algorithms::all_of(cbegin(), cend(), function) };
1946 return returnArray;
1947 }
1948 case Axis::COL:
1949 {
1950 NdArray<bool> returnArray(1, shape_.rows);
1951 for (uint32 row = 0; row < shape_.rows; ++row)
1952 {
1953 returnArray(0, row) = stl_algorithms::all_of(cbegin(row), cend(row), function);
1954 }
1955
1956 return returnArray;
1957 }
1958 case Axis::ROW:
1959 {
1960 return transpose().all(Axis::COL);
1961 }
1962 default:
1963 {
1964 THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
1965 return {}; // get rid of compiler warning
1966 }
1967 }
1968 }
1969
1970 //============================================================================
1971 // Method Description:
1979 [[nodiscard]] NdArray<bool> any(Axis inAxis = Axis::NONE) const
1980 {
1982
1983 const auto function = [](dtype i) -> bool { return !utils::essentiallyEqual(i, dtype{ 0 }); };
1984
1985 switch (inAxis)
1986 {
1987 case Axis::NONE:
1988 {
1989 NdArray<bool> returnArray = { stl_algorithms::any_of(cbegin(), cend(), function) };
1990 return returnArray;
1991 }
1992 case Axis::COL:
1993 {
1994 NdArray<bool> returnArray(1, shape_.rows);
1995 for (uint32 row = 0; row < shape_.rows; ++row)
1996 {
1997 returnArray(0, row) = stl_algorithms::any_of(cbegin(row), cend(row), function);
1998 }
1999
2000 return returnArray;
2001 }
2002 case Axis::ROW:
2003 {
2004 return transpose().any(Axis::COL);
2005 }
2006 default:
2007 {
2008 THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
2009 return {}; // get rid of compiler warning
2010 }
2011 }
2012 }
2013
2014 //============================================================================
2015 // Method Description:
2024 [[nodiscard]] NdArray<size_type> argmax(Axis inAxis = Axis::NONE) const
2025 {
2027
2028 const auto comparitor = [](dtype lhs, dtype rhs) noexcept -> bool { return lhs < rhs; };
2029
2030 switch (inAxis)
2031 {
2032 case Axis::NONE:
2033 {
2034 NdArray<size_type> returnArray = { static_cast<size_type>(
2035 stl_algorithms::max_element(cbegin(), cend(), comparitor) - cbegin()) };
2036 return returnArray;
2037 }
2038 case Axis::COL:
2039 {
2040 NdArray<size_type> returnArray(1, shape_.rows);
2041 for (size_type row = 0; row < shape_.rows; ++row)
2042 {
2043 returnArray(0, row) = static_cast<size_type>(
2044 stl_algorithms::max_element(cbegin(row), cend(row), comparitor) - cbegin(row));
2045 }
2046
2047 return returnArray;
2048 }
2049 case Axis::ROW:
2050 {
2051 return transpose().argmax(Axis::COL);
2052 }
2053 default:
2054 {
2055 THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
2056 return {}; // get rid of compiler warning
2057 }
2058 }
2059 }
2060
2061 //============================================================================
2062 // Method Description:
2071 [[nodiscard]] NdArray<size_type> argmin(Axis inAxis = Axis::NONE) const
2072 {
2074
2075 const auto comparitor = [](dtype lhs, dtype rhs) noexcept -> bool { return lhs < rhs; };
2076
2077 switch (inAxis)
2078 {
2079 case Axis::NONE:
2080 {
2081 NdArray<size_type> returnArray = { static_cast<size_type>(
2082 stl_algorithms::min_element(cbegin(), cend(), comparitor) - cbegin()) };
2083 return returnArray;
2084 }
2085 case Axis::COL:
2086 {
2087 NdArray<size_type> returnArray(1, shape_.rows);
2088 for (size_type row = 0; row < shape_.rows; ++row)
2089 {
2090 returnArray(0, row) = static_cast<size_type>(
2091 stl_algorithms::min_element(cbegin(row), cend(row), comparitor) - cbegin(row));
2092 }
2093
2094 return returnArray;
2095 }
2096 case Axis::ROW:
2097 {
2098 return transpose().argmin(Axis::COL);
2099 }
2100 default:
2101 {
2102 THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
2103 return {}; // get rid of compiler warning
2104 }
2105 }
2106 }
2107
2108 //============================================================================
2109 // Method Description:
2117 [[nodiscard]] NdArray<size_type> argsort(Axis inAxis = Axis::NONE) const
2118 {
2120
2121 switch (inAxis)
2122 {
2123 case Axis::NONE:
2124 {
2125 std::vector<size_type> idx(size_);
2126 std::iota(idx.begin(), idx.end(), 0);
2127
2128 const auto function = [this](size_type i1, size_type i2) noexcept -> bool
2129 { return (*this)[i1] < (*this)[i2]; };
2130
2131 stl_algorithms::stable_sort(idx.begin(), idx.end(), function);
2132 return NdArray<size_type>(idx); // NOLINT(modernize-return-braced-init-list)
2133 }
2134 case Axis::COL:
2135 {
2136 NdArray<size_type> returnArray(shape_);
2137 std::vector<size_type> idx(shape_.cols);
2138
2139 for (index_type row = 0; row < static_cast<index_type>(shape_.rows); ++row)
2140 {
2141 std::iota(idx.begin(), idx.end(), 0);
2142
2143 const auto function = [this, row](size_type i1, size_type i2) noexcept -> bool
2144 { return operator()(row, i1) < operator()(row, i2); };
2145
2146 stl_algorithms::stable_sort(idx.begin(), idx.end(), function);
2147
2148 for (index_type col = 0; col < static_cast<index_type>(shape_.cols); ++col)
2149 {
2150 returnArray(row, col) = idx[static_cast<size_type>(col)];
2151 }
2152 }
2153 return returnArray;
2154 }
2155 case Axis::ROW:
2156 {
2157 return transpose().argsort(Axis::COL).transpose();
2158 }
2159 default:
2160 {
2161 THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
2162 return {}; // get rid of compiler warning
2163 }
2164 }
2165 }
2166
2167 //============================================================================
2168 // Method Description:
2176 template<typename dtypeOut,
2177 typename dtype_ = dtype,
2178 std::enable_if_t<std::is_same_v<dtype_, dtype>, int> = 0,
2179 std::enable_if_t<std::is_arithmetic_v<dtype_>, int> = 0,
2180 std::enable_if_t<std::is_arithmetic_v<dtypeOut>, int> = 0>
2181 [[nodiscard]] NdArray<dtypeOut> astype() const
2182 {
2183 if constexpr (std::is_same_v<dtypeOut, dtype>)
2184 {
2185 return *this;
2186 }
2187 else
2188 {
2189 NdArray<dtypeOut> outArray(shape_);
2191 cend(),
2192 outArray.begin(),
2193 [](dtype value) -> dtypeOut { return static_cast<dtypeOut>(value); });
2194
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<std::is_arithmetic_v<dtype_>, int> = 0,
2212 std::enable_if_t<is_complex_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
2218 { return std::complex<typename dtypeOut::value_type>(value); };
2219
2220 stl_algorithms::transform(cbegin(), cend(), outArray.begin(), function);
2221
2222 return outArray;
2223 }
2224
2225 //============================================================================
2226 // Method Description:
2234 template<typename dtypeOut,
2235 typename dtype_ = dtype,
2236 std::enable_if_t<std::is_same_v<dtype_, dtype>, int> = 0,
2237 std::enable_if_t<is_complex_v<dtype_>, int> = 0,
2238 std::enable_if_t<is_complex_v<dtypeOut>, int> = 0>
2239 [[nodiscard]] NdArray<dtypeOut> astype() const
2240 {
2241 if constexpr (std::is_same_v<dtypeOut, dtype>)
2242 {
2243 return *this;
2244 }
2245 else
2246 {
2247 const auto function = [](const_reference value) noexcept -> dtypeOut
2248 { return complex_cast<typename dtypeOut::value_type>(value); };
2249
2250 NdArray<dtypeOut> outArray(shape_);
2251 stl_algorithms::transform(cbegin(), cend(), outArray.begin(), function);
2252 return outArray;
2253 }
2254 }
2255
2256 //============================================================================
2257 // Method Description:
2265 template<typename dtypeOut,
2266 typename dtype_ = dtype,
2267 std::enable_if_t<std::is_same_v<dtype_, dtype>, int> = 0,
2268 std::enable_if_t<is_complex_v<dtype_>, int> = 0,
2269 std::enable_if_t<std::is_arithmetic_v<dtypeOut>, int> = 0>
2270 [[nodiscard]] NdArray<dtypeOut> astype() const
2271 {
2272 NdArray<dtypeOut> outArray(shape_);
2273
2274 const auto function = [](const_reference value) -> dtypeOut { return static_cast<dtypeOut>(value.real()); };
2275
2276 stl_algorithms::transform(cbegin(), cend(), outArray.begin(), function);
2277
2278 return outArray;
2279 }
2280
2281 //============================================================================
2282 // Method Description:
2287 [[nodiscard]] const_reference back() const noexcept
2288 {
2289 return *(cend() - 1);
2290 }
2291
2292 //============================================================================
2293 // Method Description:
2298 reference back() noexcept
2299 {
2300 return *(end() - 1);
2301 }
2302
2303 //============================================================================
2304 // Method Description:
2309 [[nodiscard]] const_reference back(size_type row) const
2310 {
2311 return *(cend(row) - 1);
2312 }
2313
2314 //============================================================================
2315 // Method Description:
2321 {
2322 return *(end(row) - 1);
2323 }
2324
2325 //============================================================================
2326 // Method Description:
2334 {
2335 STATIC_ASSERT_INTEGER(dtype);
2336
2338 end(),
2339 [](dtype& value) noexcept -> void { value = endian::byteSwap(value); });
2340
2341 switch (endianess_)
2342 {
2343 case Endian::NATIVE:
2344 {
2345 endianess_ = endian::isLittleEndian() ? Endian::BIG : Endian::LITTLE;
2346 break;
2347 }
2348 case Endian::LITTLE:
2349 {
2350 endianess_ = Endian::BIG;
2351 break;
2352 }
2353 case Endian::BIG:
2354 {
2355 endianess_ = Endian::LITTLE;
2356 break;
2357 }
2358 }
2359
2360 return *this;
2361 }
2362
2363 //============================================================================
2364 // Method Description:
2373 [[nodiscard]] self_type clip(value_type inMin, value_type inMax) const
2374 {
2376
2377 self_type outArray(shape_);
2379 cend(),
2380 outArray.begin(),
2381 [inMin, inMax](dtype value) noexcept -> dtype
2382 {
2383#ifdef __cpp_lib_clamp
2384 const auto comparitor = [](dtype lhs, dtype rhs) noexcept -> bool
2385 { return lhs < rhs; };
2386
2387 return std::clamp(value, inMin, inMax, comparitor);
2388#else
2389 if (value < inMin)
2390 {
2391 return inMin;
2392 }
2393 else if (value > inMax)
2394 {
2395 return inMax;
2396 }
2397
2398 return value;
2399#endif
2400 });
2401
2402 return outArray;
2403 }
2404
2405 //============================================================================
2406 // Method Description:
2412 [[nodiscard]] self_type column(size_type inColumn) const
2413 {
2414 return operator()(rSlice(), inColumn);
2415 }
2416
2417 //============================================================================
2418 // Method Description:
2424 [[nodiscard]] self_type columns(const NdArray<size_type>& inCols) const
2425 {
2426 auto returnArray = self_type(shape_.rows, inCols.size());
2427 const auto rSlice = returnArray.rSlice();
2428
2429 for (size_type i = 0; i < inCols.size(); ++i)
2430 {
2431 returnArray.put(rSlice, i, column(inCols[i]));
2432 }
2433
2434 return returnArray;
2435 }
2436
2437 //============================================================================
2438 // Method Description:
2445 [[nodiscard]] NdArray<bool> contains(value_type inValue, Axis inAxis = Axis::NONE) const
2446 {
2448
2449 switch (inAxis)
2450 {
2451 case Axis::NONE:
2452 {
2453 NdArray<bool> returnArray = { stl_algorithms::find(cbegin(), cend(), inValue) != cend() };
2454 return returnArray;
2455 }
2456 case Axis::COL:
2457 {
2458 NdArray<bool> returnArray(1, shape_.rows);
2459 for (size_type row = 0; row < shape_.rows; ++row)
2460 {
2461 returnArray(0, row) = stl_algorithms::find(cbegin(row), cend(row), inValue) != cend(row);
2462 }
2463
2464 return returnArray;
2465 }
2466 case Axis::ROW:
2467 {
2468 return transpose().contains(inValue, Axis::COL);
2469 }
2470 default:
2471 {
2472 THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
2473 return {}; // get rid of compiler warning
2474 }
2475 }
2476 }
2477
2478 //============================================================================
2479 // Method Description:
2486 [[nodiscard]] self_type copy() const
2487 {
2488 return self_type(*this);
2489 }
2490
2491 //============================================================================
2492 // Method Description:
2500 [[nodiscard]] self_type cumprod(Axis inAxis = Axis::NONE) const
2501 {
2503
2504 switch (inAxis)
2505 {
2506 case Axis::NONE:
2507 {
2508 self_type returnArray(1, size_);
2509 returnArray[0] = front();
2510 for (size_type i = 1; i < size_; ++i)
2511 {
2512 returnArray[i] = returnArray[i - 1] * array_[i];
2513 }
2514
2515 return returnArray;
2516 }
2517 case Axis::COL:
2518 {
2519 self_type returnArray(shape_);
2520 for (uint32 row = 0; row < shape_.rows; ++row)
2521 {
2522 returnArray(row, 0) = operator()(row, 0);
2523 for (uint32 col = 1; col < shape_.cols; ++col)
2524 {
2525 returnArray(row, col) = returnArray(row, col - 1) * operator()(row, col);
2526 }
2527 }
2528
2529 return returnArray;
2530 }
2531 case Axis::ROW:
2532 {
2533 return transpose().cumprod(Axis::COL).transpose();
2534 }
2535 default:
2536 {
2537 THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
2538 return {}; // get rid of compiler warning
2539 }
2540 }
2541 }
2542
2543 //============================================================================
2544 // Method Description:
2552 [[nodiscard]] self_type cumsum(Axis inAxis = Axis::NONE) const
2553 {
2555
2556 switch (inAxis)
2557 {
2558 case Axis::NONE:
2559 {
2560 self_type returnArray(1, size_);
2561 returnArray[0] = front();
2562 for (size_type i = 1; i < size_; ++i)
2563 {
2564 returnArray[i] = returnArray[i - 1] + array_[i];
2565 }
2566
2567 return returnArray;
2568 }
2569 case Axis::COL:
2570 {
2571 self_type returnArray(shape_);
2572 for (uint32 row = 0; row < shape_.rows; ++row)
2573 {
2574 returnArray(row, 0) = operator()(row, 0);
2575 for (uint32 col = 1; col < shape_.cols; ++col)
2576 {
2577 returnArray(row, col) = returnArray(row, col - 1) + operator()(row, col);
2578 }
2579 }
2580
2581 return returnArray;
2582 }
2583 case Axis::ROW:
2584 {
2585 return transpose().cumsum(Axis::COL).transpose();
2586 }
2587 default:
2588 {
2589 THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
2590 return {}; // get rid of compiler warning
2591 }
2592 }
2593 }
2594
2595 //============================================================================
2596 // Method Description:
2600 [[nodiscard]] pointer data() noexcept
2601 {
2602 return array_;
2603 }
2604
2605 //============================================================================
2606 // Method Description:
2610 [[nodiscard]] const_pointer data() const noexcept
2611 {
2612 return array_;
2613 }
2614
2615 //============================================================================
2616 // Method Description:
2622 [[nodiscard]] pointer dataRelease() noexcept
2623 {
2624 ownsPtr_ = false;
2625 return data();
2626 }
2627
2628 //============================================================================
2629 // Method Description:
2639 [[nodiscard]] self_type diagonal(index_type inOffset = 0, Axis inAxis = Axis::ROW) const
2640 {
2641 switch (inAxis)
2642 {
2643 case Axis::COL:
2644 {
2645 std::vector<dtype> diagnolValues;
2646 size_type col = 0;
2647 for (index_type row = inOffset; row < static_cast<index_type>(shape_.rows); ++row)
2648 {
2649 if (row < 0)
2650 {
2651 ++col;
2652 continue;
2653 }
2654 if (col >= shape_.cols)
2655 {
2656 break;
2657 }
2658
2659 diagnolValues.push_back(operator()(static_cast<size_type>(row), col));
2660 ++col;
2661 }
2662
2663 return self_type(diagnolValues);
2664 }
2665 case Axis::ROW:
2666 {
2667 return transpose().diagonal(inOffset, Axis::COL);
2668 }
2669 default:
2670 {
2671 THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
2672 return {}; // get rid of compiler warning
2673 }
2674 }
2675 }
2676
2677 //============================================================================
2678 // Method Description:
2684 [[nodiscard]] size_type dimSize(Axis inAxis) const noexcept
2685 {
2686 switch (inAxis)
2687 {
2688 case Axis::NONE:
2689 {
2690 return size();
2691 }
2692 case Axis::ROW:
2693 {
2694 return numRows();
2695 }
2696 case Axis::COL:
2697 {
2698 return numCols();
2699 }
2700 default:
2701 {
2702 return {}; // get rid of compiler warning
2703 }
2704 }
2705 }
2706
2707 //============================================================================
2708 // Method Description:
2719 [[nodiscard]] self_type dot(const self_type& inOtherArray) const
2720 {
2722
2723 if (shape_ == inOtherArray.shape_ && (shape_.rows == 1 || shape_.cols == 1))
2724 {
2725 dtype dotProduct = std::inner_product(cbegin(), cend(), inOtherArray.cbegin(), dtype{ 0 });
2726 self_type returnArray = { dotProduct };
2727 return returnArray;
2728 }
2729 if (shape_.cols == inOtherArray.shape_.rows)
2730 {
2731 // 2D array, use matrix multiplication
2732 self_type returnArray(shape_.rows, inOtherArray.shape_.cols);
2733 auto otherArrayT = inOtherArray.transpose();
2734
2735 for (uint32 i = 0; i < shape_.rows; ++i)
2736 {
2737 for (uint32 j = 0; j < otherArrayT.shape_.rows; ++j)
2738 {
2739 returnArray(i, j) =
2740 std::inner_product(otherArrayT.cbegin(j), otherArrayT.cend(j), cbegin(i), dtype{ 0 });
2741 }
2742 }
2743
2744 return returnArray;
2745 }
2746
2747 std::string errStr = "shapes of [" + utils::num2str(shape_.rows) + ", " + utils::num2str(shape_.cols) + "]";
2748 errStr += " and [" + utils::num2str(inOtherArray.shape_.rows) + ", " +
2749 utils::num2str(inOtherArray.shape_.cols) + "]";
2750 errStr += " are not consistent.";
2752
2753 return self_type(); // get rid of compiler warning
2754 }
2755
2756 //============================================================================
2757 // Method Description:
2765 void dump(const std::string& inFilename) const
2766 {
2767 std::filesystem::path f(inFilename);
2768 if (!f.has_extension())
2769 {
2770 f.replace_extension("bin");
2771 }
2772
2773 std::ofstream ofile(f.c_str(), std::ios::binary);
2774 if (!ofile.good())
2775 {
2776 THROW_RUNTIME_ERROR("Unable to open the input file:\n\t" + inFilename);
2777 }
2778
2779 if (array_ != nullptr)
2780 {
2781 ofile.write(reinterpret_cast<const char*>(array_), size_ * sizeof(dtype));
2782 }
2783 ofile.close();
2784 }
2785
2786 //============================================================================
2787 // Method Description:
2792 [[nodiscard]] Endian endianess() const noexcept
2793 {
2795
2796 return endianess_;
2797 }
2798
2799 //============================================================================
2800 // Method Description:
2808 self_type& fill(value_type inFillValue) noexcept
2809 {
2810 stl_algorithms::fill(begin(), end(), inFillValue);
2811 return *this;
2812 }
2813
2814 //============================================================================
2815 // Method Description:
2821 [[nodiscard]] NdArray<size_type> flatnonzero() const
2822 {
2824
2825 std::vector<size_type> indices;
2826 size_type idx = 0;
2827 for (auto value : *this)
2828 {
2829 if (!utils::essentiallyEqual(value, dtype{ 0 }))
2830 {
2831 indices.push_back(idx);
2832 }
2833 ++idx;
2834 }
2835
2836 return NdArray<size_type>(indices); // NOLINT(modernize-return-braced-init-list)
2837 }
2838
2839 //============================================================================
2840 // Method Description:
2847 [[nodiscard]] self_type flatten() const
2848 {
2849 self_type outArray(1, size_);
2850 stl_algorithms::copy(cbegin(), cend(), outArray.begin());
2851 return outArray;
2852 }
2853
2854 //============================================================================
2855 // Method Description:
2860 [[nodiscard]] const_reference front() const noexcept
2861 {
2862 return *cbegin();
2863 }
2864
2865 //============================================================================
2866 // Method Description:
2871 reference front() noexcept
2872 {
2873 return *begin();
2874 }
2875
2876 //============================================================================
2877 // Method Description:
2882 [[nodiscard]] const_reference front(size_type row) const
2883 {
2884 return *cbegin(row);
2885 }
2886
2887 //============================================================================
2888 // Method Description:
2894 {
2895 return *begin(row);
2896 }
2897
2898 //============================================================================
2899 // Method Description:
2905 [[nodiscard]] self_type getByIndices(const NdArray<size_type>& inIndices) const
2906 {
2907 return operator[](inIndices);
2908 }
2909
2910 //============================================================================
2911 // Method Description:
2919 [[nodiscard]] self_type getByMask(const NdArray<bool>& inMask) const
2920 {
2921 return operator[](inMask);
2922 }
2923
2924 //============================================================================
2925 // Method Description:
2931 // NOLINTNEXTLINE(modernize-use-nodiscard)
2932 bool isempty() const noexcept
2933 {
2934 return size_ == 0;
2935 }
2936
2937 //============================================================================
2938 // Method Description:
2944 // NOLINTNEXTLINE(modernize-use-nodiscard)
2945 bool isflat() const noexcept
2946 {
2947 return !isscalar() && (shape_.rows == 1 || shape_.cols == 1);
2948 }
2949
2950 //============================================================================
2951 // Method Description:
2955 // NOLINTNEXTLINE(modernize-use-nodiscard)
2956 bool isscalar() const noexcept
2957 {
2958 return size_ == 1;
2959 }
2960
2961 //============================================================================
2962 // Method Description:
2968 [[nodiscard]] NdArray<bool> issorted(Axis inAxis = Axis::NONE) const
2969 {
2971
2972 const auto comparitor = [](dtype lhs, dtype rhs) noexcept -> bool { return lhs < rhs; };
2973
2974 switch (inAxis)
2975 {
2976 case Axis::NONE:
2977 {
2978 return { stl_algorithms::is_sorted(cbegin(), cend(), comparitor) };
2979 }
2980 case Axis::COL:
2981 {
2982 NdArray<bool> returnArray(1, shape_.rows);
2983 for (uint32 row = 0; row < shape_.rows; ++row)
2984 {
2985 returnArray(0, row) = stl_algorithms::is_sorted(cbegin(row), cend(row), comparitor);
2986 }
2987
2988 return returnArray;
2989 }
2990 case Axis::ROW:
2991 {
2992 return transpose().issorted(Axis::COL);
2993 }
2994 default:
2995 {
2996 THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
2997 return {}; // get rid of compiler warning
2998 }
2999 }
3000 }
3001
3002 //============================================================================
3003 // Method Description:
3008 // NOLINTNEXTLINE(modernize-use-nodiscard)
3009 bool issquare() const noexcept
3010 {
3011 return shape_.issquare();
3012 }
3013
3014 //============================================================================
3015 // Method Description:
3022 [[nodiscard]] value_type item() const
3023 {
3024 if (!isscalar())
3025 {
3026 THROW_INVALID_ARGUMENT_ERROR("Can only convert an array of size 1 to a C++ scalar");
3027 }
3028
3029 return front();
3030 }
3031
3032 //============================================================================
3033 // Method Description:
3041 [[nodiscard]] self_type max(Axis inAxis = Axis::NONE) const
3042 {
3044
3045 const auto comparitor = [](dtype lhs, dtype rhs) noexcept -> bool { return lhs < rhs; };
3046
3047 switch (inAxis)
3048 {
3049 case Axis::NONE:
3050 {
3051 self_type returnArray = { *stl_algorithms::max_element(cbegin(), cend(), comparitor) };
3052 return returnArray;
3053 }
3054 case Axis::COL:
3055 {
3056 self_type returnArray(1, shape_.rows);
3057 for (uint32 row = 0; row < shape_.rows; ++row)
3058 {
3059 returnArray(0, row) = *stl_algorithms::max_element(cbegin(row), cend(row), comparitor);
3060 }
3061
3062 return returnArray;
3063 }
3064 case Axis::ROW:
3065 {
3066 return transpose().max(Axis::COL);
3067 }
3068 default:
3069 {
3070 THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
3071 return {}; // get rid of compiler warning
3072 }
3073 }
3074 }
3075
3076 //============================================================================
3077 // Method Description:
3085 [[nodiscard]] self_type min(Axis inAxis = Axis::NONE) const
3086 {
3088
3089 const auto comparitor = [](dtype lhs, dtype rhs) noexcept -> bool { return lhs < rhs; };
3090
3091 switch (inAxis)
3092 {
3093 case Axis::NONE:
3094 {
3095 self_type returnArray = { *stl_algorithms::min_element(cbegin(), cend(), comparitor) };
3096 return returnArray;
3097 }
3098 case Axis::COL:
3099 {
3100 self_type returnArray(1, shape_.rows);
3101 for (uint32 row = 0; row < shape_.rows; ++row)
3102 {
3103 returnArray(0, row) = *stl_algorithms::min_element(cbegin(row), cend(row), comparitor);
3104 }
3105
3106 return returnArray;
3107 }
3108 case Axis::ROW:
3109 {
3110 return transpose().min(Axis::COL);
3111 }
3112 default:
3113 {
3114 THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
3115 return {}; // get rid of compiler warning
3116 }
3117 }
3118 }
3119
3120 //============================================================================
3121 // Method Description:
3131 [[nodiscard]] self_type median(Axis inAxis = Axis::NONE) const
3132 {
3134
3135 const auto comparitor = [](dtype lhs, dtype rhs) noexcept -> bool { return lhs < rhs; };
3136
3137 if (size_ == 0)
3138 {
3139 THROW_RUNTIME_ERROR("Median is undefined for an array of size = 0.");
3140 }
3141
3142 switch (inAxis)
3143 {
3144 case Axis::NONE:
3145 {
3146 self_type copyArray(*this);
3147
3148 const size_type middleIdx = size_ / 2; // integer division
3150 copyArray.begin() + middleIdx,
3151 copyArray.end(),
3152 comparitor);
3153
3154 dtype medianValue = copyArray.array_[middleIdx];
3155 if (size_ % 2 == 0)
3156 {
3157 const size_type lhsIndex = middleIdx - 1;
3159 copyArray.begin() + lhsIndex,
3160 copyArray.end(),
3161 comparitor);
3162 medianValue =
3163 (medianValue + copyArray.array_[lhsIndex]) / dtype{ 2 }; // potentially integer division, ok
3164 }
3165
3166 return { medianValue };
3167 }
3168 case Axis::COL:
3169 {
3170 self_type copyArray(*this);
3171 self_type returnArray(1, shape_.rows);
3172
3173 const bool isEven = shape_.cols % 2 == 0;
3174 for (uint32 row = 0; row < shape_.rows; ++row)
3175 {
3176 const uint32 middleIdx = shape_.cols / 2; // integer division
3177 stl_algorithms::nth_element(copyArray.begin(row),
3178 copyArray.begin(row) + middleIdx,
3179 copyArray.end(row),
3180 comparitor);
3181
3182 dtype medianValue = copyArray(row, middleIdx);
3183 if (isEven)
3184 {
3185 const size_type lhsIndex = middleIdx - 1;
3186 stl_algorithms::nth_element(copyArray.begin(row),
3187 copyArray.begin(row) + lhsIndex,
3188 copyArray.end(row),
3189 comparitor);
3190 medianValue = (medianValue + copyArray(row, lhsIndex)) /
3191 dtype{ 2 }; // potentially integer division, ok
3192 }
3193
3194 returnArray(0, row) = medianValue;
3195 }
3196
3197 return returnArray;
3198 }
3199 case Axis::ROW:
3200 {
3201 return transpose().median(Axis::COL);
3202 }
3203 default:
3204 {
3205 THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
3206 return {}; // get rid of compiler warning
3207 }
3208 }
3209 }
3210
3211 //============================================================================
3212 // Method Description:
3216 self_type& nans() noexcept
3217
3218 {
3219 STATIC_ASSERT_FLOAT(dtype);
3220
3222 return *this;
3223 }
3224
3225 //============================================================================
3226 // Method Description:
3233 [[nodiscard]] uint64 nbytes() const noexcept
3234 {
3235 return static_cast<uint64>(sizeof(dtype) * size_);
3236 }
3237
3238 //============================================================================
3239 // Method Description:
3248 [[nodiscard]] self_type newbyteorder(Endian inEndianess) const
3249 {
3250 STATIC_ASSERT_INTEGER(dtype);
3251
3252 const bool nativeIsLittle = endian::isLittleEndian();
3253
3254 switch (endianess_)
3255 {
3256 case Endian::NATIVE:
3257 {
3258 switch (inEndianess)
3259 {
3260 case Endian::NATIVE:
3261 {
3262 return NdArray(*this);
3263 }
3264 case Endian::BIG:
3265 {
3266 if (nativeIsLittle)
3267 {
3268 self_type outArray(shape_);
3269
3270 stl_algorithms::transform(cbegin(), end(), outArray.begin(), endian::byteSwap<dtype>);
3271
3272 outArray.endianess_ = Endian::BIG;
3273 return outArray;
3274 }
3275 else
3276 {
3277 auto outArray = NdArray(*this);
3278 outArray.endianess_ = Endian::BIG;
3279 return outArray;
3280 }
3281 }
3282 case Endian::LITTLE:
3283 {
3284 if (nativeIsLittle)
3285 {
3286 auto outArray = NdArray(*this);
3287 outArray.endianess_ = Endian::LITTLE;
3288 return outArray;
3289 }
3290 else
3291 {
3292 self_type outArray(shape_);
3293
3294 stl_algorithms::transform(cbegin(), end(), outArray.begin(), endian::byteSwap<dtype>);
3295
3296 outArray.endianess_ = Endian::LITTLE;
3297 return outArray;
3298 }
3299 }
3300 default:
3301 {
3302 THROW_INVALID_ARGUMENT_ERROR("Unimplemented endian type.");
3303 return {}; // get rid of compiler warning
3304 }
3305 }
3306 break;
3307 }
3308 case Endian::BIG:
3309 {
3310 switch (inEndianess)
3311 {
3312 case Endian::NATIVE:
3313 {
3314 if (nativeIsLittle)
3315 {
3316 self_type outArray(shape_);
3317
3318 stl_algorithms::transform(cbegin(), end(), outArray.begin(), endian::byteSwap<dtype>);
3319
3320 outArray.endianess_ = Endian::NATIVE;
3321 return outArray;
3322 }
3323 else
3324 {
3325 auto outArray = NdArray(*this);
3326 outArray.endianess_ = Endian::NATIVE;
3327 return outArray;
3328 }
3329 }
3330 case Endian::BIG:
3331 {
3332 return NdArray(*this);
3333 }
3334 case Endian::LITTLE:
3335 {
3336 self_type outArray(shape_);
3337
3338 stl_algorithms::transform(cbegin(), end(), outArray.begin(), endian::byteSwap<dtype>);
3339
3340 outArray.endianess_ = Endian::LITTLE;
3341 return outArray;
3342 }
3343 default:
3344 {
3345 THROW_INVALID_ARGUMENT_ERROR("Unimplemented endian type.");
3346 return {}; // get rid of compiler warning
3347 }
3348 }
3349 break;
3350 }
3351 case Endian::LITTLE:
3352 {
3353 switch (inEndianess)
3354 {
3355 case Endian::NATIVE:
3356 {
3357 if (nativeIsLittle)
3358 {
3359 auto outArray = NdArray(*this);
3360 outArray.endianess_ = Endian::NATIVE;
3361 return outArray;
3362 }
3363 else
3364 {
3365 self_type outArray(shape_);
3366
3367 stl_algorithms::transform(cbegin(), end(), outArray.begin(), endian::byteSwap<dtype>);
3368
3369 outArray.endianess_ = Endian::NATIVE;
3370 return outArray;
3371 }
3372 }
3373 case Endian::BIG:
3374 {
3375 self_type outArray(shape_);
3376
3377 stl_algorithms::transform(cbegin(), end(), outArray.begin(), endian::byteSwap<dtype>);
3378
3379 outArray.endianess_ = Endian::BIG;
3380 return outArray;
3381 }
3382 case Endian::LITTLE:
3383 {
3384 return NdArray(*this);
3385 }
3386 default:
3387 {
3388 THROW_INVALID_ARGUMENT_ERROR("Unimplemented endian type.");
3389 return {}; // get rid of compiler warning
3390 }
3391 }
3392 break;
3393 }
3394 default:
3395 {
3396 THROW_INVALID_ARGUMENT_ERROR("Unimplemented endian type.");
3397 return {}; // get rid of compiler warning
3398 }
3399 }
3400 }
3401
3402 //============================================================================
3403 // Method Description:
3411 [[nodiscard]] NdArray<bool> none(Axis inAxis = Axis::NONE) const
3412 {
3414
3415 const auto function = [](dtype i) -> bool { return !utils::essentiallyEqual(i, dtype{ 0 }); };
3416
3417 switch (inAxis)
3418 {
3419 case Axis::NONE:
3420 {
3421 NdArray<bool> returnArray = { stl_algorithms::none_of(cbegin(), cend(), function) };
3422 return returnArray;
3423 }
3424 case Axis::COL:
3425 {
3426 NdArray<bool> returnArray(1, shape_.rows);
3427 for (uint32 row = 0; row < shape_.rows; ++row)
3428 {
3429 returnArray(0, row) = stl_algorithms::none_of(cbegin(row), cend(row), function);
3430 }
3431
3432 return returnArray;
3433 }
3434 case Axis::ROW:
3435 {
3436 return transpose().none(Axis::COL);
3437 }
3438 default:
3439 {
3440 THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
3441 return {}; // get rid of compiler warning
3442 }
3443 }
3444 }
3445
3446 //============================================================================
3447 // Method Description:
3456 [[nodiscard]] std::pair<NdArray<size_type>, NdArray<size_type>> nonzero() const;
3457
3458 //============================================================================
3459 // Method Description:
3465 [[nodiscard]] size_type numCols() const noexcept
3466 {
3467 return shape_.cols;
3468 }
3469
3470 //============================================================================
3471 // Method Description:
3477 [[nodiscard]] size_type numRows() const noexcept
3478 {
3479 return shape_.rows;
3480 }
3481
3482 //============================================================================
3483 // Method Description:
3487 self_type& ones() noexcept
3488 {
3490
3491 fill(dtype{ 1 });
3492 return *this;
3493 }
3494
3495 //============================================================================
3496 // Method Description:
3501 bool ownsInternalData() noexcept
3502 {
3503 return ownsPtr_;
3504 }
3505
3506 //============================================================================
3507 // Method Description:
3521 self_type& partition(size_type inKth, Axis inAxis = Axis::NONE)
3522 {
3524
3525 const auto comparitor = [](dtype lhs, dtype rhs) noexcept -> bool
3526 { return lhs < rhs; }; // cppcheck-suppress returnTempReference
3527
3528 switch (inAxis)
3529 {
3530 case Axis::NONE:
3531 {
3532 if (inKth >= size_)
3533 {
3534 std::string errStr = "kth(=" + utils::num2str(inKth);
3535 errStr += ") out of bounds (" + utils::num2str(size_) + ")";
3537 }
3538
3539 stl_algorithms::nth_element(begin(), begin() + inKth, end(), comparitor);
3540 break;
3541 }
3542 case Axis::COL:
3543 {
3544 if (inKth >= shape_.cols)
3545 {
3546 std::string errStr = "kth(=" + utils::num2str(inKth);
3547 errStr += ") out of bounds (" + utils::num2str(shape_.cols) + ")";
3549 }
3550
3551 for (uint32 row = 0; row < shape_.rows; ++row)
3552 {
3553 stl_algorithms::nth_element(begin(row), begin(row) + inKth, end(row), comparitor);
3554 }
3555 break;
3556 }
3557 case Axis::ROW:
3558 {
3559 if (inKth >= shape_.rows)
3560 {
3561 std::string errStr = "kth(=" + utils::num2str(inKth);
3562 errStr += ") out of bounds (" + utils::num2str(shape_.rows) + ")";
3564 }
3565
3566 self_type transposedArray = transpose();
3567 for (uint32 row = 0; row < transposedArray.shape_.rows; ++row)
3568 {
3569 stl_algorithms::nth_element(transposedArray.begin(row),
3570 transposedArray.begin(row) + inKth,
3571 transposedArray.end(row),
3572 comparitor);
3573 }
3574 *this = transposedArray.transpose();
3575 break;
3576 }
3577 }
3578
3579 return *this;
3580 }
3581
3582 //============================================================================
3583 // Method Description:
3587 void print() const
3588 {
3590
3591 std::cout << *this;
3592 }
3593
3594 //============================================================================
3595 // Method Description:
3603 [[nodiscard]] self_type prod(Axis inAxis = Axis::NONE) const
3604 {
3606
3607 switch (inAxis)
3608 {
3609 case Axis::NONE:
3610 {
3611 dtype product = std::accumulate(cbegin(), cend(), dtype{ 1 }, std::multiplies<dtype>());
3612 self_type returnArray = { product };
3613 return returnArray;
3614 }
3615 case Axis::COL:
3616 {
3617 self_type returnArray(1, shape_.rows);
3618 for (uint32 row = 0; row < shape_.rows; ++row)
3619 {
3620 returnArray(0, row) =
3621 std::accumulate(cbegin(row), cend(row), dtype{ 1 }, std::multiplies<dtype>());
3622 }
3623
3624 return returnArray;
3625 }
3626 case Axis::ROW:
3627 {
3628 return transpose().prod(Axis::COL);
3629 }
3630 default:
3631 {
3632 THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
3633 return {}; // get rid of compiler warning
3634 }
3635 }
3636 }
3637
3638 //============================================================================
3639 // Method Description:
3647 [[nodiscard]] self_type ptp(Axis inAxis = Axis::NONE) const
3648 {
3650
3651 const auto comparitor = [](dtype lhs, dtype rhs) noexcept -> bool { return lhs < rhs; };
3652
3653 switch (inAxis)
3654 {
3655 case Axis::NONE:
3656 {
3657 const auto result = stl_algorithms::minmax_element(cbegin(), cend(), comparitor);
3658 self_type returnArray = { *result.second - *result.first };
3659 return returnArray;
3660 }
3661 case Axis::COL:
3662 {
3663 self_type returnArray(1, shape_.rows);
3664 for (uint32 row = 0; row < shape_.rows; ++row)
3665 {
3666 const auto result = stl_algorithms::minmax_element(cbegin(row), cend(row), comparitor);
3667 returnArray(0, row) = *result.second - *result.first;
3668 }
3669
3670 return returnArray;
3671 }
3672 case Axis::ROW:
3673 {
3674 return transpose().ptp(Axis::COL);
3675 }
3676 default:
3677 {
3678 THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
3679 return {}; // get rid of compiler warning
3680 }
3681 }
3682 }
3683
3684 //============================================================================
3685 // Method Description:
3693 self_type& put(index_type inIndex, const value_type& inValue)
3694 {
3695 at(inIndex) = inValue;
3696
3697 return *this;
3698 }
3699
3700 //============================================================================
3701 // Method Description:
3710 self_type& put(index_type inRow, index_type inCol, const value_type& inValue)
3711 {
3712 at(inRow, inCol) = inValue;
3713
3714 return *this;
3715 }
3716
3717 //============================================================================
3718 // Method Description:
3727 template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
3728 self_type& put(const Indices& inIndices, const value_type& inValue)
3729 {
3730 for (auto index : inIndices)
3731 {
3732 put(index, inValue);
3733 }
3734
3735 return *this;
3736 }
3737
3738 //============================================================================
3739 // Method Description:
3748 template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
3749 self_type& put(const Indices& inIndices, const self_type& inValues)
3750 {
3751 if (inValues.isscalar())
3752 {
3753 return put(inIndices, inValues.item());
3754 }
3755 else if (inIndices.size() != inValues.size())
3756 {
3757 THROW_INVALID_ARGUMENT_ERROR("Input indices do not match values dimensions.");
3758 }
3759
3760 size_type counter = 0;
3761 for (auto index : inIndices)
3762 {
3763 put(index, inValues[counter++]);
3764 }
3765
3766 return *this;
3767 }
3768
3769 //============================================================================
3770 // Method Description:
3779 self_type& put(const Slice& inSlice, const value_type& inValue)
3780 {
3781 return put(toIndices(inSlice, Axis::NONE), inValue);
3782 }
3783
3784 //============================================================================
3785 // Method Description:
3794 self_type& put(const Slice& inSlice, const self_type& inValues)
3795 {
3796 return put(toIndices(inSlice, Axis::NONE), inValues);
3797 }
3798
3799 //============================================================================
3800 // Method Description:
3810 template<typename RowIndices,
3811 typename ColIndices,
3814 self_type& put(const RowIndices& inRowIndices, const ColIndices& inColIndices, const value_type& inValue)
3815 {
3816 stl_algorithms::for_each(inRowIndices.begin(),
3817 inRowIndices.end(),
3818 [this, &inColIndices, &inValue](const auto row)
3819 {
3820 stl_algorithms::for_each(inColIndices.begin(),
3821 inColIndices.end(),
3822 [this, row, &inValue](const auto col)
3823 { this->put(row, col, inValue); });
3824 });
3825
3826 return *this;
3827 }
3828
3829 //============================================================================
3830 // Method Description:
3840 template<typename RowIndices, type_traits::ndarray_int_concept<RowIndices> = 0>
3841 self_type& put(const RowIndices& inRowIndices, const Slice& inColSlice, const value_type& inValue)
3842 {
3843 return put(inRowIndices, toIndices(inColSlice, Axis::COL), inValue);
3844 }
3845
3846 //============================================================================
3847 // Method Description:
3857 template<typename ColIndices, type_traits::ndarray_int_concept<ColIndices> = 0>
3858 self_type& put(const Slice& inRowSlice, const ColIndices& inColIndices, const value_type& inValue)
3859 {
3860 return put(toIndices(inRowSlice, Axis::ROW), inColIndices, inValue);
3861 }
3862
3863 //============================================================================
3864 // Method Description:
3874 self_type& put(const Slice& inRowSlice, const Slice& inColSlice, const value_type& inValue)
3875 {
3876 return put(toIndices(inRowSlice, Axis::ROW), toIndices(inColSlice, Axis::COL), inValue);
3877 }
3878
3879 //============================================================================
3880 // Method Description:
3890 template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
3891 self_type& put(const Indices& inRowIndices, index_type inColIndex, const value_type& inValue)
3892 {
3893 const NdArray<index_type> colIndices = { inColIndex };
3894 return put(inRowIndices, colIndices, inValue);
3895 }
3896
3897 //============================================================================
3898 // Method Description:
3908 self_type& put(const Slice& inRowSlice, index_type inColIndex, const value_type& inValue)
3909 {
3910 const NdArray<index_type> colIndices = { inColIndex };
3911 return put(toIndices(inRowSlice, Axis::ROW), colIndices, inValue);
3912 }
3913
3914 //============================================================================
3915 // Method Description:
3925 template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
3926 self_type& put(index_type inRowIndex, const Indices& inColIndices, const value_type& inValue)
3927 {
3928 const NdArray<index_type> rowIndices = { inRowIndex };
3929 return put(rowIndices, inColIndices, inValue);
3930 }
3931
3932 //============================================================================
3933 // Method Description:
3943 self_type& put(index_type inRowIndex, const Slice& inColSlice, const value_type& inValue)
3944 {
3945 const NdArray<index_type> rowIndices = { inRowIndex };
3946 return put(rowIndices, toIndices(inColSlice, Axis::COL), inValue);
3947 }
3948
3949 //============================================================================
3950 // Method Description:
3960 template<typename RowIndices,
3961 typename ColIndices,
3964 self_type& put(const RowIndices& inRowIndices, const ColIndices& inColIndices, const self_type& inValues)
3965 {
3966 std::vector<size_type> indices;
3967 indices.reserve(inRowIndices.size() * inColIndices.size());
3968 std::for_each(inRowIndices.begin(),
3969 inRowIndices.end(),
3970 [this, &inColIndices, &indices](auto row)
3971 {
3972 if constexpr (std::is_signed_v<decltype(row)>)
3973 {
3974 if (row < 0)
3975 {
3976 row += shape_.rows;
3977 }
3978 // still
3979 if (row < 0)
3980 {
3981 THROW_INVALID_ARGUMENT_ERROR("row index exceeds matrix dimensions");
3982 }
3983 }
3984 std::for_each(inColIndices.begin(),
3985 inColIndices.end(),
3986 [this, row, &indices](auto col)
3987 {
3988 if constexpr (std::is_signed_v<decltype(col)>)
3989 {
3990 if (col < 0)
3991 {
3992 col += shape_.cols;
3993 }
3994 // still
3995 if (col < 0)
3996 {
3997 THROW_INVALID_ARGUMENT_ERROR(
3998 "col index exceeds matrix dimensions");
3999 }
4000 }
4001 indices.push_back(row * shape_.cols + col);
4002 });
4003 });
4004
4005 return put(NdArray<size_type>(indices.data(), indices.size(), PointerPolicy::SHELL), inValues);
4006 }
4007
4008 //============================================================================
4009 // Method Description:
4019 template<typename RowIndices, type_traits::ndarray_int_concept<RowIndices> = 0>
4020 self_type& put(const RowIndices& inRowIndices, Slice inColSlice, const self_type& inValues)
4021 {
4022 return put(inRowIndices, toIndices(inColSlice, Axis::COL), inValues);
4023 }
4024
4025 //============================================================================
4026 // Method Description:
4036 template<typename ColIndices, type_traits::ndarray_int_concept<ColIndices> = 0>
4037 self_type& put(Slice inRowSlice, const ColIndices& inColIndices, const self_type& inValues)
4038 {
4039 return put(toIndices(inRowSlice, Axis::ROW), inColIndices, inValues);
4040 }
4041
4042 //============================================================================
4043 // Method Description:
4053 self_type& put(Slice inRowSlice, Slice inColSlice, const self_type& inValues)
4054 {
4055 return put(toIndices(inRowSlice, Axis::ROW), toIndices(inColSlice, Axis::COL), inValues);
4056 }
4057
4058 //============================================================================
4059 // Method Description:
4069 template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
4070 self_type& put(const Indices& inRowIndices, index_type inColIndex, const self_type& inValues)
4071 {
4072 const NdArray<index_type> colIndices = { inColIndex };
4073 return put(inRowIndices, colIndices, inValues);
4074 }
4075
4076 //============================================================================
4077 // Method Description:
4087 self_type& put(const Slice& inRowSlice, index_type inColIndex, const self_type& inValues)
4088 {
4089 const NdArray<index_type> colIndices = { inColIndex };
4090 return put(toIndices(inRowSlice, Axis::ROW), colIndices, inValues);
4091 }
4092
4093 //============================================================================
4094 // Method Description:
4104 template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
4105 self_type& put(index_type inRowIndex, const Indices& inColIndices, const self_type& inValues)
4106 {
4107 const NdArray<index_type> rowIndices = { inRowIndex };
4108 return put(rowIndices, inColIndices, inValues);
4109 }
4110
4111 //============================================================================
4112 // Method Description:
4122 self_type& put(index_type inRowIndex, const Slice& inColSlice, const self_type& inValues)
4123 {
4124 const NdArray<index_type> rowIndices = { inRowIndex };
4125 return put(rowIndices, toIndices(inColSlice, Axis::COL), inValues);
4126 }
4127
4128 //============================================================================
4129 // Method Description:
4135 self_type& putMask(const NdArray<bool>& inMask, const value_type& inValue)
4136 {
4137 if (inMask.shape() != shape_)
4138 {
4139 THROW_INVALID_ARGUMENT_ERROR("input inMask must be the same shape as the array it is masking.");
4140 }
4141
4142 return put(inMask.flatnonzero(), inValue);
4143 }
4144
4145 //============================================================================
4146 // Method Description:
4152 self_type& putMask(const NdArray<bool>& inMask, const self_type& inValues)
4153 {
4154 if (inMask.shape() != shape_)
4155 {
4156 THROW_INVALID_ARGUMENT_ERROR("input inMask must be the same shape as the array it is masking.");
4157 }
4158
4159 if (inValues.isscalar())
4160 {
4161 put(inMask.flatnonzero(), inValues.item());
4162 }
4163 else
4164 {
4165 put(inMask.flatnonzero(), inValues);
4166 }
4167
4168 return *this;
4169 }
4170
4171 //============================================================================
4172 // Method Description:
4180 {
4181 reshape(size_);
4182 return *this;
4183 }
4184
4185 //============================================================================
4186 // Method Description:
4195 [[nodiscard]] self_type repeat(size_type inNumRows, size_type inNumCols) const
4196 {
4197 self_type returnArray(shape_.rows * inNumRows, shape_.cols * inNumCols);
4198
4199 for (size_type row = 0; row < inNumRows; ++row)
4200 {
4201 for (size_type col = 0; col < inNumCols; ++col)
4202 {
4203 std::vector<size_type> indices(shape_.size());
4204
4205 const size_type rowStart = row * shape_.rows;
4206 const size_type colStart = col * shape_.cols;
4207
4208 const size_type rowEnd = (row + 1) * shape_.rows;
4209 const size_type colEnd = (col + 1) * shape_.cols;
4210
4211 size_type counter = 0;
4212 for (size_type rowIdx = rowStart; rowIdx < rowEnd; ++rowIdx)
4213 {
4214 for (size_type colIdx = colStart; colIdx < colEnd; ++colIdx)
4215 {
4216 indices[counter++] = rowIdx * returnArray.shape_.cols + colIdx;
4217 }
4218 }
4219
4220 returnArray.put(NdArray<size_type>(indices), *this);
4221 }
4222 }
4223
4224 return returnArray;
4225 }
4226
4227 //============================================================================
4228 // Method Description:
4236 [[nodiscard]] self_type repeat(const Shape& inRepeatShape) const
4237 {
4238 return repeat(inRepeatShape.rows, inRepeatShape.cols);
4239 }
4240
4241 //============================================================================
4242 // Method Description:
4249 {
4251
4252 stl_algorithms::replace(begin(), end(), oldValue, newValue);
4253 return *this;
4254 }
4255
4256 //============================================================================
4257 // Method Description:
4272 {
4273 if (inSize != size_)
4274 {
4275 std::string errStr = "Cannot reshape array of size " + utils::num2str(size_) + " into shape ";
4276 errStr += "[" + utils::num2str(1) + ", " + utils::num2str(inSize) + "]";
4277 THROW_RUNTIME_ERROR(errStr);
4278 }
4279
4280 shape_.rows = 1;
4281 shape_.cols = inSize;
4282
4283 return *this;
4284 }
4285
4286 //============================================================================
4287 // Method Description:
4303 {
4304 if (inNumRows < 0)
4305 {
4306 if (size_ % inNumCols == 0)
4307 {
4308 return reshape(size_ / inNumCols, inNumCols);
4309 }
4310
4311 std::string errStr = "Cannot reshape array of size " + utils::num2str(size_) + " into a shape ";
4312 errStr += "with " + utils::num2str(inNumCols) + " columns";
4314 }
4315
4316 if (inNumCols < 0)
4317 {
4318 if (size_ % inNumRows == 0)
4319 {
4320 return reshape(inNumRows, size_ / inNumRows);
4321 }
4322
4323 std::string errStr = "Cannot reshape array of size " + utils::num2str(size_) + " into a shape ";
4324 errStr += "with " + utils::num2str(inNumRows) + " rows";
4326 }
4327
4328 if (static_cast<size_type>(inNumRows * inNumCols) != size_)
4329 {
4330 std::string errStr = "Cannot reshape array of size " + utils::num2str(size_) + " into shape ";
4331 errStr += "[" + utils::num2str(inNumRows) + ", " + utils::num2str(inNumCols) + "]";
4333 }
4334
4335 shape_.rows = static_cast<size_type>(inNumRows);
4336 shape_.cols = static_cast<size_type>(inNumCols);
4337
4338 return *this;
4339 }
4340
4341 //============================================================================
4342 // Method Description:
4356 self_type& reshape(const Shape& inShape)
4357 {
4358 return reshape(inShape.rows, inShape.cols);
4359 }
4360
4361 //============================================================================
4362 // Method Description:
4372 {
4373 newArray(Shape(inNumRows, inNumCols));
4374 return *this;
4375 }
4376
4377 //============================================================================
4378 // Method Description:
4386 self_type& resizeFast(const Shape& inShape)
4387 {
4388 return resizeFast(inShape.rows, inShape.cols);
4389 }
4390
4391 //============================================================================
4392 // Method Description:
4404 {
4405 std::vector<dtype> oldData(size_);
4406 stl_algorithms::copy(begin(), end(), oldData.begin());
4407
4408 const Shape inShape(inNumRows, inNumCols);
4409 const Shape oldShape = shape_;
4410
4411 newArray(inShape);
4412
4413 for (uint32 row = 0; row < inShape.rows; ++row)
4414 {
4415 for (uint32 col = 0; col < inShape.cols; ++col)
4416 {
4417 if (row >= oldShape.rows || col >= oldShape.cols)
4418 {
4419 operator()(row, col) = dtype{ 0 }; // zero fill
4420 }
4421 else
4422 {
4423 operator()(row, col) = oldData[row * oldShape.cols + col];
4424 }
4425 }
4426 }
4427
4428 return *this;
4429 }
4430
4431 //============================================================================
4432 // Method Description:
4442 self_type& resizeSlow(const Shape& inShape)
4443 {
4444 return resizeSlow(inShape.rows, inShape.cols);
4445 }
4446
4447 //============================================================================
4448 // Method Description:
4457 [[nodiscard]] self_type round(uint8 inNumDecimals = 0) const
4458 {
4459 STATIC_ASSERT_FLOAT(dtype);
4460
4461 self_type returnArray(shape_);
4462 const double multFactor = utils::power(10., inNumDecimals);
4463 const auto function = [multFactor](dtype value) noexcept -> dtype
4464 { return static_cast<dtype>(std::nearbyint(static_cast<double>(value) * multFactor) / multFactor); };
4465
4466 stl_algorithms::transform(cbegin(), cend(), returnArray.begin(), function);
4467
4468 return returnArray;
4469 }
4470
4471 //============================================================================
4472 // Method Description:
4478 [[nodiscard]] self_type row(size_type inRow) const
4479 {
4480 return self_type(cbegin(inRow), cend(inRow));
4481 }
4482
4483 //============================================================================
4484 // Method Description:
4490 [[nodiscard]] self_type rows(const NdArray<size_type>& inRows) const
4491 {
4492 auto returnArray = self_type(inRows.size(), shape_.cols);
4493 const auto cSlice = returnArray.cSlice();
4494
4495 for (size_type i = 0; i < inRows.size(); ++i)
4496 {
4497 returnArray.put(i, cSlice, row(inRows[i]));
4498 }
4499
4500 return returnArray;
4501 }
4502
4503 //============================================================================
4504 // Method Description:
4511 [[nodiscard]] const Shape& shape() const noexcept
4512 {
4513 return shape_;
4514 }
4515
4516 //============================================================================
4517 // Method Description:
4524 [[nodiscard]] size_type size() const noexcept
4525 {
4526 return size_;
4527 }
4528
4529 //============================================================================
4530 // Method Description:
4538 self_type& sort(Axis inAxis = Axis::NONE)
4539 {
4541
4542 const auto comparitor = [](dtype lhs, dtype rhs) noexcept -> bool
4543 { return lhs < rhs; }; // cppcheck-suppress returnTempReference
4544
4545 switch (inAxis)
4546 {
4547 case Axis::NONE:
4548 {
4549 stl_algorithms::sort(begin(), end(), comparitor);
4550 break;
4551 }
4552 case Axis::COL:
4553 {
4554 for (uint32 row = 0; row < shape_.rows; ++row)
4555 {
4556 stl_algorithms::sort(begin(row), end(row), comparitor);
4557 }
4558 break;
4559 }
4560 case Axis::ROW:
4561 {
4562 self_type transposedArray = transpose();
4563 for (uint32 row = 0; row < transposedArray.shape_.rows; ++row)
4564 {
4565 stl_algorithms::sort(transposedArray.begin(row), transposedArray.end(row), comparitor);
4566 }
4567
4568 *this = transposedArray.transpose();
4569 break;
4570 }
4571 }
4572
4573 return *this;
4574 }
4575
4576 //============================================================================
4577 // Method Description:
4582 [[nodiscard]] std::string str() const
4583 {
4585
4586 std::string out;
4587 out += "[";
4588 for (uint32 row = 0; row < shape_.rows; ++row)
4589 {
4590 out += "[";
4591 for (uint32 col = 0; col < shape_.cols; ++col)
4592 {
4593 out += utils::value2str(operator()(row, col)) + ", ";
4594 }
4595
4596 if (row == shape_.rows - 1)
4597 {
4598 out += "]";
4599 }
4600 else
4601 {
4602 out += "]\n";
4603 }
4604 }
4605 out += "]\n";
4606 return out;
4607 }
4608
4609 //============================================================================
4610 // Method Description:
4618 [[nodiscard]] self_type sum(Axis inAxis = Axis::NONE) const
4619 {
4621
4622 switch (inAxis)
4623 {
4624 case Axis::NONE:
4625 {
4626 self_type returnArray = { std::accumulate(cbegin(), cend(), dtype{ 0 }) };
4627 return returnArray;
4628 }
4629 case Axis::COL:
4630 {
4631 self_type returnArray(1, shape_.rows);
4632 for (uint32 row = 0; row < shape_.rows; ++row)
4633 {
4634 returnArray(0, row) = std::accumulate(cbegin(row), cend(row), dtype{ 0 });
4635 }
4636
4637 return returnArray;
4638 }
4639 case Axis::ROW:
4640 {
4641 return transpose().sum(Axis::COL);
4642 }
4643 default:
4644 {
4645 THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
4646 return {}; // get rid of compiler warning
4647 }
4648 }
4649 }
4650
4651 //============================================================================
4652 // Method Description:
4659 [[nodiscard]] self_type swapaxes() const
4660 {
4661 return transpose();
4662 }
4663
4664 //============================================================================
4665 // Method Description:
4672 self_type& swapCols(index_type colIdx1, index_type colIdx2) noexcept
4673 {
4674 for (index_type row = 0; row < static_cast<index_type>(shape_.rows); ++row)
4675 {
4676 std::swap(operator()(row, colIdx1), operator()(row, colIdx2));
4677 }
4678
4679 return *this;
4680 }
4681
4682 //============================================================================
4683 // Method Description:
4690 self_type& swapRows(index_type rowIdx1, index_type rowIdx2) noexcept
4691 {
4692 for (index_type col = 0; col < static_cast<index_type>(shape_.cols); ++col)
4693 {
4694 std::swap(operator()(rowIdx1, col), operator()(rowIdx2, col));
4695 }
4696
4697 return *this;
4698 }
4699
4700 //============================================================================
4701 // Method Description:
4710 void tofile(const std::string& inFilename) const
4711 {
4712 dump(inFilename);
4713 }
4714
4715 //============================================================================
4716 // Method Description:
4726 void tofile(const std::string& inFilename, const char inSep) const
4727 {
4729
4730 std::filesystem::path f(inFilename);
4731 if (!f.has_extension())
4732 {
4733 f.replace_extension("txt");
4734 }
4735
4736 std::ofstream ofile(f.c_str());
4737 if (!ofile.good())
4738 {
4739 THROW_RUNTIME_ERROR("Input file could not be opened:\n\t" + inFilename);
4740 }
4741
4742 size_type counter = 0;
4743 for (auto value : *this)
4744 {
4745 ofile << value;
4746 if (counter++ != size_ - 1)
4747 {
4748 ofile << inSep;
4749 }
4750 }
4751 ofile.close();
4752 }
4753
4754 //============================================================================
4755 // Method Description:
4763 [[nodiscard]] NdArray<size_type> toIndices(Slice inSlice, Axis inAxis = Axis::NONE) const
4764 {
4765 size_type numElements = 0;
4766 switch (inAxis)
4767 {
4768 case Axis::NONE:
4769 {
4770 numElements = inSlice.numElements(size_);
4771 break;
4772 }
4773 case Axis::ROW:
4774 {
4775 numElements = inSlice.numElements(shape_.rows);
4776 break;
4777 }
4778 case Axis::COL:
4779 {
4780 numElements = inSlice.numElements(shape_.cols);
4781 break;
4782 }
4783 default:
4784 {
4785 // not actually possible, getting rid of compiler warning
4786 THROW_INVALID_ARGUMENT_ERROR("Invalid 'inAxis' option");
4787 }
4788 }
4789
4790 if (numElements == 0)
4791 {
4792 return {};
4793 }
4794
4795 NdArray<size_type> indices(1, numElements);
4796 indices[0] = static_cast<size_type>(inSlice.start);
4797 for (size_type i = 1; i < indices.size(); ++i)
4798 {
4799 indices[static_cast<index_type>(i)] = static_cast<size_type>(
4800 indices[static_cast<index_type>(i - size_type{ 1 })] + static_cast<size_type>(inSlice.step));
4801 }
4802
4803 return indices;
4804 }
4805
4806 //============================================================================
4807 // Method Description:
4812 [[nodiscard]] std::vector<dtype> toStlVector() const
4813 {
4814 return std::vector<dtype>(cbegin(), cend());
4815 }
4816
4817 //============================================================================
4818 // Method Description:
4829 [[nodiscard]] value_type trace(size_type inOffset = 0, Axis inAxis = Axis::ROW) const noexcept
4830 {
4832
4833 size_type rowStart = 0;
4834 size_type colStart = 0;
4835 switch (inAxis)
4836 {
4837 case Axis::ROW:
4838 {
4839 rowStart += inOffset;
4840 break;
4841 }
4842 case Axis::COL:
4843 {
4844 colStart += inOffset;
4845 break;
4846 }
4847 default:
4848 {
4849 // if the user input NONE, override back to ROW
4850 inAxis = Axis::ROW;
4851 break;
4852 }
4853 }
4854
4855 if (rowStart >= shape_.rows || colStart >= shape_.cols)
4856 {
4857 return dtype{ 0 };
4858 }
4859
4860 size_type col = colStart;
4861 dtype sum = 0;
4862 for (size_type row = rowStart; row < shape_.rows; ++row)
4863 {
4864 if (col >= shape_.cols)
4865 {
4866 break;
4867 }
4868 sum += operator()(row, col++);
4869 }
4870
4871 return sum;
4872 }
4873
4874 //============================================================================
4875 // Method Description:
4882 [[nodiscard]] self_type transpose() const
4883 {
4884 self_type transArray(shape_.cols, shape_.rows);
4885 for (uint32 row = 0; row < shape_.rows; ++row)
4886 {
4887 for (uint32 col = 0; col < shape_.cols; ++col)
4888 {
4889 transArray(col, row) = operator()(row, col);
4890 }
4891 }
4892 return transArray;
4893 }
4894
4895 //============================================================================
4896 // Method Description:
4900 self_type& zeros() noexcept
4901 {
4903
4904 fill(dtype{ 0 });
4905 return *this;
4906 }
4907
4908 private:
4909 //====================================Attributes==============================
4910 allocator_type allocator_{};
4911 Shape shape_{ 0, 0 };
4912 size_type size_{ 0 };
4913 Endian endianess_{ Endian::NATIVE };
4914 pointer array_{ nullptr };
4915 bool ownsPtr_{ false };
4916
4917 //============================================================================
4918 // Method Description:
4921 void deleteArray() noexcept
4922 {
4923 if (ownsPtr_ && array_ != nullptr)
4924 {
4925 allocator_.deallocate(array_, size_);
4926 }
4927
4928 array_ = nullptr;
4929 shape_.rows = shape_.cols = 0;
4930 size_ = 0;
4931 ownsPtr_ = false;
4932 endianess_ = Endian::NATIVE;
4933 }
4934
4935 //============================================================================
4936 // Method Description:
4939 void newArray()
4940 {
4941 if (size_ > 0)
4942 {
4943 array_ = allocator_.allocate(size_);
4944 ownsPtr_ = true;
4945 }
4946 }
4947
4948 //============================================================================
4949 // Method Description:
4954 void newArray(const Shape& inShape)
4955 {
4956 deleteArray();
4957
4958 shape_ = inShape;
4959 size_ = inShape.size();
4960 newArray();
4961 }
4962 };
4963
4964 // NOTE: this needs to be defined outside of the class to get rid of a compiler
4965 // error in Visual Studio
4966 template<typename dtype, class Alloc_>
4967 [[nodiscard]] std::pair<NdArray<uint32>, NdArray<uint32>> NdArray<dtype, Alloc_>::nonzero() const
4968 {
4970
4971 std::vector<size_type> rowIndices;
4972 std::vector<size_type> colIndices;
4973
4974 for (uint32 row = 0; row < shape_.rows; ++row)
4975 {
4976 for (uint32 col = 0; col < shape_.cols; ++col)
4977 {
4978 if (!utils::essentiallyEqual(operator()(row, col), dtype{ 0 }))
4979 {
4980 rowIndices.push_back(row);
4981 colIndices.push_back(col);
4982 }
4983 }
4984 }
4985
4986 return std::make_pair(NdArray<size_type>(rowIndices), NdArray<size_type>(colIndices));
4987 }
4988} // namespace nc
#define THROW_RUNTIME_ERROR(msg)
Definition: Error.hpp:40
#define THROW_INVALID_ARGUMENT_ERROR(msg)
Definition: Error.hpp:37
#define STATIC_ASSERT_FLOAT(dtype)
Definition: StaticAsserts.hpp:50
#define STATIC_ASSERT_ARITHMETIC_OR_COMPLEX(dtype)
Definition: StaticAsserts.hpp:56
#define STATIC_ASSERT_INTEGER(dtype)
Definition: StaticAsserts.hpp:43
#define STATIC_ASSERT_ARITHMETIC(dtype)
Definition: StaticAsserts.hpp:39
Custom column iterator for NdArray.
Definition: NdArrayIterators.hpp:813
Custom column const_iterator for NdArray.
Definition: NdArrayIterators.hpp:487
Custom const_iterator for NdArray.
Definition: NdArrayIterators.hpp:41
Holds 1D and 2D arrays, the main work horse of the NumCpp library.
Definition: NdArrayCore.hpp:139
NdArray(pointer inPtr, UIntType size, PointerPolicy policy)
Definition: NdArrayCore.hpp:580
const_reverse_column_iterator rcolbegin() const noexcept
Definition: NdArrayCore.hpp:1573
size_type dimSize(Axis inAxis) const noexcept
Definition: NdArrayCore.hpp:2684
NdArray< size_type > toIndices(Slice inSlice, Axis inAxis=Axis::NONE) const
Definition: NdArrayCore.hpp:4763
self_type operator[](Slice inSlice) const
Definition: NdArrayCore.hpp:823
self_type max(Axis inAxis=Axis::NONE) const
Definition: NdArrayCore.hpp:3041
size_type size() const noexcept
Definition: NdArrayCore.hpp:4524
reverse_iterator rbegin() noexcept
Definition: NdArrayCore.hpp:1469
self_type at(index_type inRowIndex, const Slice &inColSlice) const
Definition: NdArrayCore.hpp:1197
self_type columns(const NdArray< size_type > &inCols) const
Definition: NdArrayCore.hpp:2424
self_type & put(const RowIndices &inRowIndices, const ColIndices &inColIndices, const self_type &inValues)
Definition: NdArrayCore.hpp:3964
self_type & resizeSlow(size_type inNumRows, size_type inNumCols)
Definition: NdArrayCore.hpp:4403
self_type & put(const Slice &inRowSlice, const ColIndices &inColIndices, const value_type &inValue)
Definition: NdArrayCore.hpp:3858
self_type & zeros() noexcept
Definition: NdArrayCore.hpp:4900
self_type & ones() noexcept
Definition: NdArrayCore.hpp:3487
const_iterator cbegin() const noexcept
Definition: NdArrayCore.hpp:1365
self_type at(const RowIndices &rowIndices, const ColIndices &colIndices) const
Definition: NdArrayCore.hpp:1273
const_column_iterator ccolbegin(size_type inCol) const
Definition: NdArrayCore.hpp:1454
NdArray< bool > contains(value_type inValue, Axis inAxis=Axis::NONE) const
Definition: NdArrayCore.hpp:2445
const_pointer data() const noexcept
Definition: NdArrayCore.hpp:2610
iterator end() noexcept
Definition: NdArrayCore.hpp:1623
self_type & swapCols(index_type colIdx1, index_type colIdx2) noexcept
Definition: NdArrayCore.hpp:4672
NdArray(const std::initializer_list< std::initializer_list< dtype > > &inList)
Definition: NdArrayCore.hpp:239
reference at(index_type inRowIndex, index_type inColIndex)
Definition: NdArrayCore.hpp:1068
self_type & put(const RowIndices &inRowIndices, const ColIndices &inColIndices, const value_type &inValue)
Definition: NdArrayCore.hpp:3814
self_type repeat(const Shape &inRepeatShape) const
Definition: NdArrayCore.hpp:4236
self_type at(Slice rowSlice, const Indices &colIndices) const
Definition: NdArrayCore.hpp:1256
reference back(size_type row)
Definition: NdArrayCore.hpp:2320
iterator end(size_type inRow)
Definition: NdArrayCore.hpp:1635
self_type operator()(const RowIndices &rowIndices, const ColIndices &colIndices) const
Definition: NdArrayCore.hpp:980
void tofile(const std::string &inFilename, const char inSep) const
Definition: NdArrayCore.hpp:4726
const_column_iterator ccolbegin() const noexcept
Definition: NdArrayCore.hpp:1442
NdArray(std::array< dtype, ArraySize > &inArray, PointerPolicy policy=PointerPolicy::COPY)
Definition: NdArrayCore.hpp:274
NdArray(const std::deque< std::deque< dtype > > &in2dDeque)
Definition: NdArrayCore.hpp:469
self_type & reshape(size_type inSize)
Definition: NdArrayCore.hpp:4271
typename AllocTraits::pointer pointer
Definition: NdArrayCore.hpp:152
self_type transpose() const
Definition: NdArrayCore.hpp:4882
reverse_iterator rbegin(size_type inRow)
Definition: NdArrayCore.hpp:1481
NdArray(std::vector< dtype > &inVector, PointerPolicy policy=PointerPolicy::COPY)
Definition: NdArrayCore.hpp:348
NdArray< size_type > argsort(Axis inAxis=Axis::NONE) const
Definition: NdArrayCore.hpp:2117
const_reverse_column_iterator rcolend() const noexcept
Definition: NdArrayCore.hpp:1881
self_type rows(const NdArray< size_type > &inRows) const
Definition: NdArrayCore.hpp:4490
const dtype & const_reference
Definition: NdArrayCore.hpp:155
bool issquare() const noexcept
Definition: NdArrayCore.hpp:3009
bool isflat() const noexcept
Definition: NdArrayCore.hpp:2945
Endian endianess() const noexcept
Definition: NdArrayCore.hpp:2792
self_type dot(const self_type &inOtherArray) const
Definition: NdArrayCore.hpp:2719
void tofile(const std::string &inFilename) const
Definition: NdArrayCore.hpp:4710
const_reverse_column_iterator crcolbegin() const noexcept
Definition: NdArrayCore.hpp:1596
self_type & swapRows(index_type rowIdx1, index_type rowIdx2) noexcept
Definition: NdArrayCore.hpp:4690
const_reverse_column_iterator crcolend(size_type inCol) const
Definition: NdArrayCore.hpp:1916
size_type numCols() const noexcept
Definition: NdArrayCore.hpp:3465
column_iterator colbegin(size_type inCol)
Definition: NdArrayCore.hpp:1404
self_type median(Axis inAxis=Axis::NONE) const
Definition: NdArrayCore.hpp:3131
const_reference at(index_type inRowIndex, index_type inColIndex) const
Definition: NdArrayCore.hpp:1081
self_type at(const Slice &inSlice) const
Definition: NdArrayCore.hpp:1111
NdArray< bool > none(Axis inAxis=Axis::NONE) const
Definition: NdArrayCore.hpp:3411
pointer data() noexcept
Definition: NdArrayCore.hpp:2600
bool isempty() const noexcept
Definition: NdArrayCore.hpp:2932
column_iterator colbegin() noexcept
Definition: NdArrayCore.hpp:1392
NdArray(std::vector< std::array< dtype, Dim1Size > > &in2dArray, PointerPolicy policy=PointerPolicy::COPY)
Definition: NdArrayCore.hpp:416
const_reference front(size_type row) const
Definition: NdArrayCore.hpp:2882
reverse_column_iterator rcolend(size_type inCol)
Definition: NdArrayCore.hpp:1866
self_type column(size_type inColumn) const
Definition: NdArrayCore.hpp:2412
self_type prod(Axis inAxis=Axis::NONE) const
Definition: NdArrayCore.hpp:3603
NdArray(Iterator inFirst, Iterator inLast)
Definition: NdArrayCore.hpp:521
reference at(index_type inIndex)
Definition: NdArrayCore.hpp:1034
const Shape & shape() const noexcept
Definition: NdArrayCore.hpp:4511
reverse_column_iterator rcolbegin() noexcept
Definition: NdArrayCore.hpp:1546
self_type at(const Indices &inIndices) const
Definition: NdArrayCore.hpp:1141
const_iterator cbegin(size_type inRow) const
Definition: NdArrayCore.hpp:1377
const_column_iterator ccolend(size_type inCol) const
Definition: NdArrayCore.hpp:1839
self_type at(index_type rowIndex, const Indices &colIndices) const
Definition: NdArrayCore.hpp:1241
self_type & resizeFast(size_type inNumRows, size_type inNumCols)
Definition: NdArrayCore.hpp:4371
const_iterator cend(size_type inRow) const
Definition: NdArrayCore.hpp:1685
NdArray< size_type > flatnonzero() const
Definition: NdArrayCore.hpp:2821
self_type & byteswap() noexcept
Definition: NdArrayCore.hpp:2333
self_type & ravel()
Definition: NdArrayCore.hpp:4179
self_type getByIndices(const NdArray< size_type > &inIndices) const
Definition: NdArrayCore.hpp:2905
const_reverse_column_iterator rcolend(size_type inCol) const
Definition: NdArrayCore.hpp:1893
NdArray(const std::vector< std::vector< dtype > > &in2dVector)
Definition: NdArrayCore.hpp:382
self_type & partition(size_type inKth, Axis inAxis=Axis::NONE)
Definition: NdArrayCore.hpp:3521
self_type & put(const Indices &inRowIndices, index_type inColIndex, const value_type &inValue)
Definition: NdArrayCore.hpp:3891
const_iterator end(size_type inRow) const
Definition: NdArrayCore.hpp:1662
self_type flatten() const
Definition: NdArrayCore.hpp:2847
self_type & replace(value_type oldValue, value_type newValue)
Definition: NdArrayCore.hpp:4248
reference back() noexcept
Definition: NdArrayCore.hpp:2298
const_reverse_column_iterator crcolend() const noexcept
Definition: NdArrayCore.hpp:1904
const_reference back(size_type row) const
Definition: NdArrayCore.hpp:2309
reverse_column_iterator rcolbegin(size_type inCol)
Definition: NdArrayCore.hpp:1558
self_type & put(Slice inRowSlice, Slice inColSlice, const self_type &inValues)
Definition: NdArrayCore.hpp:4053
iterator begin(size_type inRow)
Definition: NdArrayCore.hpp:1327
const_reverse_iterator rend() const noexcept
Definition: NdArrayCore.hpp:1727
self_type copy() const
Definition: NdArrayCore.hpp:2486
self_type round(uint8 inNumDecimals=0) const
Definition: NdArrayCore.hpp:4457
std::vector< dtype > toStlVector() const
Definition: NdArrayCore.hpp:4812
self_type swapaxes() const
Definition: NdArrayCore.hpp:4659
const_reverse_column_iterator rcolbegin(size_type inCol) const
Definition: NdArrayCore.hpp:1585
typename AllocTraits::difference_type difference_type
Definition: NdArrayCore.hpp:158
const_iterator end() const noexcept
Definition: NdArrayCore.hpp:1650
NdArray< dtypeOut > astype() const
Definition: NdArrayCore.hpp:2181
self_type & put(index_type inRowIndex, const Slice &inColSlice, const self_type &inValues)
Definition: NdArrayCore.hpp:4122
bool ownsInternalData() noexcept
Definition: NdArrayCore.hpp:3501
self_type operator[](const NdArray< bool > &inMask) const
Definition: NdArrayCore.hpp:835
self_type & fill(value_type inFillValue) noexcept
Definition: NdArrayCore.hpp:2808
column_iterator colend() noexcept
Definition: NdArrayCore.hpp:1777
NdArray(std::initializer_list< dtype > inList)
Definition: NdArrayCore.hpp:222
self_type at(const Indices &rowIndices, Slice colSlice) const
Definition: NdArrayCore.hpp:1227
const_reference back() const noexcept
Definition: NdArrayCore.hpp:2287
std::pair< NdArray< size_type >, NdArray< size_type > > nonzero() const
Definition: NdArrayCore.hpp:4967
self_type diagonal(index_type inOffset=0, Axis inAxis=Axis::ROW) const
Definition: NdArrayCore.hpp:2639
self_type & put(index_type inRowIndex, const Indices &inColIndices, const self_type &inValues)
Definition: NdArrayCore.hpp:4105
std::reverse_iterator< const_iterator > const_reverse_iterator
Definition: NdArrayCore.hpp:163
self_type at(const Slice &inRowSlice, index_type inColIndex) const
Definition: NdArrayCore.hpp:1183
NdArray(const_pointer inPtr, UIntType1 numRows, UIntType2 numCols)
Definition: NdArrayCore.hpp:558
NdArray< bool > any(Axis inAxis=Axis::NONE) const
Definition: NdArrayCore.hpp:1979
NdArray(const self_type &inOtherArray)
Definition: NdArrayCore.hpp:633
NdArray(self_type &&inOtherArray) noexcept
Definition: NdArrayCore.hpp:651
uint64 nbytes() const noexcept
Definition: NdArrayCore.hpp:3233
NdArray< size_type > argmax(Axis inAxis=Axis::NONE) const
Definition: NdArrayCore.hpp:2024
self_type at(const NdArray< bool > &inMask) const
Definition: NdArrayCore.hpp:1123
NdArray(const std::list< dtype > &inList)
Definition: NdArrayCore.hpp:501
NdArray()=default
self_type & put(const Indices &inRowIndices, index_type inColIndex, const self_type &inValues)
Definition: NdArrayCore.hpp:4070
const_reference front() const noexcept
Definition: NdArrayCore.hpp:2860
~NdArray() noexcept
Definition: NdArrayCore.hpp:668
Slice rSlice(index_type inStartIdx=0, size_type inStepSize=1) const
Definition: NdArrayCore.hpp:1022
reference front() noexcept
Definition: NdArrayCore.hpp:2871
self_type & put(const Slice &inRowSlice, index_type inColIndex, const self_type &inValues)
Definition: NdArrayCore.hpp:4087
self_type & put(Slice inRowSlice, const ColIndices &inColIndices, const self_type &inValues)
Definition: NdArrayCore.hpp:4037
self_type & put(const Slice &inRowSlice, index_type inColIndex, const value_type &inValue)
Definition: NdArrayCore.hpp:3908
NdArray(size_type inNumRows, size_type inNumCols)
Definition: NdArrayCore.hpp:196
self_type & putMask(const NdArray< bool > &inMask, const value_type &inValue)
Definition: NdArrayCore.hpp:4135
Allocator allocator_type
Definition: NdArrayCore.hpp:151
self_type & nans() noexcept
Definition: NdArrayCore.hpp:3216
NdArray(pointer inPtr, UIntType1 numRows, UIntType2 numCols, PointerPolicy policy)
Definition: NdArrayCore.hpp:599
void print() const
Definition: NdArrayCore.hpp:3587
const_reverse_column_iterator crcolbegin(size_type inCol) const
Definition: NdArrayCore.hpp:1608
self_type & reshape(const Shape &inShape)
Definition: NdArrayCore.hpp:4356
size_type numRows() const noexcept
Definition: NdArrayCore.hpp:3477
reverse_iterator rend(size_type inRow)
Definition: NdArrayCore.hpp:1712
NdArray(size_type inSquareSize)
Definition: NdArrayCore.hpp:182
self_type at(const Indices &rowIndices, index_type colIndex) const
Definition: NdArrayCore.hpp:1212
reverse_iterator rend() noexcept
Definition: NdArrayCore.hpp:1700
const_reverse_iterator rend(size_type inRow) const
Definition: NdArrayCore.hpp:1739
typename AllocTraits::const_pointer const_pointer
Definition: NdArrayCore.hpp:153
self_type & put(const Indices &inIndices, const self_type &inValues)
Definition: NdArrayCore.hpp:3749
self_type & operator=(value_type inValue) noexcept
Definition: NdArrayCore.hpp:714
const_reverse_iterator crbegin() const noexcept
Definition: NdArrayCore.hpp:1519
NdArray(const_pointer inPtr, UIntType size)
Definition: NdArrayCore.hpp:541
const_column_iterator colend(size_type inCol) const
Definition: NdArrayCore.hpp:1816
std::reverse_iterator< iterator > reverse_iterator
Definition: NdArrayCore.hpp:162
const_reverse_iterator rbegin(size_type inRow) const
Definition: NdArrayCore.hpp:1508
self_type operator[](const Indices &inIndices) const
Definition: NdArrayCore.hpp:849
const_iterator cend() const noexcept
Definition: NdArrayCore.hpp:1673
self_type & resizeSlow(const Shape &inShape)
Definition: NdArrayCore.hpp:4442
self_type & operator=(self_type &&rhs) noexcept
Definition: NdArrayCore.hpp:731
std::string str() const
Definition: NdArrayCore.hpp:4582
std::reverse_iterator< const_column_iterator > const_reverse_column_iterator
Definition: NdArrayCore.hpp:168
self_type cumsum(Axis inAxis=Axis::NONE) const
Definition: NdArrayCore.hpp:2552
NdArray< bool > all(Axis inAxis=Axis::NONE) const
Definition: NdArrayCore.hpp:1935
self_type & resizeFast(const Shape &inShape)
Definition: NdArrayCore.hpp:4386
self_type & put(index_type inRowIndex, const Indices &inColIndices, const value_type &inValue)
Definition: NdArrayCore.hpp:3926
reference front(size_type row)
Definition: NdArrayCore.hpp:2893
self_type & put(const RowIndices &inRowIndices, Slice inColSlice, const self_type &inValues)
Definition: NdArrayCore.hpp:4020
NdArray(std::array< std::array< dtype, Dim1Size >, Dim0Size > &in2dArray, PointerPolicy policy=PointerPolicy::COPY)
Definition: NdArrayCore.hpp:310
self_type repeat(size_type inNumRows, size_type inNumCols) const
Definition: NdArrayCore.hpp:4195
const_iterator begin(size_type inRow) const
Definition: NdArrayCore.hpp:1354
iterator begin() noexcept
Definition: NdArrayCore.hpp:1315
const_column_iterator colbegin() const noexcept
Definition: NdArrayCore.hpp:1419
bool isscalar() const noexcept
Definition: NdArrayCore.hpp:2956
std::reverse_iterator< column_iterator > reverse_column_iterator
Definition: NdArrayCore.hpp:167
self_type operator()(Slice inRowSlice, Slice inColSlice) const
Definition: NdArrayCore.hpp:870
self_type & put(const Slice &inSlice, const value_type &inValue)
Definition: NdArrayCore.hpp:3779
self_type newbyteorder(Endian inEndianess) const
Definition: NdArrayCore.hpp:3248
value_type item() const
Definition: NdArrayCore.hpp:3022
const_reference at(index_type inIndex) const
Definition: NdArrayCore.hpp:1046
self_type & reshape(index_type inNumRows, index_type inNumCols)
Definition: NdArrayCore.hpp:4302
const_column_iterator colend() const noexcept
Definition: NdArrayCore.hpp:1804
self_type row(size_type inRow) const
Definition: NdArrayCore.hpp:4478
self_type operator()(const Indices &rowIndices, index_type colIndex) const
Definition: NdArrayCore.hpp:915
self_type at(const Slice &inRowSlice, const Slice &inColSlice) const
Definition: NdArrayCore.hpp:1170
self_type operator()(Slice inRowSlice, index_type inColIndex) const
Definition: NdArrayCore.hpp:884
const_reverse_iterator crend() const noexcept
Definition: NdArrayCore.hpp:1750
self_type operator()(index_type rowIndex, const Indices &colIndices) const
Definition: NdArrayCore.hpp:946
NdArray< dtype, Allocator > self_type
Definition: NdArrayCore.hpp:149
const_column_iterator colbegin(size_type inCol) const
Definition: NdArrayCore.hpp:1431
self_type & put(const Slice &inSlice, const self_type &inValues)
Definition: NdArrayCore.hpp:3794
self_type & put(const Indices &inIndices, const value_type &inValue)
Definition: NdArrayCore.hpp:3728
self_type cumprod(Axis inAxis=Axis::NONE) const
Definition: NdArrayCore.hpp:2500
const_column_iterator ccolend() const noexcept
Definition: NdArrayCore.hpp:1827
reference operator()(index_type inRowIndex, index_type inColIndex) noexcept
Definition: NdArrayCore.hpp:787
self_type operator()(index_type inRowIndex, Slice inColSlice) const
Definition: NdArrayCore.hpp:899
reverse_column_iterator rcolend() noexcept
Definition: NdArrayCore.hpp:1854
const_reverse_iterator rbegin() const noexcept
Definition: NdArrayCore.hpp:1496
NdArray(const std::deque< dtype > &inDeque)
Definition: NdArrayCore.hpp:452
void dump(const std::string &inFilename) const
Definition: NdArrayCore.hpp:2765
dtype & reference
Definition: NdArrayCore.hpp:154
self_type & put(const RowIndices &inRowIndices, const Slice &inColSlice, const value_type &inValue)
Definition: NdArrayCore.hpp:3841
self_type & put(index_type inRowIndex, const Slice &inColSlice, const value_type &inValue)
Definition: NdArrayCore.hpp:3943
value_type trace(size_type inOffset=0, Axis inAxis=Axis::ROW) const noexcept
Definition: NdArrayCore.hpp:4829
pointer dataRelease() noexcept
Definition: NdArrayCore.hpp:2622
self_type ptp(Axis inAxis=Axis::NONE) const
Definition: NdArrayCore.hpp:3647
self_type clip(value_type inMin, value_type inMax) const
Definition: NdArrayCore.hpp:2373
self_type getByMask(const NdArray< bool > &inMask) const
Definition: NdArrayCore.hpp:2919
uint32 size_type
Definition: NdArrayCore.hpp:156
NdArray< bool > issorted(Axis inAxis=Axis::NONE) const
Definition: NdArrayCore.hpp:2968
self_type & operator=(const self_type &rhs)
Definition: NdArrayCore.hpp:690
const_iterator begin() const noexcept
Definition: NdArrayCore.hpp:1342
column_iterator colend(size_type inCol)
Definition: NdArrayCore.hpp:1789
NdArray< size_type > argmin(Axis inAxis=Axis::NONE) const
Definition: NdArrayCore.hpp:2071
const_reference operator[](index_type inIndex) const noexcept
Definition: NdArrayCore.hpp:769
self_type operator()(Slice rowSlice, const Indices &colIndices) const
Definition: NdArrayCore.hpp:962
const_reference operator()(index_type inRowIndex, index_type inColIndex) const noexcept
Definition: NdArrayCore.hpp:800
self_type min(Axis inAxis=Axis::NONE) const
Definition: NdArrayCore.hpp:3085
self_type & putMask(const NdArray< bool > &inMask, const self_type &inValues)
Definition: NdArrayCore.hpp:4152
dtype value_type
Definition: NdArrayCore.hpp:150
reference operator[](index_type inIndex) noexcept
Definition: NdArrayCore.hpp:757
Slice cSlice(index_type inStartIdx=0, size_type inStepSize=1) const
Definition: NdArrayCore.hpp:1008
self_type & sort(Axis inAxis=Axis::NONE)
Definition: NdArrayCore.hpp:4538
self_type & put(const Slice &inRowSlice, const Slice &inColSlice, const value_type &inValue)
Definition: NdArrayCore.hpp:3874
const_reverse_iterator crend(size_type inRow) const
Definition: NdArrayCore.hpp:1762
const_reverse_iterator crbegin(size_type inRow) const
Definition: NdArrayCore.hpp:1531
int32 index_type
Definition: NdArrayCore.hpp:157
NdArray(const Shape &inShape)
Definition: NdArrayCore.hpp:209
self_type sum(Axis inAxis=Axis::NONE) const
Definition: NdArrayCore.hpp:4618
self_type operator()(const Indices &rowIndices, Slice colSlice) const
Definition: NdArrayCore.hpp:931
self_type & put(index_type inRow, index_type inCol, const value_type &inValue)
Definition: NdArrayCore.hpp:3710
self_type & put(index_type inIndex, const value_type &inValue)
Definition: NdArrayCore.hpp:3693
Custom iterator for NdArray.
Definition: NdArrayIterators.hpp:313
A Shape Class for NdArrays.
Definition: Core/Shape.hpp:41
uint32 rows
Definition: Core/Shape.hpp:44
uint32 cols
Definition: Core/Shape.hpp:45
uint32 size() const noexcept
Definition: Core/Shape.hpp:104
A Class for slicing into NdArrays.
Definition: Slice.hpp:45
int32 step
Definition: Slice.hpp:50
int32 start
Definition: Slice.hpp:48
uint32 numElements(uint32 inArraySize)
Definition: Slice.hpp:195
constexpr auto j
Definition: Core/Constants.hpp:42
const double nan
NaN.
Definition: Core/Constants.hpp:41
bool isLittleEndian() noexcept
Definition: Endian.hpp:43
dtype byteSwap(dtype value) noexcept
Definition: Endian.hpp:63
dtype f(GeneratorType &generator, dtype inDofN, dtype inDofD)
Definition: f.hpp:56
bool any_of(InputIt first, InputIt last, UnaryPredicate p) noexcept
Definition: StlAlgorithms.hpp:76
void sort(RandomIt first, RandomIt last) noexcept
Definition: StlAlgorithms.hpp:696
bool none_of(InputIt first, InputIt last, UnaryPredicate p) noexcept
Definition: StlAlgorithms.hpp:405
ForwardIt max_element(ForwardIt first, ForwardIt last) noexcept
Definition: StlAlgorithms.hpp:285
void stable_sort(RandomIt first, RandomIt last) noexcept
Definition: StlAlgorithms.hpp:734
OutputIt transform(InputIt first, InputIt last, OutputIt destination, UnaryOperation unaryFunction)
Definition: StlAlgorithms.hpp:775
bool all_of(InputIt first, InputIt last, UnaryPredicate p) noexcept
Definition: StlAlgorithms.hpp:55
void for_each(InputIt first, InputIt last, UnaryFunction f)
Definition: StlAlgorithms.hpp:225
InputIt find(InputIt first, InputIt last, const T &value) noexcept
Definition: StlAlgorithms.hpp:205
void replace(ForwardIt first, ForwardIt last, const T &oldValue, const T &newValue) noexcept
Definition: StlAlgorithms.hpp:468
std::pair< ForwardIt, ForwardIt > minmax_element(ForwardIt first, ForwardIt last) noexcept
Definition: StlAlgorithms.hpp:364
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:124
std::enable_if_t< is_ndarray_int_v< T >, int > ndarray_int_concept
Definition: NdArrayCore.hpp:131
constexpr bool is_ndarray_int_v
Definition: NdArrayCore.hpp:97
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:49
Definition: Cartesian.hpp:40
constexpr dtype power(dtype inValue, uint8 inExponent) noexcept
Definition: Functions/power.hpp:52
uint32 size(const NdArray< dtype > &inArray) noexcept
Definition: size.hpp:43
std::pair< NdArray< uint32 >, NdArray< uint32 > > nonzero(const NdArray< dtype > &inArray)
Definition: nonzero.hpp:48
NdArray< dtype > & resizeSlow(NdArray< dtype > &inArray, uint32 inNumRows, uint32 inNumCols)
Definition: resizeSlow.hpp:52
void swap(NdArray< dtype > &inArray1, NdArray< dtype > &inArray2) noexcept
Definition: swap.hpp:42
Axis
Enum To describe an axis.
Definition: Enums.hpp:36
std::int64_t int64
Definition: Types.hpp:35
NdArray< dtype > & put(NdArray< dtype > &inArray, int32 inIndex, const dtype &inValue)
Definition: put.hpp:46
auto abs(dtype inValue) noexcept
Definition: abs.hpp:49
std::uint64_t uint64
Definition: Types.hpp:39
NdArray< dtype > & resizeFast(NdArray< dtype > &inArray, uint32 inNumRows, uint32 inNumCols)
Definition: resizeFast.hpp:50
Endian
Enum for endianess.
Definition: Enums.hpp:46
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 > & reshape(NdArray< dtype > &inArray, uint32 inSize)
Definition: reshape.hpp:51
PointerPolicy
Policy for NdArray constructor that takes in a pointer to data.
Definition: Enums.hpp:56
NdArray< dtype > repeat(const NdArray< dtype > &inArray, uint32 inNumRows, uint32 inNumCols)
Definition: repeat.hpp:49
std::uint32_t uint32
Definition: Types.hpp:40
NdArray< dtype > transpose(const NdArray< dtype > &inArray)
Definition: transpose.hpp:45
void dump(const NdArray< dtype > &inArray, const std::string &inFilename)
Definition: dump.hpp:45
Definition: NdArrayCore.hpp:78
Definition: NdArrayCore.hpp:105