NumCpp  2.16.1
A Templatized Header Only C++ Implementation of the Python NumPy Library
Loading...
Searching...
No Matches
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>
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>
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:
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:
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:
183 shape_{ inSquareSize, inSquareSize },
184 size_{ inSquareSize * inSquareSize }
185 {
186 newArray();
187 }
188
189 //============================================================================
190 // Method Description:
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,
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>
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 {
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) :
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 {
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>
522 shape_{ 1, static_cast<uint32>(std::distance(inFirst, inLast)) },
523 size_{ shape_.size() }
524 {
525 newArray();
526 if (size_ > 0)
527 {
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>
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>
559 shape_(numRows, numCols),
560 size_{ shape_.size() }
561 {
562 newArray();
563 if (inPtr != nullptr && size_ > 0)
564 {
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>
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>
600 shape_(numRows, numCols),
601 size_{ shape_.size() }
602 {
603 switch (policy)
604 {
606 {
607 newArray();
608 if (inPtr != nullptr && size_ > 0)
609 {
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:
634 shape_{ inOtherArray.shape_ },
635 size_{ inOtherArray.size_ },
636 endianess_{ inOtherArray.endianess_ }
637 {
638 newArray();
639 if (size_ > 0)
640 {
642 }
643 }
644
645 //============================================================================
646 // Method Description:
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:
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:
715 {
716 if (array_ != nullptr)
717 {
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:
770 {
771 if (inIndex < 0)
772 {
773 inIndex += size_;
774 }
775
776 return array_[inIndex];
777 }
778
779 //============================================================================
780 // Method Description:
788 {
789 return const_cast<reference>(const_cast<const self_type*>(this)->operator()(inRowIndex, inColIndex));
790 }
791
792 //============================================================================
793 // Method Description:
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:
827
828 //============================================================================
829 // Method Description:
836 {
837 return operator[](inMask.flatnonzero());
838 }
839
840 //============================================================================
841 // Method Description:
848 template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
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:
874
875 //============================================================================
876 // Method Description:
889
890 //============================================================================
891 // Method Description:
904
905 //============================================================================
906 // Method Description:
914 template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
920
921 //============================================================================
922 // Method Description:
930 template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
935
936 //============================================================================
937 // Method Description:
945 template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
951
952 //============================================================================
953 // Method Description:
961 template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
966
967 //============================================================================
968 // Method Description:
976 template<typename RowIndices,
977 typename ColIndices,
981 {
983
985 for (auto rowIter = rowIndices.begin(); rowIter != rowIndices.end(); ++rowIter)
986 {
988 for (auto colIter = colIndices.begin(); colIter != colIndices.end(); ++colIter)
989 {
991 }
992
993 ++rowCounter;
994 }
995
996 return returnArray;
997 }
998
999 //============================================================================
1000 // Method Description:
1009 {
1010 return Slice(inStartIdx, shape_.cols, inStepSize); // NOLINT(modernize-return-braced-init-list)
1011 }
1012
1013 //============================================================================
1014 // Method Description:
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:
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:
1069 {
1070 return const_cast<reference>(const_cast<const self_type*>(this)->at(inRowIndex, inColIndex));
1071 }
1072
1073 //============================================================================
1074 // Method Description:
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:
1112 {
1113 return at(toIndices(inSlice, Axis::NONE));
1114 }
1115
1116 //============================================================================
1117 // Method Description:
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>
1142 {
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:
1171 {
1172 return at(toIndices(inRowSlice, Axis::ROW), toIndices(inColSlice, Axis::COL));
1173 }
1174
1175 //============================================================================
1176 // Method Description:
1184 {
1186 return at(toIndices(inRowSlice, Axis::ROW), colIndices);
1187 }
1188
1189 //============================================================================
1190 // Method Description:
1198 {
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>
1213 {
1215 return at(rowIndices, colIndices);
1216 }
1217
1218 //============================================================================
1219 // Method Description:
1226 template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
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>
1242 {
1244 return at(rowIndices, colIndices);
1245 }
1246
1247 //============================================================================
1248 // Method Description:
1255 template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
1257 {
1258 return at(toIndices(rowSlice, Axis::ROW), colIndices);
1259 }
1260
1261 //============================================================================
1262 // Method Description:
1269 template<typename RowIndices,
1270 typename ColIndices,
1274 {
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
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:
2120 [[nodiscard]] NdArray<size_type> argpartition(size_type inKth, Axis inAxis = Axis::NONE) const
2121 {
2123
2124 switch (inAxis)
2125 {
2126 case Axis::NONE:
2127 {
2128 if (inKth >= size_)
2129 {
2130 std::string errStr = "kth(=" + utils::num2str(inKth);
2131 errStr += ") out of bounds (" + utils::num2str(size_) + ")";
2133 }
2134
2135 std::vector<size_type> idx(size_);
2136 std::iota(idx.begin(), idx.end(), 0);
2137
2138 const auto comparitor = [this](size_type i1, size_type i2) noexcept -> bool
2139 { return (*this)[i1] < (*this)[i2]; };
2140
2141 stl_algorithms::nth_element(idx.begin(), idx.begin() + inKth, idx.end(), comparitor);
2142 return NdArray<size_type>(idx); // NOLINT(modernize-return-braced-init-list)
2143 }
2144 case Axis::COL:
2145 {
2146 if (inKth >= shape_.cols)
2147 {
2148 std::string errStr = "kth(=" + utils::num2str(inKth);
2149 errStr += ") out of bounds (" + utils::num2str(shape_.cols) + ")";
2151 }
2152
2153 NdArray<size_type> returnArray(shape_);
2154 std::vector<size_type> idx(shape_.cols);
2155
2156 for (uint32 row = 0; row < shape_.rows; ++row)
2157 {
2158 std::iota(idx.begin(), idx.end(), 0);
2159
2160 const auto comparitor = [this, row](size_type i1, size_type i2) noexcept -> bool
2161 { return operator()(row, i1) < operator()(row, i2); };
2162
2163 stl_algorithms::nth_element(idx.begin(), idx.begin() + inKth, idx.end(), comparitor);
2164
2165 for (index_type col = 0; col < static_cast<index_type>(shape_.cols); ++col)
2166 {
2167 returnArray(row, col) = idx[static_cast<size_type>(col)];
2168 }
2169 }
2170 return returnArray;
2171 }
2172 case Axis::ROW:
2173 {
2174 return transpose().argpartition(inKth, Axis::COL).transpose();
2175 }
2176 default:
2177 {
2178 THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
2179 return {}; // get rid of compiler warning
2180 }
2181 }
2182 }
2183
2184 //============================================================================
2185 // Method Description:
2193 [[nodiscard]] NdArray<size_type> argsort(Axis inAxis = Axis::NONE) const
2194 {
2196
2197 switch (inAxis)
2198 {
2199 case Axis::NONE:
2200 {
2201 std::vector<size_type> idx(size_);
2202 std::iota(idx.begin(), idx.end(), 0);
2203
2204 const auto comparitor = [this](size_type i1, size_type i2) noexcept -> bool
2205 { return (*this)[i1] < (*this)[i2]; };
2206
2207 stl_algorithms::stable_sort(idx.begin(), idx.end(), comparitor);
2208 return NdArray<size_type>(idx); // NOLINT(modernize-return-braced-init-list)
2209 }
2210 case Axis::COL:
2211 {
2212 NdArray<size_type> returnArray(shape_);
2213 std::vector<size_type> idx(shape_.cols);
2214
2215 for (index_type row = 0; row < static_cast<index_type>(shape_.rows); ++row)
2216 {
2217 std::iota(idx.begin(), idx.end(), 0);
2218
2219 const auto comparitor = [this, row](size_type i1, size_type i2) noexcept -> bool
2220 { return operator()(row, i1) < operator()(row, i2); };
2221
2222 stl_algorithms::stable_sort(idx.begin(), idx.end(), comparitor);
2223
2224 for (index_type col = 0; col < static_cast<index_type>(shape_.cols); ++col)
2225 {
2226 returnArray(row, col) = idx[static_cast<size_type>(col)];
2227 }
2228 }
2229 return returnArray;
2230 }
2231 case Axis::ROW:
2232 {
2233 return transpose().argsort(Axis::COL).transpose();
2234 }
2235 default:
2236 {
2237 THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
2238 return {}; // get rid of compiler warning
2239 }
2240 }
2241 }
2242
2243 //============================================================================
2244 // Method Description:
2252 template<typename dtypeOut,
2253 typename dtype_ = dtype,
2254 std::enable_if_t<std::is_same_v<dtype_, dtype>, int> = 0,
2255 std::enable_if_t<std::is_arithmetic_v<dtype_>, int> = 0,
2256 std::enable_if_t<std::is_arithmetic_v<dtypeOut>, int> = 0>
2257 [[nodiscard]] NdArray<dtypeOut> astype() const
2258 {
2259 if constexpr (std::is_same_v<dtypeOut, dtype>)
2260 {
2261 return *this;
2262 }
2263 else
2264 {
2265 NdArray<dtypeOut> outArray(shape_);
2266 stl_algorithms::transform(cbegin(),
2267 cend(),
2268 outArray.begin(),
2269 [](dtype value) -> dtypeOut { return static_cast<dtypeOut>(value); });
2270
2271 return outArray;
2272 }
2273 }
2274
2275 //============================================================================
2276 // Method Description:
2284 template<typename dtypeOut,
2285 typename dtype_ = dtype,
2286 std::enable_if_t<std::is_same_v<dtype_, dtype>, int> = 0,
2287 std::enable_if_t<std::is_arithmetic_v<dtype_>, int> = 0,
2288 std::enable_if_t<is_complex_v<dtypeOut>, int> = 0>
2289 [[nodiscard]] NdArray<dtypeOut> astype() const
2290 {
2291 NdArray<dtypeOut> outArray(shape_);
2292
2293 const auto function = [](const_reference value) -> dtypeOut
2294 { return std::complex<typename dtypeOut::value_type>(value); };
2295
2296 stl_algorithms::transform(cbegin(), cend(), outArray.begin(), function);
2297
2298 return outArray;
2299 }
2300
2301 //============================================================================
2302 // Method Description:
2310 template<typename dtypeOut,
2311 typename dtype_ = dtype,
2312 std::enable_if_t<std::is_same_v<dtype_, dtype>, int> = 0,
2313 std::enable_if_t<is_complex_v<dtype_>, int> = 0,
2314 std::enable_if_t<is_complex_v<dtypeOut>, int> = 0>
2315 [[nodiscard]] NdArray<dtypeOut> astype() const
2316 {
2317 if constexpr (std::is_same_v<dtypeOut, dtype>)
2318 {
2319 return *this;
2320 }
2321 else
2322 {
2323 const auto function = [](const_reference value) noexcept -> dtypeOut
2324 { return complex_cast<typename dtypeOut::value_type>(value); };
2325
2326 NdArray<dtypeOut> outArray(shape_);
2327 stl_algorithms::transform(cbegin(), cend(), outArray.begin(), function);
2328 return outArray;
2329 }
2330 }
2331
2332 //============================================================================
2333 // Method Description:
2341 template<typename dtypeOut,
2342 typename dtype_ = dtype,
2343 std::enable_if_t<std::is_same_v<dtype_, dtype>, int> = 0,
2344 std::enable_if_t<is_complex_v<dtype_>, int> = 0,
2345 std::enable_if_t<std::is_arithmetic_v<dtypeOut>, int> = 0>
2346 [[nodiscard]] NdArray<dtypeOut> astype() const
2347 {
2348 NdArray<dtypeOut> outArray(shape_);
2349
2350 const auto function = [](const_reference value) -> dtypeOut { return static_cast<dtypeOut>(value.real()); };
2351
2352 stl_algorithms::transform(cbegin(), cend(), outArray.begin(), function);
2353
2354 return outArray;
2355 }
2356
2357 //============================================================================
2358 // Method Description:
2363 [[nodiscard]] const_reference back() const noexcept
2364 {
2365 return *(cend() - 1);
2366 }
2367
2368 //============================================================================
2369 // Method Description:
2374 reference back() noexcept
2375 {
2376 return *(end() - 1);
2377 }
2378
2379 //============================================================================
2380 // Method Description:
2385 [[nodiscard]] const_reference back(size_type row) const
2386 {
2387 return *(cend(row) - 1);
2388 }
2389
2390 //============================================================================
2391 // Method Description:
2397 {
2398 return *(end(row) - 1);
2399 }
2400
2401 //============================================================================
2402 // Method Description:
2410 {
2411 STATIC_ASSERT_INTEGER(dtype);
2412
2413 stl_algorithms::for_each(begin(),
2414 end(),
2415 [](dtype& value) noexcept -> void { value = endian::byteSwap(value); });
2416
2417 switch (endianess_)
2418 {
2419 case Endian::NATIVE:
2420 {
2421 endianess_ = endian::isLittleEndian() ? Endian::BIG : Endian::LITTLE;
2422 break;
2423 }
2424 case Endian::LITTLE:
2425 {
2426 endianess_ = Endian::BIG;
2427 break;
2428 }
2429 case Endian::BIG:
2430 {
2431 endianess_ = Endian::LITTLE;
2432 break;
2433 }
2434 }
2435
2436 return *this;
2437 }
2438
2439 //============================================================================
2440 // Method Description:
2449 [[nodiscard]] self_type clip(value_type inMin, value_type inMax) const
2450 {
2452
2453 self_type outArray(shape_);
2454 stl_algorithms::transform(cbegin(),
2455 cend(),
2456 outArray.begin(),
2457 [inMin, inMax](dtype value) noexcept -> dtype
2458 {
2459#ifdef __cpp_lib_clamp
2460 const auto comparitor = [](dtype lhs, dtype rhs) noexcept -> bool
2461 { return lhs < rhs; };
2462
2463 return std::clamp(value, inMin, inMax, comparitor);
2464#else
2465 if (value < inMin)
2466 {
2467 return inMin;
2468 }
2469 else if (value > inMax)
2470 {
2471 return inMax;
2472 }
2473
2474 return value;
2475#endif
2476 });
2477
2478 return outArray;
2479 }
2480
2481 //============================================================================
2482 // Method Description:
2488 [[nodiscard]] self_type column(size_type inColumn) const
2489 {
2490 return operator()(rSlice(), inColumn);
2491 }
2492
2493 //============================================================================
2494 // Method Description:
2500 [[nodiscard]] self_type columns(const NdArray<size_type>& inCols) const
2501 {
2502 auto returnArray = self_type(shape_.rows, inCols.size());
2503 const auto rSlice = returnArray.rSlice();
2504
2505 for (size_type i = 0; i < inCols.size(); ++i)
2506 {
2507 returnArray.put(rSlice, i, column(inCols[i]));
2508 }
2509
2510 return returnArray;
2511 }
2512
2513 //============================================================================
2514 // Method Description:
2521 [[nodiscard]] NdArray<bool> contains(value_type inValue, Axis inAxis = Axis::NONE) const
2522 {
2524
2525 switch (inAxis)
2526 {
2527 case Axis::NONE:
2528 {
2529 NdArray<bool> returnArray = { stl_algorithms::find(cbegin(), cend(), inValue) != cend() };
2530 return returnArray;
2531 }
2532 case Axis::COL:
2533 {
2534 NdArray<bool> returnArray(1, shape_.rows);
2535 for (size_type row = 0; row < shape_.rows; ++row)
2536 {
2537 returnArray(0, row) = stl_algorithms::find(cbegin(row), cend(row), inValue) != cend(row);
2538 }
2539
2540 return returnArray;
2541 }
2542 case Axis::ROW:
2543 {
2544 return transpose().contains(inValue, Axis::COL);
2545 }
2546 default:
2547 {
2548 THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
2549 return {}; // get rid of compiler warning
2550 }
2551 }
2552 }
2553
2554 //============================================================================
2555 // Method Description:
2562 [[nodiscard]] self_type copy() const
2563 {
2564 return self_type(*this);
2565 }
2566
2567 //============================================================================
2568 // Method Description:
2576 [[nodiscard]] self_type cumprod(Axis inAxis = Axis::NONE) const
2577 {
2579
2580 switch (inAxis)
2581 {
2582 case Axis::NONE:
2583 {
2584 self_type returnArray(1, size_);
2585 returnArray[0] = front();
2586 for (size_type i = 1; i < size_; ++i)
2587 {
2588 returnArray[i] = returnArray[i - 1] * array_[i];
2589 }
2590
2591 return returnArray;
2592 }
2593 case Axis::COL:
2594 {
2595 self_type returnArray(shape_);
2596 for (uint32 row = 0; row < shape_.rows; ++row)
2597 {
2598 returnArray(row, 0) = operator()(row, 0);
2599 for (uint32 col = 1; col < shape_.cols; ++col)
2600 {
2601 returnArray(row, col) = returnArray(row, col - 1) * operator()(row, col);
2602 }
2603 }
2604
2605 return returnArray;
2606 }
2607 case Axis::ROW:
2608 {
2609 return transpose().cumprod(Axis::COL).transpose();
2610 }
2611 default:
2612 {
2613 THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
2614 return {}; // get rid of compiler warning
2615 }
2616 }
2617 }
2618
2619 //============================================================================
2620 // Method Description:
2628 [[nodiscard]] self_type cumsum(Axis inAxis = Axis::NONE) const
2629 {
2631
2632 switch (inAxis)
2633 {
2634 case Axis::NONE:
2635 {
2636 self_type returnArray(1, size_);
2637 returnArray[0] = front();
2638 for (size_type i = 1; i < size_; ++i)
2639 {
2640 returnArray[i] = returnArray[i - 1] + array_[i];
2641 }
2642
2643 return returnArray;
2644 }
2645 case Axis::COL:
2646 {
2647 self_type returnArray(shape_);
2648 for (uint32 row = 0; row < shape_.rows; ++row)
2649 {
2650 returnArray(row, 0) = operator()(row, 0);
2651 for (uint32 col = 1; col < shape_.cols; ++col)
2652 {
2653 returnArray(row, col) = returnArray(row, col - 1) + operator()(row, col);
2654 }
2655 }
2656
2657 return returnArray;
2658 }
2659 case Axis::ROW:
2660 {
2661 return transpose().cumsum(Axis::COL).transpose();
2662 }
2663 default:
2664 {
2665 THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
2666 return {}; // get rid of compiler warning
2667 }
2668 }
2669 }
2670
2671 //============================================================================
2672 // Method Description:
2676 [[nodiscard]] pointer data() noexcept
2677 {
2678 return array_;
2679 }
2680
2681 //============================================================================
2682 // Method Description:
2686 [[nodiscard]] const_pointer data() const noexcept
2687 {
2688 return array_;
2689 }
2690
2691 //============================================================================
2692 // Method Description:
2698 [[nodiscard]] pointer dataRelease() noexcept
2699 {
2700 ownsPtr_ = false;
2701 return data();
2702 }
2703
2704 //============================================================================
2705 // Method Description:
2715 [[nodiscard]] self_type diagonal(index_type inOffset = 0, Axis inAxis = Axis::ROW) const
2716 {
2717 switch (inAxis)
2718 {
2719 case Axis::COL:
2720 {
2721 std::vector<dtype> diagnolValues;
2722 size_type col = 0;
2723 for (index_type row = inOffset; row < static_cast<index_type>(shape_.rows); ++row)
2724 {
2725 if (row < 0)
2726 {
2727 ++col;
2728 continue;
2729 }
2730 if (col >= shape_.cols)
2731 {
2732 break;
2733 }
2734
2735 diagnolValues.push_back(operator()(static_cast<size_type>(row), col));
2736 ++col;
2737 }
2738
2739 return self_type(diagnolValues);
2740 }
2741 case Axis::ROW:
2742 {
2743 return transpose().diagonal(inOffset, Axis::COL);
2744 }
2745 default:
2746 {
2747 THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
2748 return {}; // get rid of compiler warning
2749 }
2750 }
2751 }
2752
2753 //============================================================================
2754 // Method Description:
2760 [[nodiscard]] size_type dimSize(Axis inAxis) const noexcept
2761 {
2762 switch (inAxis)
2763 {
2764 case Axis::NONE:
2765 {
2766 return size();
2767 }
2768 case Axis::ROW:
2769 {
2770 return numRows();
2771 }
2772 case Axis::COL:
2773 {
2774 return numCols();
2775 }
2776 default:
2777 {
2778 return {}; // get rid of compiler warning
2779 }
2780 }
2781 }
2782
2783 //============================================================================
2784 // Method Description:
2795 [[nodiscard]] self_type dot(const self_type& inOtherArray) const
2796 {
2798
2799 if (shape_ == inOtherArray.shape_ && (shape_.rows == 1 || shape_.cols == 1))
2800 {
2801 dtype dotProduct =
2802 stl_algorithms::transform_reduce(cbegin(), cend(), inOtherArray.cbegin(), dtype{ 0 });
2803 self_type returnArray = { dotProduct };
2804 return returnArray;
2805 }
2806
2807 if (shape_.cols == inOtherArray.shape_.rows)
2808 {
2809 // 2D array, use matrix multiplication
2810 self_type returnArray(shape_.rows, inOtherArray.shape_.cols);
2811 auto otherArrayT = inOtherArray.transpose();
2812
2813 for (uint32 i = 0; i < shape_.rows; ++i)
2814 {
2815 for (uint32 j = 0; j < otherArrayT.shape_.rows; ++j)
2816 {
2817 returnArray(i, j) = stl_algorithms::transform_reduce(otherArrayT.cbegin(j),
2818 otherArrayT.cend(j),
2819 cbegin(i),
2820 dtype{ 0 });
2821 }
2822 }
2823
2824 return returnArray;
2825 }
2826
2827 std::string errStr = "shapes of [" + utils::num2str(shape_.rows) + ", " + utils::num2str(shape_.cols) + "]";
2828 errStr += " and [" + utils::num2str(inOtherArray.shape_.rows) + ", " +
2829 utils::num2str(inOtherArray.shape_.cols) + "]";
2830 errStr += " are not consistent.";
2832
2833 return self_type(); // get rid of compiler warning
2834 }
2835
2836 //============================================================================
2837 // Method Description:
2845 void dump(const std::string& inFilename) const
2846 {
2847 std::filesystem::path f(inFilename);
2848 if (!f.has_extension())
2849 {
2850 f.replace_extension("bin");
2851 }
2852
2853 std::ofstream ofile(f.c_str(), std::ios::binary);
2854 if (!ofile.good())
2855 {
2856 THROW_RUNTIME_ERROR("Unable to open the input file:\n\t" + inFilename);
2857 }
2858
2859 if (array_ != nullptr)
2860 {
2861 ofile.write(reinterpret_cast<const char*>(array_), size_ * sizeof(dtype));
2862 }
2863 ofile.close();
2864 }
2865
2866 //============================================================================
2867 // Method Description:
2872 [[nodiscard]] Endian endianess() const noexcept
2873 {
2875
2876 return endianess_;
2877 }
2878
2879 //============================================================================
2880 // Method Description:
2888 self_type& fill(value_type inFillValue) noexcept
2889 {
2890 stl_algorithms::fill(begin(), end(), inFillValue);
2891 return *this;
2892 }
2893
2894 //============================================================================
2895 // Method Description:
2901 [[nodiscard]] NdArray<size_type> flatnonzero() const
2902 {
2904
2905 std::vector<size_type> indices;
2906 size_type idx = 0;
2907 for (auto value : *this)
2908 {
2909 if (!utils::essentiallyEqual(value, dtype{ 0 }))
2910 {
2911 indices.push_back(idx);
2912 }
2913 ++idx;
2914 }
2915
2916 return NdArray<size_type>(indices); // NOLINT(modernize-return-braced-init-list)
2917 }
2918
2919 //============================================================================
2920 // Method Description:
2927 [[nodiscard]] self_type flatten() const
2928 {
2929 self_type outArray(1, size_);
2930 stl_algorithms::copy(cbegin(), cend(), outArray.begin());
2931 return outArray;
2932 }
2933
2934 //============================================================================
2935 // Method Description:
2940 [[nodiscard]] const_reference front() const noexcept
2941 {
2942 return *cbegin();
2943 }
2944
2945 //============================================================================
2946 // Method Description:
2951 reference front() noexcept
2952 {
2953 return *begin();
2954 }
2955
2956 //============================================================================
2957 // Method Description:
2962 [[nodiscard]] const_reference front(size_type row) const
2963 {
2964 return *cbegin(row);
2965 }
2966
2967 //============================================================================
2968 // Method Description:
2974 {
2975 return *begin(row);
2976 }
2977
2978 //============================================================================
2979 // Method Description:
2985 [[nodiscard]] self_type getByIndices(const NdArray<size_type>& inIndices) const
2986 {
2987 return operator[](inIndices);
2988 }
2989
2990 //============================================================================
2991 // Method Description:
2999 [[nodiscard]] self_type getByMask(const NdArray<bool>& inMask) const
3000 {
3001 return operator[](inMask);
3002 }
3003
3004 //============================================================================
3005 // Method Description:
3011 // NOLINTNEXTLINE(modernize-use-nodiscard)
3012 bool isempty() const noexcept
3013 {
3014 return size_ == 0;
3015 }
3016
3017 //============================================================================
3018 // Method Description:
3024 // NOLINTNEXTLINE(modernize-use-nodiscard)
3025 bool isflat() const noexcept
3026 {
3027 return !isscalar() && (shape_.rows == 1 || shape_.cols == 1);
3028 }
3029
3030 //============================================================================
3031 // Method Description:
3035 // NOLINTNEXTLINE(modernize-use-nodiscard)
3036 bool isscalar() const noexcept
3037 {
3038 return size_ == 1;
3039 }
3040
3041 //============================================================================
3042 // Method Description:
3048 [[nodiscard]] NdArray<bool> issorted(Axis inAxis = Axis::NONE) const
3049 {
3051
3052 const auto comparitor = [](dtype lhs, dtype rhs) noexcept -> bool { return lhs < rhs; };
3053
3054 switch (inAxis)
3055 {
3056 case Axis::NONE:
3057 {
3058 return { stl_algorithms::is_sorted(cbegin(), cend(), comparitor) };
3059 }
3060 case Axis::COL:
3061 {
3062 NdArray<bool> returnArray(1, shape_.rows);
3063 for (uint32 row = 0; row < shape_.rows; ++row)
3064 {
3065 returnArray(0, row) = stl_algorithms::is_sorted(cbegin(row), cend(row), comparitor);
3066 }
3067
3068 return returnArray;
3069 }
3070 case Axis::ROW:
3071 {
3072 return transpose().issorted(Axis::COL);
3073 }
3074 default:
3075 {
3076 THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
3077 return {}; // get rid of compiler warning
3078 }
3079 }
3080 }
3081
3082 //============================================================================
3083 // Method Description:
3088 // NOLINTNEXTLINE(modernize-use-nodiscard)
3089 bool issquare() const noexcept
3090 {
3091 return shape_.issquare();
3092 }
3093
3094 //============================================================================
3095 // Method Description:
3102 [[nodiscard]] value_type item() const
3103 {
3104 if (!isscalar())
3105 {
3106 THROW_INVALID_ARGUMENT_ERROR("Can only convert an array of size 1 to a C++ scalar");
3107 }
3108
3109 return front();
3110 }
3111
3112 //============================================================================
3113 // Method Description:
3121 [[nodiscard]] self_type max(Axis inAxis = Axis::NONE) const
3122 {
3124
3125 const auto comparitor = [](dtype lhs, dtype rhs) noexcept -> bool { return lhs < rhs; };
3126
3127 switch (inAxis)
3128 {
3129 case Axis::NONE:
3130 {
3131 self_type returnArray = { *stl_algorithms::max_element(cbegin(), cend(), comparitor) };
3132 return returnArray;
3133 }
3134 case Axis::COL:
3135 {
3136 self_type returnArray(1, shape_.rows);
3137 for (uint32 row = 0; row < shape_.rows; ++row)
3138 {
3139 returnArray(0, row) = *stl_algorithms::max_element(cbegin(row), cend(row), comparitor);
3140 }
3141
3142 return returnArray;
3143 }
3144 case Axis::ROW:
3145 {
3146 return transpose().max(Axis::COL);
3147 }
3148 default:
3149 {
3150 THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
3151 return {}; // get rid of compiler warning
3152 }
3153 }
3154 }
3155
3156 //============================================================================
3157 // Method Description:
3165 [[nodiscard]] self_type min(Axis inAxis = Axis::NONE) const
3166 {
3168
3169 const auto comparitor = [](dtype lhs, dtype rhs) noexcept -> bool { return lhs < rhs; };
3170
3171 switch (inAxis)
3172 {
3173 case Axis::NONE:
3174 {
3175 self_type returnArray = { *stl_algorithms::min_element(cbegin(), cend(), comparitor) };
3176 return returnArray;
3177 }
3178 case Axis::COL:
3179 {
3180 self_type returnArray(1, shape_.rows);
3181 for (uint32 row = 0; row < shape_.rows; ++row)
3182 {
3183 returnArray(0, row) = *stl_algorithms::min_element(cbegin(row), cend(row), comparitor);
3184 }
3185
3186 return returnArray;
3187 }
3188 case Axis::ROW:
3189 {
3190 return transpose().min(Axis::COL);
3191 }
3192 default:
3193 {
3194 THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
3195 return {}; // get rid of compiler warning
3196 }
3197 }
3198 }
3199
3200 //============================================================================
3201 // Method Description:
3211 [[nodiscard]] self_type median(Axis inAxis = Axis::NONE) const
3212 {
3214
3215 const auto comparitor = [](dtype lhs, dtype rhs) noexcept -> bool { return lhs < rhs; };
3216
3217 if (size_ == 0)
3218 {
3219 THROW_RUNTIME_ERROR("Median is undefined for an array of size = 0.");
3220 }
3221
3222 switch (inAxis)
3223 {
3224 case Axis::NONE:
3225 {
3226 self_type copyArray(*this);
3227
3228 const size_type middleIdx = size_ / 2; // integer division
3229 stl_algorithms::nth_element(copyArray.begin(),
3230 copyArray.begin() + middleIdx,
3231 copyArray.end(),
3232 comparitor);
3233
3234 dtype medianValue = copyArray.array_[middleIdx];
3235 if (size_ % 2 == 0)
3236 {
3237 const size_type lhsIndex = middleIdx - 1;
3238 stl_algorithms::nth_element(copyArray.begin(),
3239 copyArray.begin() + lhsIndex,
3240 copyArray.end(),
3241 comparitor);
3242 medianValue =
3243 (medianValue + copyArray.array_[lhsIndex]) / dtype{ 2 }; // potentially integer division, ok
3244 }
3245
3246 return { medianValue };
3247 }
3248 case Axis::COL:
3249 {
3250 self_type copyArray(*this);
3251 self_type returnArray(1, shape_.rows);
3252
3253 const bool isEven = shape_.cols % 2 == 0;
3254 for (uint32 row = 0; row < shape_.rows; ++row)
3255 {
3256 const uint32 middleIdx = shape_.cols / 2; // integer division
3257 stl_algorithms::nth_element(copyArray.begin(row),
3258 copyArray.begin(row) + middleIdx,
3259 copyArray.end(row),
3260 comparitor);
3261
3262 dtype medianValue = copyArray(row, middleIdx);
3263 if (isEven)
3264 {
3265 const size_type lhsIndex = middleIdx - 1;
3266 stl_algorithms::nth_element(copyArray.begin(row),
3267 copyArray.begin(row) + lhsIndex,
3268 copyArray.end(row),
3269 comparitor);
3270 medianValue = (medianValue + copyArray(row, lhsIndex)) /
3271 dtype{ 2 }; // potentially integer division, ok
3272 }
3273
3274 returnArray(0, row) = medianValue;
3275 }
3276
3277 return returnArray;
3278 }
3279 case Axis::ROW:
3280 {
3281 return transpose().median(Axis::COL);
3282 }
3283 default:
3284 {
3285 THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
3286 return {}; // get rid of compiler warning
3287 }
3288 }
3289 }
3290
3291 //============================================================================
3292 // Method Description:
3296 self_type& nans() noexcept
3297
3298 {
3299 STATIC_ASSERT_FLOAT(dtype);
3300
3301 fill(constants::nan);
3302 return *this;
3303 }
3304
3305 //============================================================================
3306 // Method Description:
3313 [[nodiscard]] uint64 nbytes() const noexcept
3314 {
3315 return static_cast<uint64>(sizeof(dtype) * size_);
3316 }
3317
3318 //============================================================================
3319 // Method Description:
3328 [[nodiscard]] self_type newbyteorder(Endian inEndianess) const
3329 {
3330 STATIC_ASSERT_INTEGER(dtype);
3331
3332 const bool nativeIsLittle = endian::isLittleEndian();
3333
3334 switch (endianess_)
3335 {
3336 case Endian::NATIVE:
3337 {
3338 switch (inEndianess)
3339 {
3340 case Endian::NATIVE:
3341 {
3342 return NdArray(*this);
3343 }
3344 case Endian::BIG:
3345 {
3346 if (nativeIsLittle)
3347 {
3348 self_type outArray(shape_);
3349
3350 stl_algorithms::transform(cbegin(), end(), outArray.begin(), endian::byteSwap<dtype>);
3351
3352 outArray.endianess_ = Endian::BIG;
3353 return outArray;
3354 }
3355 else
3356 {
3357 auto outArray = NdArray(*this);
3358 outArray.endianess_ = Endian::BIG;
3359 return outArray;
3360 }
3361 }
3362 case Endian::LITTLE:
3363 {
3364 if (nativeIsLittle)
3365 {
3366 auto outArray = NdArray(*this);
3367 outArray.endianess_ = Endian::LITTLE;
3368 return outArray;
3369 }
3370 else
3371 {
3372 self_type outArray(shape_);
3373
3374 stl_algorithms::transform(cbegin(), end(), outArray.begin(), endian::byteSwap<dtype>);
3375
3376 outArray.endianess_ = Endian::LITTLE;
3377 return outArray;
3378 }
3379 }
3380 default:
3381 {
3382 THROW_INVALID_ARGUMENT_ERROR("Unimplemented endian type.");
3383 return {}; // get rid of compiler warning
3384 }
3385 }
3386 break;
3387 }
3388 case Endian::BIG:
3389 {
3390 switch (inEndianess)
3391 {
3392 case Endian::NATIVE:
3393 {
3394 if (nativeIsLittle)
3395 {
3396 self_type outArray(shape_);
3397
3398 stl_algorithms::transform(cbegin(), end(), outArray.begin(), endian::byteSwap<dtype>);
3399
3400 outArray.endianess_ = Endian::NATIVE;
3401 return outArray;
3402 }
3403 else
3404 {
3405 auto outArray = NdArray(*this);
3406 outArray.endianess_ = Endian::NATIVE;
3407 return outArray;
3408 }
3409 }
3410 case Endian::BIG:
3411 {
3412 return NdArray(*this);
3413 }
3414 case Endian::LITTLE:
3415 {
3416 self_type outArray(shape_);
3417
3418 stl_algorithms::transform(cbegin(), end(), outArray.begin(), endian::byteSwap<dtype>);
3419
3420 outArray.endianess_ = Endian::LITTLE;
3421 return outArray;
3422 }
3423 default:
3424 {
3425 THROW_INVALID_ARGUMENT_ERROR("Unimplemented endian type.");
3426 return {}; // get rid of compiler warning
3427 }
3428 }
3429 break;
3430 }
3431 case Endian::LITTLE:
3432 {
3433 switch (inEndianess)
3434 {
3435 case Endian::NATIVE:
3436 {
3437 if (nativeIsLittle)
3438 {
3439 auto outArray = NdArray(*this);
3440 outArray.endianess_ = Endian::NATIVE;
3441 return outArray;
3442 }
3443 else
3444 {
3445 self_type outArray(shape_);
3446
3447 stl_algorithms::transform(cbegin(), end(), outArray.begin(), endian::byteSwap<dtype>);
3448
3449 outArray.endianess_ = Endian::NATIVE;
3450 return outArray;
3451 }
3452 }
3453 case Endian::BIG:
3454 {
3455 self_type outArray(shape_);
3456
3457 stl_algorithms::transform(cbegin(), end(), outArray.begin(), endian::byteSwap<dtype>);
3458
3459 outArray.endianess_ = Endian::BIG;
3460 return outArray;
3461 }
3462 case Endian::LITTLE:
3463 {
3464 return NdArray(*this);
3465 }
3466 default:
3467 {
3468 THROW_INVALID_ARGUMENT_ERROR("Unimplemented endian type.");
3469 return {}; // get rid of compiler warning
3470 }
3471 }
3472 break;
3473 }
3474 default:
3475 {
3476 THROW_INVALID_ARGUMENT_ERROR("Unimplemented endian type.");
3477 return {}; // get rid of compiler warning
3478 }
3479 }
3480 }
3481
3482 //============================================================================
3483 // Method Description:
3491 [[nodiscard]] NdArray<bool> none(Axis inAxis = Axis::NONE) const
3492 {
3494
3495 const auto function = [](dtype i) -> bool { return !utils::essentiallyEqual(i, dtype{ 0 }); };
3496
3497 switch (inAxis)
3498 {
3499 case Axis::NONE:
3500 {
3501 NdArray<bool> returnArray = { stl_algorithms::none_of(cbegin(), cend(), function) };
3502 return returnArray;
3503 }
3504 case Axis::COL:
3505 {
3506 NdArray<bool> returnArray(1, shape_.rows);
3507 for (uint32 row = 0; row < shape_.rows; ++row)
3508 {
3509 returnArray(0, row) = stl_algorithms::none_of(cbegin(row), cend(row), function);
3510 }
3511
3512 return returnArray;
3513 }
3514 case Axis::ROW:
3515 {
3516 return transpose().none(Axis::COL);
3517 }
3518 default:
3519 {
3520 THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
3521 return {}; // get rid of compiler warning
3522 }
3523 }
3524 }
3525
3526 //============================================================================
3527 // Method Description:
3536 [[nodiscard]] std::pair<NdArray<size_type>, NdArray<size_type>> nonzero() const;
3537
3538 //============================================================================
3539 // Method Description:
3545 [[nodiscard]] size_type numCols() const noexcept
3546 {
3547 return shape_.cols;
3548 }
3549
3550 //============================================================================
3551 // Method Description:
3557 [[nodiscard]] size_type numRows() const noexcept
3558 {
3559 return shape_.rows;
3560 }
3561
3562 //============================================================================
3563 // Method Description:
3567 self_type& ones() noexcept
3568 {
3570
3571 fill(dtype{ 1 });
3572 return *this;
3573 }
3574
3575 //============================================================================
3576 // Method Description:
3581 bool ownsInternalData() noexcept
3582 {
3583 return ownsPtr_;
3584 }
3585
3586 //============================================================================
3587 // Method Description:
3601 self_type& partition(size_type inKth, Axis inAxis = Axis::NONE)
3602 {
3604
3605 const auto comparitor = [](dtype lhs, dtype rhs) noexcept -> bool
3606 { return lhs < rhs; }; // cppcheck-suppress returnTempReference
3607
3608 switch (inAxis)
3609 {
3610 case Axis::NONE:
3611 {
3612 if (inKth >= size_)
3613 {
3614 std::string errStr = "kth(=" + utils::num2str(inKth);
3615 errStr += ") out of bounds (" + utils::num2str(size_) + ")";
3617 }
3618
3619 stl_algorithms::nth_element(begin(), begin() + inKth, end(), comparitor);
3620 break;
3621 }
3622 case Axis::COL:
3623 {
3624 if (inKth >= shape_.cols)
3625 {
3626 std::string errStr = "kth(=" + utils::num2str(inKth);
3627 errStr += ") out of bounds (" + utils::num2str(shape_.cols) + ")";
3629 }
3630
3631 for (uint32 row = 0; row < shape_.rows; ++row)
3632 {
3633 stl_algorithms::nth_element(begin(row), begin(row) + inKth, end(row), comparitor);
3634 }
3635 break;
3636 }
3637 case Axis::ROW:
3638 {
3639 if (inKth >= shape_.rows)
3640 {
3641 std::string errStr = "kth(=" + utils::num2str(inKth);
3642 errStr += ") out of bounds (" + utils::num2str(shape_.rows) + ")";
3644 }
3645
3646 self_type transposedArray = transpose();
3647 for (uint32 row = 0; row < transposedArray.shape_.rows; ++row)
3648 {
3649 stl_algorithms::nth_element(transposedArray.begin(row),
3650 transposedArray.begin(row) + inKth,
3651 transposedArray.end(row),
3652 comparitor);
3653 }
3654 *this = transposedArray.transpose();
3655 break;
3656 }
3657 }
3658
3659 return *this;
3660 }
3661
3662 //============================================================================
3663 // Method Description:
3667 void print() const
3668 {
3670
3671 std::cout << *this;
3672 }
3673
3674 //============================================================================
3675 // Method Description:
3683 [[nodiscard]] self_type prod(Axis inAxis = Axis::NONE) const
3684 {
3686
3687 switch (inAxis)
3688 {
3689 case Axis::NONE:
3690 {
3691 dtype product = std::accumulate(cbegin(), cend(), dtype{ 1 }, std::multiplies<dtype>());
3692 self_type returnArray = { product };
3693 return returnArray;
3694 }
3695 case Axis::COL:
3696 {
3697 self_type returnArray(1, shape_.rows);
3698 for (uint32 row = 0; row < shape_.rows; ++row)
3699 {
3700 returnArray(0, row) =
3701 std::accumulate(cbegin(row), cend(row), dtype{ 1 }, std::multiplies<dtype>());
3702 }
3703
3704 return returnArray;
3705 }
3706 case Axis::ROW:
3707 {
3708 return transpose().prod(Axis::COL);
3709 }
3710 default:
3711 {
3712 THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
3713 return {}; // get rid of compiler warning
3714 }
3715 }
3716 }
3717
3718 //============================================================================
3719 // Method Description:
3727 [[nodiscard]] self_type ptp(Axis inAxis = Axis::NONE) const
3728 {
3730
3731 const auto comparitor = [](dtype lhs, dtype rhs) noexcept -> bool { return lhs < rhs; };
3732
3733 switch (inAxis)
3734 {
3735 case Axis::NONE:
3736 {
3737 const auto result = stl_algorithms::minmax_element(cbegin(), cend(), comparitor);
3738 self_type returnArray = { *result.second - *result.first };
3739 return returnArray;
3740 }
3741 case Axis::COL:
3742 {
3743 self_type returnArray(1, shape_.rows);
3744 for (uint32 row = 0; row < shape_.rows; ++row)
3745 {
3746 const auto result = stl_algorithms::minmax_element(cbegin(row), cend(row), comparitor);
3747 returnArray(0, row) = *result.second - *result.first;
3748 }
3749
3750 return returnArray;
3751 }
3752 case Axis::ROW:
3753 {
3754 return transpose().ptp(Axis::COL);
3755 }
3756 default:
3757 {
3758 THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
3759 return {}; // get rid of compiler warning
3760 }
3761 }
3762 }
3763
3764 //============================================================================
3765 // Method Description:
3773 self_type& put(index_type inIndex, const value_type& inValue)
3774 {
3775 at(inIndex) = inValue;
3776
3777 return *this;
3778 }
3779
3780 //============================================================================
3781 // Method Description:
3790 self_type& put(index_type inRow, index_type inCol, const value_type& inValue)
3791 {
3792 at(inRow, inCol) = inValue;
3793
3794 return *this;
3795 }
3796
3797 //============================================================================
3798 // Method Description:
3807 template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
3808 self_type& put(const Indices& inIndices, const value_type& inValue)
3809 {
3810 for (auto index : inIndices)
3811 {
3812 put(index, inValue);
3813 }
3814
3815 return *this;
3816 }
3817
3818 //============================================================================
3819 // Method Description:
3828 template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
3829 self_type& put(const Indices& inIndices, const self_type& inValues)
3830 {
3831 if (inValues.isscalar())
3832 {
3833 return put(inIndices, inValues.item());
3834 }
3835 else if (inIndices.size() != inValues.size())
3836 {
3837 THROW_INVALID_ARGUMENT_ERROR("Input indices do not match values dimensions.");
3838 }
3839
3840 size_type counter = 0;
3841 for (auto index : inIndices)
3842 {
3843 put(index, inValues[counter++]);
3844 }
3845
3846 return *this;
3847 }
3848
3849 //============================================================================
3850 // Method Description:
3859 self_type& put(const Slice& inSlice, const value_type& inValue)
3860 {
3861 return put(toIndices(inSlice, Axis::NONE), inValue);
3862 }
3863
3864 //============================================================================
3865 // Method Description:
3874 self_type& put(const Slice& inSlice, const self_type& inValues)
3875 {
3876 return put(toIndices(inSlice, Axis::NONE), inValues);
3877 }
3878
3879 //============================================================================
3880 // Method Description:
3890 template<typename RowIndices,
3891 typename ColIndices,
3894 self_type& put(const RowIndices& inRowIndices, const ColIndices& inColIndices, const value_type& inValue)
3895 {
3896 stl_algorithms::for_each(inRowIndices.begin(),
3897 inRowIndices.end(),
3898 [this, &inColIndices, &inValue](const auto row)
3899 {
3900 stl_algorithms::for_each(inColIndices.begin(),
3901 inColIndices.end(),
3902 [this, row, &inValue](const auto col)
3903 { this->put(row, col, inValue); });
3904 });
3905
3906 return *this;
3907 }
3908
3909 //============================================================================
3910 // Method Description:
3920 template<typename RowIndices, type_traits::ndarray_int_concept<RowIndices> = 0>
3921 self_type& put(const RowIndices& inRowIndices, const Slice& inColSlice, const value_type& inValue)
3922 {
3923 return put(inRowIndices, toIndices(inColSlice, Axis::COL), inValue);
3924 }
3925
3926 //============================================================================
3927 // Method Description:
3937 template<typename ColIndices, type_traits::ndarray_int_concept<ColIndices> = 0>
3938 self_type& put(const Slice& inRowSlice, const ColIndices& inColIndices, const value_type& inValue)
3939 {
3940 return put(toIndices(inRowSlice, Axis::ROW), inColIndices, inValue);
3941 }
3942
3943 //============================================================================
3944 // Method Description:
3954 self_type& put(const Slice& inRowSlice, const Slice& inColSlice, const value_type& inValue)
3955 {
3956 return put(toIndices(inRowSlice, Axis::ROW), toIndices(inColSlice, Axis::COL), inValue);
3957 }
3958
3959 //============================================================================
3960 // Method Description:
3970 template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
3971 self_type& put(const Indices& inRowIndices, index_type inColIndex, const value_type& inValue)
3972 {
3973 const NdArray<index_type> colIndices = { inColIndex };
3974 return put(inRowIndices, colIndices, inValue);
3975 }
3976
3977 //============================================================================
3978 // Method Description:
3988 self_type& put(const Slice& inRowSlice, index_type inColIndex, const value_type& inValue)
3989 {
3990 const NdArray<index_type> colIndices = { inColIndex };
3991 return put(toIndices(inRowSlice, Axis::ROW), colIndices, inValue);
3992 }
3993
3994 //============================================================================
3995 // Method Description:
4005 template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
4006 self_type& put(index_type inRowIndex, const Indices& inColIndices, const value_type& inValue)
4007 {
4008 const NdArray<index_type> rowIndices = { inRowIndex };
4009 return put(rowIndices, inColIndices, inValue);
4010 }
4011
4012 //============================================================================
4013 // Method Description:
4023 self_type& put(index_type inRowIndex, const Slice& inColSlice, const value_type& inValue)
4024 {
4025 const NdArray<index_type> rowIndices = { inRowIndex };
4026 return put(rowIndices, toIndices(inColSlice, Axis::COL), inValue);
4027 }
4028
4029 //============================================================================
4030 // Method Description:
4040 template<typename RowIndices,
4041 typename ColIndices,
4044 self_type& put(const RowIndices& inRowIndices, const ColIndices& inColIndices, const self_type& inValues)
4045 {
4046 std::vector<size_type> indices;
4047 indices.reserve(inRowIndices.size() * inColIndices.size());
4048 std::for_each(inRowIndices.begin(),
4049 inRowIndices.end(),
4050 [this, &inColIndices, &indices](auto row)
4051 {
4052 if constexpr (std::is_signed_v<decltype(row)>)
4053 {
4054 if (row < 0)
4055 {
4056 row += shape_.rows;
4057 }
4058 // still
4059 if (row < 0)
4060 {
4061 THROW_INVALID_ARGUMENT_ERROR("row index exceeds matrix dimensions");
4062 }
4063 }
4064 std::for_each(inColIndices.begin(),
4065 inColIndices.end(),
4066 [this, row, &indices](auto col)
4067 {
4068 if constexpr (std::is_signed_v<decltype(col)>)
4069 {
4070 if (col < 0)
4071 {
4072 col += shape_.cols;
4073 }
4074 // still
4075 if (col < 0)
4076 {
4077 THROW_INVALID_ARGUMENT_ERROR(
4078 "col index exceeds matrix dimensions");
4079 }
4080 }
4081 indices.push_back(row * shape_.cols + col);
4082 });
4083 });
4084
4085 return put(NdArray<size_type>(indices.data(), indices.size(), PointerPolicy::SHELL), inValues);
4086 }
4087
4088 //============================================================================
4089 // Method Description:
4099 template<typename RowIndices, type_traits::ndarray_int_concept<RowIndices> = 0>
4100 self_type& put(const RowIndices& inRowIndices, Slice inColSlice, const self_type& inValues)
4101 {
4102 return put(inRowIndices, toIndices(inColSlice, Axis::COL), inValues);
4103 }
4104
4105 //============================================================================
4106 // Method Description:
4116 template<typename ColIndices, type_traits::ndarray_int_concept<ColIndices> = 0>
4117 self_type& put(Slice inRowSlice, const ColIndices& inColIndices, const self_type& inValues)
4118 {
4119 return put(toIndices(inRowSlice, Axis::ROW), inColIndices, inValues);
4120 }
4121
4122 //============================================================================
4123 // Method Description:
4133 self_type& put(Slice inRowSlice, Slice inColSlice, const self_type& inValues)
4134 {
4135 return put(toIndices(inRowSlice, Axis::ROW), toIndices(inColSlice, Axis::COL), inValues);
4136 }
4137
4138 //============================================================================
4139 // Method Description:
4149 template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
4150 self_type& put(const Indices& inRowIndices, index_type inColIndex, const self_type& inValues)
4151 {
4152 const NdArray<index_type> colIndices = { inColIndex };
4153 return put(inRowIndices, colIndices, inValues);
4154 }
4155
4156 //============================================================================
4157 // Method Description:
4167 self_type& put(const Slice& inRowSlice, index_type inColIndex, const self_type& inValues)
4168 {
4169 const NdArray<index_type> colIndices = { inColIndex };
4170 return put(toIndices(inRowSlice, Axis::ROW), colIndices, inValues);
4171 }
4172
4173 //============================================================================
4174 // Method Description:
4184 template<typename Indices, type_traits::ndarray_int_concept<Indices> = 0>
4185 self_type& put(index_type inRowIndex, const Indices& inColIndices, const self_type& inValues)
4186 {
4187 const NdArray<index_type> rowIndices = { inRowIndex };
4188 return put(rowIndices, inColIndices, inValues);
4189 }
4190
4191 //============================================================================
4192 // Method Description:
4202 self_type& put(index_type inRowIndex, const Slice& inColSlice, const self_type& inValues)
4203 {
4204 const NdArray<index_type> rowIndices = { inRowIndex };
4205 return put(rowIndices, toIndices(inColSlice, Axis::COL), inValues);
4206 }
4207
4208 //============================================================================
4209 // Method Description:
4215 self_type& putMask(const NdArray<bool>& inMask, const value_type& inValue)
4216 {
4217 if (inMask.shape() != shape_)
4218 {
4219 THROW_INVALID_ARGUMENT_ERROR("input inMask must be the same shape as the array it is masking.");
4220 }
4221
4222 return put(inMask.flatnonzero(), inValue);
4223 }
4224
4225 //============================================================================
4226 // Method Description:
4232 self_type& putMask(const NdArray<bool>& inMask, const self_type& inValues)
4233 {
4234 if (inMask.shape() != shape_)
4235 {
4236 THROW_INVALID_ARGUMENT_ERROR("input inMask must be the same shape as the array it is masking.");
4237 }
4238
4239 if (inValues.isscalar())
4240 {
4241 put(inMask.flatnonzero(), inValues.item());
4242 }
4243 else
4244 {
4245 put(inMask.flatnonzero(), inValues);
4246 }
4247
4248 return *this;
4249 }
4250
4251 //============================================================================
4252 // Method Description:
4260 {
4261 reshape(size_);
4262 return *this;
4263 }
4264
4265 //============================================================================
4266 // Method Description:
4275 [[nodiscard]] self_type repeat(size_type inNumRows, size_type inNumCols) const
4276 {
4277 self_type returnArray(shape_.rows * inNumRows, shape_.cols * inNumCols);
4278
4279 for (size_type row = 0; row < inNumRows; ++row)
4280 {
4281 for (size_type col = 0; col < inNumCols; ++col)
4282 {
4283 std::vector<size_type> indices(shape_.size());
4284
4285 const size_type rowStart = row * shape_.rows;
4286 const size_type colStart = col * shape_.cols;
4287
4288 const size_type rowEnd = (row + 1) * shape_.rows;
4289 const size_type colEnd = (col + 1) * shape_.cols;
4290
4291 size_type counter = 0;
4292 for (size_type rowIdx = rowStart; rowIdx < rowEnd; ++rowIdx)
4293 {
4294 for (size_type colIdx = colStart; colIdx < colEnd; ++colIdx)
4295 {
4296 indices[counter++] = rowIdx * returnArray.shape_.cols + colIdx;
4297 }
4298 }
4299
4300 returnArray.put(NdArray<size_type>(indices), *this);
4301 }
4302 }
4303
4304 return returnArray;
4305 }
4306
4307 //============================================================================
4308 // Method Description:
4316 [[nodiscard]] self_type repeat(const Shape& inRepeatShape) const
4317 {
4318 return repeat(inRepeatShape.rows, inRepeatShape.cols);
4319 }
4320
4321 //============================================================================
4322 // Method Description:
4329 {
4331
4332 stl_algorithms::replace(begin(), end(), oldValue, newValue);
4333 return *this;
4334 }
4335
4336 //============================================================================
4337 // Method Description:
4352 {
4353 if (inSize != size_)
4354 {
4355 std::string errStr = "Cannot reshape array of size " + utils::num2str(size_) + " into shape ";
4356 errStr += "[" + utils::num2str(1) + ", " + utils::num2str(inSize) + "]";
4357 THROW_RUNTIME_ERROR(errStr);
4358 }
4359
4360 shape_.rows = 1;
4361 shape_.cols = inSize;
4362
4363 return *this;
4364 }
4365
4366 //============================================================================
4367 // Method Description:
4383 {
4384 if (inNumRows < 0)
4385 {
4386 if (size_ % inNumCols == 0)
4387 {
4388 return reshape(size_ / inNumCols, inNumCols);
4389 }
4390
4391 std::string errStr = "Cannot reshape array of size " + utils::num2str(size_) + " into a shape ";
4392 errStr += "with " + utils::num2str(inNumCols) + " columns";
4394 }
4395
4396 if (inNumCols < 0)
4397 {
4398 if (size_ % inNumRows == 0)
4399 {
4400 return reshape(inNumRows, size_ / inNumRows);
4401 }
4402
4403 std::string errStr = "Cannot reshape array of size " + utils::num2str(size_) + " into a shape ";
4404 errStr += "with " + utils::num2str(inNumRows) + " rows";
4406 }
4407
4408 if (static_cast<size_type>(inNumRows * inNumCols) != size_)
4409 {
4410 std::string errStr = "Cannot reshape array of size " + utils::num2str(size_) + " into shape ";
4411 errStr += "[" + utils::num2str(inNumRows) + ", " + utils::num2str(inNumCols) + "]";
4413 }
4414
4415 shape_.rows = static_cast<size_type>(inNumRows);
4416 shape_.cols = static_cast<size_type>(inNumCols);
4417
4418 return *this;
4419 }
4420
4421 //============================================================================
4422 // Method Description:
4436 self_type& reshape(const Shape& inShape)
4437 {
4438 return reshape(inShape.rows, inShape.cols);
4439 }
4440
4441 //============================================================================
4442 // Method Description:
4452 {
4453 newArray(Shape(inNumRows, inNumCols));
4454 return *this;
4455 }
4456
4457 //============================================================================
4458 // Method Description:
4466 self_type& resizeFast(const Shape& inShape)
4467 {
4468 return resizeFast(inShape.rows, inShape.cols);
4469 }
4470
4471 //============================================================================
4472 // Method Description:
4484 {
4485 std::vector<dtype> oldData(size_);
4486 stl_algorithms::copy(begin(), end(), oldData.begin());
4487
4488 const Shape inShape(inNumRows, inNumCols);
4489 const Shape oldShape = shape_;
4490
4491 newArray(inShape);
4492
4493 for (uint32 row = 0; row < inShape.rows; ++row)
4494 {
4495 for (uint32 col = 0; col < inShape.cols; ++col)
4496 {
4497 if (row >= oldShape.rows || col >= oldShape.cols)
4498 {
4499 operator()(row, col) = dtype{ 0 }; // zero fill
4500 }
4501 else
4502 {
4503 operator()(row, col) = oldData[row * oldShape.cols + col];
4504 }
4505 }
4506 }
4507
4508 return *this;
4509 }
4510
4511 //============================================================================
4512 // Method Description:
4522 self_type& resizeSlow(const Shape& inShape)
4523 {
4524 return resizeSlow(inShape.rows, inShape.cols);
4525 }
4526
4527 //============================================================================
4528 // Method Description:
4537 [[nodiscard]] self_type round(uint8 inNumDecimals = 0) const
4538 {
4539 STATIC_ASSERT_FLOAT(dtype);
4540
4541 self_type returnArray(shape_);
4542 const double multFactor = utils::power(10., inNumDecimals);
4543 const auto function = [multFactor](dtype value) noexcept -> dtype
4544 { return static_cast<dtype>(std::nearbyint(static_cast<double>(value) * multFactor) / multFactor); };
4545
4546 stl_algorithms::transform(cbegin(), cend(), returnArray.begin(), function);
4547
4548 return returnArray;
4549 }
4550
4551 //============================================================================
4552 // Method Description:
4558 [[nodiscard]] self_type row(size_type inRow) const
4559 {
4560 return self_type(cbegin(inRow), cend(inRow));
4561 }
4562
4563 //============================================================================
4564 // Method Description:
4570 [[nodiscard]] self_type rows(const NdArray<size_type>& inRows) const
4571 {
4572 auto returnArray = self_type(inRows.size(), shape_.cols);
4573 const auto cSlice = returnArray.cSlice();
4574
4575 for (size_type i = 0; i < inRows.size(); ++i)
4576 {
4577 returnArray.put(i, cSlice, row(inRows[i]));
4578 }
4579
4580 return returnArray;
4581 }
4582
4583 //============================================================================
4584 // Method Description:
4591 [[nodiscard]] const Shape& shape() const noexcept
4592 {
4593 return shape_;
4594 }
4595
4596 //============================================================================
4597 // Method Description:
4604 [[nodiscard]] size_type size() const noexcept
4605 {
4606 return size_;
4607 }
4608
4609 //============================================================================
4610 // Method Description:
4618 self_type& sort(Axis inAxis = Axis::NONE)
4619 {
4621
4622 const auto comparitor = [](dtype lhs, dtype rhs) noexcept -> bool
4623 { return lhs < rhs; }; // cppcheck-suppress returnTempReference
4624
4625 switch (inAxis)
4626 {
4627 case Axis::NONE:
4628 {
4629 stl_algorithms::sort(begin(), end(), comparitor);
4630 break;
4631 }
4632 case Axis::COL:
4633 {
4634 for (uint32 row = 0; row < shape_.rows; ++row)
4635 {
4636 stl_algorithms::sort(begin(row), end(row), comparitor);
4637 }
4638 break;
4639 }
4640 case Axis::ROW:
4641 {
4642 self_type transposedArray = transpose();
4643 for (uint32 row = 0; row < transposedArray.shape_.rows; ++row)
4644 {
4645 stl_algorithms::sort(transposedArray.begin(row), transposedArray.end(row), comparitor);
4646 }
4647
4648 *this = transposedArray.transpose();
4649 break;
4650 }
4651 }
4652
4653 return *this;
4654 }
4655
4656 //============================================================================
4657 // Method Description:
4662 [[nodiscard]] std::string str() const
4663 {
4665
4666 std::string out;
4667 out += "[";
4668 for (uint32 row = 0; row < shape_.rows; ++row)
4669 {
4670 out += "[";
4671 for (uint32 col = 0; col < shape_.cols; ++col)
4672 {
4673 out += utils::value2str(operator()(row, col)) + ", ";
4674 }
4675
4676 if (row == shape_.rows - 1)
4677 {
4678 out += "]";
4679 }
4680 else
4681 {
4682 out += "]\n";
4683 }
4684 }
4685 out += "]\n";
4686 return out;
4687 }
4688
4689 //============================================================================
4690 // Method Description:
4698 [[nodiscard]] self_type sum(Axis inAxis = Axis::NONE) const
4699 {
4701
4702 switch (inAxis)
4703 {
4704 case Axis::NONE:
4705 {
4706 self_type returnArray = { std::accumulate(cbegin(), cend(), dtype{ 0 }) };
4707 return returnArray;
4708 }
4709 case Axis::COL:
4710 {
4711 self_type returnArray(1, shape_.rows);
4712 for (uint32 row = 0; row < shape_.rows; ++row)
4713 {
4714 returnArray(0, row) = std::accumulate(cbegin(row), cend(row), dtype{ 0 });
4715 }
4716
4717 return returnArray;
4718 }
4719 case Axis::ROW:
4720 {
4721 return transpose().sum(Axis::COL);
4722 }
4723 default:
4724 {
4725 THROW_INVALID_ARGUMENT_ERROR("Unimplemented axis type.");
4726 return {}; // get rid of compiler warning
4727 }
4728 }
4729 }
4730
4731 //============================================================================
4732 // Method Description:
4739 [[nodiscard]] self_type swapaxes() const
4740 {
4741 return transpose();
4742 }
4743
4744 //============================================================================
4745 // Method Description:
4752 self_type& swapCols(index_type colIdx1, index_type colIdx2) noexcept
4753 {
4754 for (index_type row = 0; row < static_cast<index_type>(shape_.rows); ++row)
4755 {
4756 std::swap(operator()(row, colIdx1), operator()(row, colIdx2));
4757 }
4758
4759 return *this;
4760 }
4761
4762 //============================================================================
4763 // Method Description:
4770 self_type& swapRows(index_type rowIdx1, index_type rowIdx2) noexcept
4771 {
4772 for (index_type col = 0; col < static_cast<index_type>(shape_.cols); ++col)
4773 {
4774 std::swap(operator()(rowIdx1, col), operator()(rowIdx2, col));
4775 }
4776
4777 return *this;
4778 }
4779
4780 //============================================================================
4781 // Method Description:
4790 void tofile(const std::string& inFilename) const
4791 {
4792 dump(inFilename);
4793 }
4794
4795 //============================================================================
4796 // Method Description:
4806 void tofile(const std::string& inFilename, const char inSep) const
4807 {
4809
4810 std::filesystem::path f(inFilename);
4811 if (!f.has_extension())
4812 {
4813 f.replace_extension("txt");
4814 }
4815
4816 std::ofstream ofile(f.c_str());
4817 if (!ofile.good())
4818 {
4819 THROW_RUNTIME_ERROR("Input file could not be opened:\n\t" + inFilename);
4820 }
4821
4822 size_type counter = 0;
4823 for (auto value : *this)
4824 {
4825 ofile << value;
4826 if (counter++ != size_ - 1)
4827 {
4828 ofile << inSep;
4829 }
4830 }
4831 ofile << '\n';
4832 ofile.close();
4833 }
4834
4835 //============================================================================
4836 // Method Description:
4844 [[nodiscard]] NdArray<size_type> toIndices(Slice inSlice, Axis inAxis = Axis::NONE) const
4845 {
4846 size_type numElements = 0;
4847 switch (inAxis)
4848 {
4849 case Axis::NONE:
4850 {
4851 numElements = inSlice.numElements(size_);
4852 break;
4853 }
4854 case Axis::ROW:
4855 {
4856 numElements = inSlice.numElements(shape_.rows);
4857 break;
4858 }
4859 case Axis::COL:
4860 {
4861 numElements = inSlice.numElements(shape_.cols);
4862 break;
4863 }
4864 default:
4865 {
4866 // not actually possible, getting rid of compiler warning
4867 THROW_INVALID_ARGUMENT_ERROR("Invalid 'inAxis' option");
4868 }
4869 }
4870
4871 if (numElements == 0)
4872 {
4873 return {};
4874 }
4875
4876 NdArray<size_type> indices(1, numElements);
4877 indices[0] = static_cast<size_type>(inSlice.start);
4878 for (size_type i = 1; i < indices.size(); ++i)
4879 {
4880 indices[static_cast<index_type>(i)] = static_cast<size_type>(
4881 indices[static_cast<index_type>(i - size_type{ 1 })] + static_cast<size_type>(inSlice.step));
4882 }
4883
4884 return indices;
4885 }
4886
4887 //============================================================================
4888 // Method Description:
4893 [[nodiscard]] std::vector<dtype> toStlVector() const
4894 {
4895 return std::vector<dtype>(cbegin(), cend());
4896 }
4897
4898 //============================================================================
4899 // Method Description:
4910 [[nodiscard]] value_type trace(size_type inOffset = 0, Axis inAxis = Axis::ROW) const noexcept
4911 {
4913
4914 size_type rowStart = 0;
4915 size_type colStart = 0;
4916 switch (inAxis)
4917 {
4918 case Axis::ROW:
4919 {
4920 rowStart += inOffset;
4921 break;
4922 }
4923 case Axis::COL:
4924 {
4925 colStart += inOffset;
4926 break;
4927 }
4928 default:
4929 {
4930 // if the user input NONE, override back to ROW
4931 inAxis = Axis::ROW;
4932 break;
4933 }
4934 }
4935
4936 if (rowStart >= shape_.rows || colStart >= shape_.cols)
4937 {
4938 return dtype{ 0 };
4939 }
4940
4941 size_type col = colStart;
4942 dtype sum = 0;
4943 for (size_type row = rowStart; row < shape_.rows; ++row)
4944 {
4945 if (col >= shape_.cols)
4946 {
4947 break;
4948 }
4949 sum += operator()(row, col++);
4950 }
4951
4952 return sum;
4953 }
4954
4955 //============================================================================
4956 // Method Description:
4963 [[nodiscard]] self_type transpose() const
4964 {
4965 self_type transArray(shape_.cols, shape_.rows);
4966 for (uint32 row = 0; row < shape_.rows; ++row)
4967 {
4968 for (uint32 col = 0; col < shape_.cols; ++col)
4969 {
4970 transArray(col, row) = operator()(row, col);
4971 }
4972 }
4973 return transArray;
4974 }
4975
4976 //============================================================================
4977 // Method Description:
4981 self_type& zeros() noexcept
4982 {
4984
4985 fill(dtype{ 0 });
4986 return *this;
4987 }
4988
4989 private:
4990 //====================================Attributes==============================
4991 allocator_type allocator_{};
4992 Shape shape_{ 0, 0 };
4993 size_type size_{ 0 };
4994 Endian endianess_{ Endian::NATIVE };
4995 pointer array_{ nullptr };
4996 bool ownsPtr_{ false };
4997
4998 //============================================================================
4999 // Method Description:
5002 void deleteArray() noexcept
5003 {
5004 if (ownsPtr_ && array_ != nullptr)
5005 {
5006 allocator_.deallocate(array_, size_);
5007 }
5008
5009 array_ = nullptr;
5010 shape_.rows = shape_.cols = 0;
5011 size_ = 0;
5012 ownsPtr_ = false;
5013 endianess_ = Endian::NATIVE;
5014 }
5015
5016 //============================================================================
5017 // Method Description:
5020 void newArray()
5021 {
5022 if (size_ > 0)
5023 {
5024 array_ = allocator_.allocate(size_);
5025 ownsPtr_ = true;
5026 }
5027 }
5028
5029 //============================================================================
5030 // Method Description:
5035 void newArray(const Shape& inShape)
5036 {
5037 deleteArray();
5038
5039 shape_ = inShape;
5040 size_ = inShape.size();
5041 newArray();
5042 }
5043 };
5044
5045 // NOTE: this needs to be defined outside of the class to get rid of a compiler
5046 // error in Visual Studio
5047 template<typename dtype, class Alloc_>
5048 [[nodiscard]] std::pair<NdArray<uint32>, NdArray<uint32>> NdArray<dtype, Alloc_>::nonzero() const
5049 {
5051
5052 std::vector<size_type> rowIndices;
5053 std::vector<size_type> colIndices;
5054
5055 for (uint32 row = 0; row < shape_.rows; ++row)
5056 {
5057 for (uint32 col = 0; col < shape_.cols; ++col)
5058 {
5059 if (!utils::essentiallyEqual(operator()(row, col), dtype{ 0 }))
5060 {
5061 rowIndices.push_back(row);
5062 colIndices.push_back(col);
5063 }
5064 }
5065 }
5066
5067 return std::make_pair(NdArray<size_type>(rowIndices), NdArray<size_type>(colIndices));
5068 }
5069} // namespace nc
#define THROW_RUNTIME_ERROR(msg)
Definition Error.hpp:40
#define THROW_INVALID_ARGUMENT_ERROR(msg)
Definition Error.hpp:37
#define STATIC_ASSERT_VALID_DTYPE(dtype)
Definition StaticAsserts.hpp:35
#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:2760
NdArray< size_type > toIndices(Slice inSlice, Axis inAxis=Axis::NONE) const
Definition NdArrayCore.hpp:4844
self_type operator[](Slice inSlice) const
Definition NdArrayCore.hpp:823
self_type max(Axis inAxis=Axis::NONE) const
Definition NdArrayCore.hpp:3121
size_type size() const noexcept
Definition NdArrayCore.hpp:4604
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:2500
self_type & put(const RowIndices &inRowIndices, const ColIndices &inColIndices, const self_type &inValues)
Definition NdArrayCore.hpp:4044
self_type & resizeSlow(size_type inNumRows, size_type inNumCols)
Definition NdArrayCore.hpp:4483
self_type & put(const Slice &inRowSlice, const ColIndices &inColIndices, const value_type &inValue)
Definition NdArrayCore.hpp:3938
self_type & zeros() noexcept
Definition NdArrayCore.hpp:4981
self_type & ones() noexcept
Definition NdArrayCore.hpp:3567
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:2521
const_pointer data() const noexcept
Definition NdArrayCore.hpp:2686
iterator end() noexcept
Definition NdArrayCore.hpp:1623
self_type & swapCols(index_type colIdx1, index_type colIdx2) noexcept
Definition NdArrayCore.hpp:4752
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:3894
self_type repeat(const Shape &inRepeatShape) const
Definition NdArrayCore.hpp:4316
self_type at(Slice rowSlice, const Indices &colIndices) const
Definition NdArrayCore.hpp:1256
reference back(size_type row)
Definition NdArrayCore.hpp:2396
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:4806
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:4351
typename AllocTraits::pointer pointer
Definition NdArrayCore.hpp:152
self_type transpose() const
Definition NdArrayCore.hpp:4963
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:2193
const_reverse_column_iterator rcolend() const noexcept
Definition NdArrayCore.hpp:1881
self_type rows(const NdArray< size_type > &inRows) const
Definition NdArrayCore.hpp:4570
const dtype & const_reference
Definition NdArrayCore.hpp:155
bool issquare() const noexcept
Definition NdArrayCore.hpp:3089
bool isflat() const noexcept
Definition NdArrayCore.hpp:3025
Endian endianess() const noexcept
Definition NdArrayCore.hpp:2872
self_type dot(const self_type &inOtherArray) const
Definition NdArrayCore.hpp:2795
void tofile(const std::string &inFilename) const
Definition NdArrayCore.hpp:4790
const_reverse_column_iterator crcolbegin() const noexcept
Definition NdArrayCore.hpp:1596
self_type & swapRows(index_type rowIdx1, index_type rowIdx2) noexcept
Definition NdArrayCore.hpp:4770
const_reverse_column_iterator crcolend(size_type inCol) const
Definition NdArrayCore.hpp:1916
size_type numCols() const noexcept
Definition NdArrayCore.hpp:3545
column_iterator colbegin(size_type inCol)
Definition NdArrayCore.hpp:1404
self_type median(Axis inAxis=Axis::NONE) const
Definition NdArrayCore.hpp:3211
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:3491
pointer data() noexcept
Definition NdArrayCore.hpp:2676
bool isempty() const noexcept
Definition NdArrayCore.hpp:3012
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:2962
reverse_column_iterator rcolend(size_type inCol)
Definition NdArrayCore.hpp:1866
self_type column(size_type inColumn) const
Definition NdArrayCore.hpp:2488
self_type prod(Axis inAxis=Axis::NONE) const
Definition NdArrayCore.hpp:3683
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:4591
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:4451
const_iterator cend(size_type inRow) const
Definition NdArrayCore.hpp:1685
NdArray< size_type > flatnonzero() const
Definition NdArrayCore.hpp:2901
self_type & byteswap() noexcept
Definition NdArrayCore.hpp:2409
self_type & ravel()
Definition NdArrayCore.hpp:4259
self_type getByIndices(const NdArray< size_type > &inIndices) const
Definition NdArrayCore.hpp:2985
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:3601
self_type & put(const Indices &inRowIndices, index_type inColIndex, const value_type &inValue)
Definition NdArrayCore.hpp:3971
const_iterator end(size_type inRow) const
Definition NdArrayCore.hpp:1662
self_type flatten() const
Definition NdArrayCore.hpp:2927
self_type & replace(value_type oldValue, value_type newValue)
Definition NdArrayCore.hpp:4328
reference back() noexcept
Definition NdArrayCore.hpp:2374
const_reverse_column_iterator crcolend() const noexcept
Definition NdArrayCore.hpp:1904
const_reference back(size_type row) const
Definition NdArrayCore.hpp:2385
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:4133
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:2562
self_type round(uint8 inNumDecimals=0) const
Definition NdArrayCore.hpp:4537
std::vector< dtype > toStlVector() const
Definition NdArrayCore.hpp:4893
self_type swapaxes() const
Definition NdArrayCore.hpp:4739
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:2257
self_type & put(index_type inRowIndex, const Slice &inColSlice, const self_type &inValues)
Definition NdArrayCore.hpp:4202
bool ownsInternalData() noexcept
Definition NdArrayCore.hpp:3581
self_type operator[](const NdArray< bool > &inMask) const
Definition NdArrayCore.hpp:835
self_type & fill(value_type inFillValue) noexcept
Definition NdArrayCore.hpp:2888
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:2363
std::pair< NdArray< size_type >, NdArray< size_type > > nonzero() const
Definition NdArrayCore.hpp:5048
self_type diagonal(index_type inOffset=0, Axis inAxis=Axis::ROW) const
Definition NdArrayCore.hpp:2715
self_type & put(index_type inRowIndex, const Indices &inColIndices, const self_type &inValues)
Definition NdArrayCore.hpp:4185
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:3313
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:4150
const_reference front() const noexcept
Definition NdArrayCore.hpp:2940
~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:2951
self_type & put(const Slice &inRowSlice, index_type inColIndex, const self_type &inValues)
Definition NdArrayCore.hpp:4167
self_type & put(Slice inRowSlice, const ColIndices &inColIndices, const self_type &inValues)
Definition NdArrayCore.hpp:4117
self_type & put(const Slice &inRowSlice, index_type inColIndex, const value_type &inValue)
Definition NdArrayCore.hpp:3988
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:4215
Allocator allocator_type
Definition NdArrayCore.hpp:151
self_type & nans() noexcept
Definition NdArrayCore.hpp:3296
NdArray(pointer inPtr, UIntType1 numRows, UIntType2 numCols, PointerPolicy policy)
Definition NdArrayCore.hpp:599
void print() const
Definition NdArrayCore.hpp:3667
const_reverse_column_iterator crcolbegin(size_type inCol) const
Definition NdArrayCore.hpp:1608
self_type & reshape(const Shape &inShape)
Definition NdArrayCore.hpp:4436
size_type numRows() const noexcept
Definition NdArrayCore.hpp:3557
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:3829
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:4522
self_type & operator=(self_type &&rhs) noexcept
Definition NdArrayCore.hpp:731
std::string str() const
Definition NdArrayCore.hpp:4662
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:2628
NdArray< bool > all(Axis inAxis=Axis::NONE) const
Definition NdArrayCore.hpp:1935
self_type & resizeFast(const Shape &inShape)
Definition NdArrayCore.hpp:4466
self_type & put(index_type inRowIndex, const Indices &inColIndices, const value_type &inValue)
Definition NdArrayCore.hpp:4006
reference front(size_type row)
Definition NdArrayCore.hpp:2973
self_type & put(const RowIndices &inRowIndices, Slice inColSlice, const self_type &inValues)
Definition NdArrayCore.hpp:4100
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:4275
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:3036
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:3859
self_type newbyteorder(Endian inEndianess) const
Definition NdArrayCore.hpp:3328
value_type item() const
Definition NdArrayCore.hpp:3102
const_reference at(index_type inIndex) const
Definition NdArrayCore.hpp:1046
self_type & reshape(index_type inNumRows, index_type inNumCols)
Definition NdArrayCore.hpp:4382
const_column_iterator colend() const noexcept
Definition NdArrayCore.hpp:1804
self_type row(size_type inRow) const
Definition NdArrayCore.hpp:4558
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:3874
self_type & put(const Indices &inIndices, const value_type &inValue)
Definition NdArrayCore.hpp:3808
self_type cumprod(Axis inAxis=Axis::NONE) const
Definition NdArrayCore.hpp:2576
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:2845
dtype & reference
Definition NdArrayCore.hpp:154
self_type & put(const RowIndices &inRowIndices, const Slice &inColSlice, const value_type &inValue)
Definition NdArrayCore.hpp:3921
self_type & put(index_type inRowIndex, const Slice &inColSlice, const value_type &inValue)
Definition NdArrayCore.hpp:4023
value_type trace(size_type inOffset=0, Axis inAxis=Axis::ROW) const noexcept
Definition NdArrayCore.hpp:4910
pointer dataRelease() noexcept
Definition NdArrayCore.hpp:2698
self_type ptp(Axis inAxis=Axis::NONE) const
Definition NdArrayCore.hpp:3727
self_type clip(value_type inMin, value_type inMax) const
Definition NdArrayCore.hpp:2449
self_type getByMask(const NdArray< bool > &inMask) const
Definition NdArrayCore.hpp:2999
uint32 size_type
Definition NdArrayCore.hpp:156
NdArray< bool > issorted(Axis inAxis=Axis::NONE) const
Definition NdArrayCore.hpp:3048
self_type & operator=(const self_type &rhs)
Definition NdArrayCore.hpp:690
const_iterator begin() const noexcept
Definition NdArrayCore.hpp:1342
NdArray< size_type > argpartition(size_type inKth, Axis inAxis=Axis::NONE) const
Definition NdArrayCore.hpp:2120
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:3165
self_type & putMask(const NdArray< bool > &inMask, const self_type &inValues)
Definition NdArrayCore.hpp:4232
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:4618
self_type & put(const Slice &inRowSlice, const Slice &inColSlice, const value_type &inValue)
Definition NdArrayCore.hpp:3954
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:4698
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:3790
self_type & put(index_type inIndex, const value_type &inValue)
Definition NdArrayCore.hpp:3773
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
void for_each(InputIt first, InputIt last, UnaryFunction f)
Definition StlAlgorithms.hpp:226
OutputIt copy(InputIt first, InputIt last, OutputIt destination) noexcept
Definition StlAlgorithms.hpp:98
void fill(ForwardIt first, ForwardIt last, const T &value) noexcept
Definition StlAlgorithms.hpp:184
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
Definition Cartesian.hpp:40
uint32 size(const NdArray< dtype > &inArray) noexcept
Definition size.hpp:43
NdArray< dtype > & resizeSlow(NdArray< dtype > &inArray, uint32 inNumRows, uint32 inNumCols)
Definition resizeSlow.hpp:52
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
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
NdArray< dtype > arange(dtype inStart, dtype inStop, dtype inStep=1)
Definition arange.hpp:59
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