2 #ifndef SYDEVS_ARRAYND_H_
3 #define SYDEVS_ARRAYND_H_
186 template<
typename T,
int64 ndims>
189 friend class arraynd<T, ndims+1>;
210 arraynd(
const std::array<int64, ndims>&
dims,
const T& value);
229 arraynd(
const std::array<int64, ndims>&
dims,
const std::vector<T>&
data);
245 arraynd(
const std::array<int64, ndims>&
dims, std::function<T(
const std::array<int64, ndims>& indices)> func);
304 arraynd(
const std::array<int64, 1>&
dims,
const T& value);
335 arraynd(
const std::array<int64, 1>&
dims, std::function<T(
const std::array<int64, 1>& indices)> func);
379 template<
typename T,
int64 ndims>
386 template<
typename T,
int64 ndims>
393 template<
typename T,
int64 ndims>
400 template<
typename T,
int64 ndims>
407 template<
typename T,
int64 ndims>
410 return arraynd<T, ndims-1>(*
this, index,
true);
414 template<
typename T,
int64 ndims>
417 return arraynd<T, ndims-1>(*
this, index, this->is_readonly());
421 template<
typename T,
int64 ndims>
428 template<
typename T,
int64 ndims>
435 template<
typename T,
int64 ndims>
442 template<
typename T,
int64 ndims>
449 template<
typename T,
int64 ndims>
456 template<
typename T,
int64 ndims>
460 this->transpose(arr);
465 template<
typename T,
int64 ndims>
469 this->transpose(arr);
474 template<
typename T,
int64 ndims>
478 this->transpose(arr);
483 template<
typename T,
int64 ndims>
487 this->swap_axes(arr, idim0, idim1);
492 template<
typename T,
int64 ndims>
496 this->swap_axes(arr, idim0, idim1);
501 template<
typename T,
int64 ndims>
505 this->swap_axes(arr, idim0, idim1);
510 template<
typename T,
int64 ndims>
514 this->subdivide_axis(*
this, arr, idim, dims);
519 template<
typename T,
int64 ndims>
523 this->subdivide_axis(*
this, arr, idim, dims);
528 template<
typename T,
int64 ndims>
532 return arr0.view_subdivided_axis(idim, dims);
536 template<
typename T,
int64 ndims>
539 auto arr =
arraynd<T, ndims - 1>(std::array<
int64, ndims - 1>(), std::vector<T>());
540 this->absorb_axis(*
this, arr, idim);
545 template<
typename T,
int64 ndims>
548 auto arr =
arraynd<T, ndims - 1>(std::array<
int64, ndims - 1>(), std::vector<T>());
549 this->absorb_axis(*
this, arr, idim);
554 template<
typename T,
int64 ndims>
558 return arr0.view_absorbed_axis(idim);
562 template<
typename T,
int64 ndims>
569 template<
typename T,
int64 ndims>
571 : arraynd_base<T, ndims>(rhs, r, readonly)
576 template<
typename T,
int64 ndims>
578 : arraynd_base<T, ndims>(rhs, is_view, readonly)
623 if (this->
is_readonly())
throw std::logic_error(
"Attempt to obtain a non-const reference to readonly multidimensional array data");
685 return arr0.view_subdivided_axis(idim,
dims);
698 : arraynd_base<T, 1>(rhs, r, readonly)
705 : arraynd_base<T, 1>(rhs, is_view, readonly)
712 template<
typename T,
int64 ndims>
716 for (
int64 idim = 0; okay && idim < ndims; ++idim) {
717 okay = (lhs.
dims()[idim] == rhs.
dims()[idim]);
723 template<
typename T,
int64 ndims>
726 return arraynd<decltype(+(*rhs.
data())), ndims>(rhs.
dims(), [&rhs](
const std::array<int64, ndims>& indices) {
727 return +rhs(indices);
732 template<
typename T,
int64 ndims>
735 return arraynd<decltype(-(*rhs.
data())), ndims>(rhs.
dims(), [&rhs](
const std::array<int64, ndims>& indices) {
736 return -rhs(indices);
741 template<
typename T,
int64 ndims>
744 if (!
aligned(lhs, rhs))
throw std::domain_error(
"Attempt to apply + operator to multidimensional arrays with inconsistent dimensions");
745 return arraynd<decltype((*lhs.
data()) + (*rhs.
data())), ndims>(lhs.
dims(), [&lhs, &rhs](
const std::array<int64, ndims>& indices) {
746 return lhs(indices) + rhs(indices);
751 template<
typename T,
int64 ndims>
754 if (!
aligned(lhs, rhs))
throw std::domain_error(
"Attempt to apply - operator to multidimensional arrays with inconsistent dimensions");
755 return arraynd<decltype((*lhs.
data()) - (*rhs.
data())), ndims>(lhs.
dims(), [&lhs, &rhs](
const std::array<int64, ndims>& indices) {
756 return lhs(indices) - rhs(indices);
761 template<
typename T,
int64 ndims>
764 if (!
aligned(lhs, rhs))
throw std::domain_error(
"Attempt to apply * operator to multidimensional arrays with inconsistent dimensions");
765 return arraynd<decltype((*lhs.
data()) * (*rhs.
data())), ndims>(lhs.
dims(), [&lhs, &rhs](
const std::array<int64, ndims>& indices) {
766 return lhs(indices)*rhs(indices);
771 template<
typename T,
int64 ndims>
774 if (!
aligned(lhs, rhs))
throw std::domain_error(
"Attempt to apply / operator to multidimensional arrays with inconsistent dimensions");
775 return arraynd<decltype((*lhs.
data()) / (*rhs.
data())), ndims>(lhs.
dims(), [&lhs, &rhs](
const std::array<int64, ndims>& indices) {
776 return lhs(indices)/rhs(indices);
781 template<
typename T,
int64 ndims,
typename U>
784 return arraynd<decltype((*lhs.
data()) + rhs), ndims>(lhs.
dims(), [&lhs, &rhs](
const std::array<int64, ndims>& indices) {
785 return lhs(indices) + rhs;
790 template<
typename T,
int64 ndims,
typename U>
793 return arraynd<decltype((*lhs.
data()) - rhs), ndims>(lhs.
dims(), [&lhs, &rhs](
const std::array<int64, ndims>& indices) {
794 return lhs(indices) - rhs;
799 template<
typename T,
int64 ndims,
typename U>
802 return arraynd<decltype((*lhs.
data()) * rhs), ndims>(lhs.
dims(), [&lhs, &rhs](
const std::array<int64, ndims>& indices) {
803 return lhs(indices)*rhs;
808 template<
typename T,
int64 ndims,
typename U>
811 return arraynd<decltype((*lhs.
data()) / rhs), ndims>(lhs.
dims(), [&lhs, &rhs](
const std::array<int64, ndims>& indices) {
812 return lhs(indices)/rhs;
817 template<
typename T,
int64 ndims,
typename U>
820 return arraynd<decltype(lhs + (*rhs.
data())), ndims>(rhs.
dims(), [&lhs, &rhs](
const std::array<int64, ndims>& indices) {
821 return lhs + rhs(indices);
826 template<
typename T,
int64 ndims,
typename U>
829 return arraynd<decltype(lhs - (*rhs.
data())), ndims>(rhs.
dims(), [&lhs, &rhs](
const std::array<int64, ndims>& indices) {
830 return lhs - rhs(indices);
835 template<
typename T,
int64 ndims,
typename U>
838 return arraynd<decltype(lhs * (*rhs.
data())), ndims>(rhs.
dims(), [&lhs, &rhs](
const std::array<int64, ndims>& indices) {
839 return lhs*rhs(indices);
844 template<
typename T,
int64 ndims,
typename U>
847 return arraynd<decltype(lhs / (*rhs.
data())), ndims>(rhs.
dims(), [&lhs, &rhs](
const std::array<int64, ndims>& indices) {
848 return lhs/rhs(indices);
853 template<
typename T,
int64 ndims>
856 if (!
aligned(lhs, rhs))
throw std::domain_error(
"Attempt to apply < operator to multidimensional arrays with inconsistent dimensions");
857 return arraynd<decltype((*lhs.
data()) < (*rhs.
data())), ndims>(lhs.
dims(), [&lhs, &rhs](
const std::array<int64, ndims>& indices) {
858 return lhs(indices) < rhs(indices);
863 template<
typename T,
int64 ndims>
866 if (!
aligned(lhs, rhs))
throw std::domain_error(
"Attempt to apply > operator to multidimensional arrays with inconsistent dimensions");
867 return arraynd<decltype((*lhs.
data()) > (*rhs.
data())), ndims>(lhs.
dims(), [&lhs, &rhs](
const std::array<int64, ndims>& indices) {
868 return lhs(indices) > rhs(indices);
873 template<
typename T,
int64 ndims>
876 if (!
aligned(lhs, rhs))
throw std::domain_error(
"Attempt to apply <= operator to multidimensional arrays with inconsistent dimensions");
877 return arraynd<decltype((*lhs.
data()) <= (*rhs.
data())), ndims>(lhs.
dims(), [&lhs, &rhs](
const std::array<int64, ndims>& indices) {
878 return lhs(indices) <= rhs(indices);
883 template<
typename T,
int64 ndims>
886 if (!
aligned(lhs, rhs))
throw std::domain_error(
"Attempt to apply >= operator to multidimensional arrays with inconsistent dimensions");
887 return arraynd<decltype((*lhs.
data()) >= (*rhs.
data())), ndims>(lhs.
dims(), [&lhs, &rhs](
const std::array<int64, ndims>& indices) {
888 return lhs(indices) >= rhs(indices);
893 template<
typename T,
int64 ndims>
896 if (!
aligned(lhs, rhs))
throw std::domain_error(
"Attempt to apply == operator to multidimensional arrays with inconsistent dimensions");
897 return arraynd<decltype((*lhs.
data()) == (*rhs.
data())), ndims>(lhs.
dims(), [&lhs, &rhs](
const std::array<int64, ndims>& indices) {
898 return lhs(indices) == rhs(indices);
903 template<
typename T,
int64 ndims>
906 if (!
aligned(lhs, rhs))
throw std::domain_error(
"Attempt to apply != operator to multidimensional arrays with inconsistent dimensions");
907 return arraynd<decltype((*lhs.
data()) != (*rhs.
data())), ndims>(lhs.
dims(), [&lhs, &rhs](
const std::array<int64, ndims>& indices) {
908 return lhs(indices) != rhs(indices);
913 template<
typename T,
int64 ndims>
916 if (!
aligned(lhs, rhs))
throw std::domain_error(
"Attempt to apply && operator to multidimensional arrays with inconsistent dimensions");
917 return arraynd<decltype((*lhs.
data()) && (*rhs.
data())), ndims>(lhs.
dims(), [&lhs, &rhs](
const std::array<int64, ndims>& indices) {
918 return lhs(indices) && rhs(indices);
923 template<
typename T,
int64 ndims>
926 if (!
aligned(lhs, rhs))
throw std::domain_error(
"Attempt to apply || operator to multidimensional arrays with inconsistent dimensions");
927 return arraynd<decltype((*lhs.
data()) || (*rhs.
data())), ndims>(lhs.
dims(), [&lhs, &rhs](
const std::array<int64, ndims>& indices) {
928 return lhs(indices) || rhs(indices);
933 template<
typename T,
int64 ndims,
typename U>
936 return arraynd<decltype((*lhs.
data()) < rhs), ndims>(lhs.
dims(), [&lhs, &rhs](
const std::array<int64, ndims>& indices) {
937 return lhs(indices) < rhs;
942 template<
typename T,
int64 ndims,
typename U>
945 return arraynd<decltype((*lhs.
data()) > rhs), ndims>(lhs.
dims(), [&lhs, &rhs](
const std::array<int64, ndims>& indices) {
946 return lhs(indices) > rhs;
951 template<
typename T,
int64 ndims,
typename U>
954 return arraynd<decltype((*lhs.
data()) <= rhs), ndims>(lhs.
dims(), [&lhs, &rhs](
const std::array<int64, ndims>& indices) {
955 return lhs(indices) <= rhs;
960 template<
typename T,
int64 ndims,
typename U>
963 return arraynd<decltype((*lhs.
data()) >= rhs), ndims>(lhs.
dims(), [&lhs, &rhs](
const std::array<int64, ndims>& indices) {
964 return lhs(indices) >= rhs;
969 template<
typename T,
int64 ndims,
typename U>
972 return arraynd<decltype((*lhs.
data()) == rhs), ndims>(lhs.
dims(), [&lhs, &rhs](
const std::array<int64, ndims>& indices) {
973 return lhs(indices) == rhs;
978 template<
typename T,
int64 ndims,
typename U>
981 return arraynd<decltype((*lhs.
data()) != rhs), ndims>(lhs.
dims(), [&lhs, &rhs](
const std::array<int64, ndims>& indices) {
982 return lhs(indices) != rhs;
987 template<
typename T,
int64 ndims,
typename U>
990 return arraynd<decltype((*lhs.
data()) && rhs), ndims>(lhs.
dims(), [&lhs, &rhs](
const std::array<int64, ndims>& indices) {
991 return lhs(indices) && rhs;
996 template<
typename T,
int64 ndims,
typename U>
999 return arraynd<decltype((*lhs.
data()) || rhs), ndims>(lhs.
dims(), [&lhs, &rhs](
const std::array<int64, ndims>& indices) {
1000 return lhs(indices) || rhs;
1005 template<
typename T,
int64 ndims,
typename U>
1008 return arraynd<decltype(lhs < (*rhs.
data())), ndims>(rhs.
dims(), [&lhs, &rhs](
const std::array<int64, ndims>& indices) {
1009 return lhs < rhs(indices);
1014 template<
typename T,
int64 ndims,
typename U>
1018 return lhs > rhs(indices);
1023 template<
typename T,
int64 ndims,
typename U>
1026 return arraynd<decltype(lhs <= (*rhs.
data())), ndims>(rhs.
dims(), [&lhs, &rhs](
const std::array<int64, ndims>& indices) {
1027 return lhs <= rhs(indices);
1032 template<
typename T,
int64 ndims,
typename U>
1035 return arraynd<decltype(lhs >= (*rhs.
data())), ndims>(rhs.
dims(), [&lhs, &rhs](
const std::array<int64, ndims>& indices) {
1036 return lhs >= rhs(indices);
1041 template<
typename T,
int64 ndims,
typename U>
1044 return arraynd<decltype(lhs == (*rhs.
data())), ndims>(rhs.
dims(), [&lhs, &rhs](
const std::array<int64, ndims>& indices) {
1045 return lhs == rhs(indices);
1050 template<
typename T,
int64 ndims,
typename U>
1053 return arraynd<decltype(lhs != (*rhs.
data())), ndims>(rhs.
dims(), [&lhs, &rhs](
const std::array<int64, ndims>& indices) {
1054 return lhs != rhs(indices);
1059 template<
typename T,
int64 ndims,
typename U>
1062 return arraynd<decltype(lhs && (*rhs.
data())), ndims>(rhs.
dims(), [&lhs, &rhs](
const std::array<int64, ndims>& indices) {
1063 return lhs && rhs(indices);
1068 template<
typename T,
int64 ndims,
typename U>
1071 return arraynd<decltype(lhs || (*rhs.
data())), ndims>(rhs.
dims(), [&lhs, &rhs](
const std::array<int64, ndims>& indices) {
1072 return lhs || rhs(indices);
1077 template<
typename T,
int64 ndims>
1080 return arraynd<decltype(!(*arr.
data())), ndims>(arr.
dims(), [&arr](
const std::array<int64, ndims>& indices) {
1081 return !arr(indices);
1089 template<
int64 ndims>
1092 bool conjunction =
true;
1093 arr.
traverse([&conjunction](
const std::array<int64, ndims>& indices,
const bool& value) {
1094 conjunction = (conjunction && value);
1104 template<
int64 ndims>
1107 bool disjunction =
false;
1108 arr.
traverse([&disjunction](
const std::array<int64, ndims>& indices,
const bool& value) {
1109 disjunction = (disjunction || value);
1110 return !disjunction;
1120 template<
typename T,
int64 ndims,
typename U>
1124 return static_cast<T>(arr(indices));
1133 template<
typename T,
int64 ndims,
typename U>
1136 return arraynd<T, ndims>(lhs.
dims(), [&lhs, &selection, &rhs](
const std::array<int64, ndims>& indices) {
1137 return selection(indices) ? rhs : lhs(indices);
1147 template<
typename T,
int64 ndims,
typename U>
1150 if (!
aligned(lhs, rhs))
throw std::domain_error(
"Attempt to replace values using multidimensional arrays with inconsistent dimensions");
1151 return arraynd<T, ndims>(lhs.
dims(), [&lhs, &selection, &rhs](
const std::array<int64, ndims>& indices) {
1152 return selection(indices) ? rhs(indices) : lhs(indices);
1157 template<
typename T,
int64 ndims>
1160 auto indices = std::array<int64, ndims>();
1161 for (
int64 idim = 0; idim < ndims; ++idim) {
1168 if (indices[idim] < rhs.
dims()[idim]) {
1171 if (indices[idim] > 0) {
1176 if (idim == ndims - 1) {
1179 os << rhs.
data()[offset];
1181 offset += rhs.
strides()[idim];
1198 offset += rhs.
strides()[idim];
1217 template<
typename T>
1221 return std::lexicographical_compare(lhs.
data(), lhs.
data() + lhs.
size(),
A one-dimensional (1D) specialization of the arraynd multidimensional array template.
Definition: arraynd.h:292
arraynd< T, 1 > & operator=(arraynd< T, 1 > &&)=default
Move assignment (data is shared)
arraynd(const arraynd< T, 1 > &)=default
Copy constructor (if rhs.is_view(), data is shared; otherwise data is copied)
A base class template for a multidimensional array with elements of type T arranged in a lattice of n...
Definition: arraynd_base.h:26
int64 offset() const
Returns the number of element-size steps in memory before the first element.
Definition: arraynd_base.h:229
bool traverse(std::function< bool(const std::array< int64, ndims > &indices, const T &value)> func) const
Traverses the multidimensional array in row-major order, calling func at every element.
Definition: arraynd_base.h:392
std::array< int64, ndims > dims() const
Returns the lengths of each dimension.
Definition: arraynd_base.h:197
int64 size() const
Returns the total number of elements.
Definition: arraynd_base.h:221
const T * data() const
Returns a pointer to the element data (const).
Definition: arraynd_base.h:237
bool is_view() const
Returns true if this multidimensional array is a view of another, meaning that data is shared.
Definition: arraynd_base.h:272
std::array< int64, ndims > strides() const
Returns the number of element-size steps in memory between successive elements for each dimension.
Definition: arraynd_base.h:205
static void subdivide_axis(const arraynd_base< T, ndims > &arr0, arraynd_base< T, ndims+1 > &arr, int64 idim, const std::array< int64, 2 > &dims)
Definition: arraynd_base.h:564
bool is_readonly() const
Returns true if the data is readonly, in which case attempts to modify it raise a std::logic_error.
Definition: arraynd_base.h:280
A class template for a multidimensional array with elements of type T arranged in a lattice of ndims ...
Definition: arraynd.h:188
arraynd< T, ndims > copy_transposed() const
Create a transposed deep copy of the multidimensional array (data is copied).
Definition: arraynd.h:475
const arraynd< T, ndims > view_transposed() const
Create a const transposed view of the multidimensional array (data is shared).
Definition: arraynd.h:457
const arraynd< T, ndims-1 > operator[](int64 index) const
Create a const slice with one dimension replaced by referencing elements at the specified index (data...
Definition: arraynd.h:408
arraynd< T, ndims > & operator=(const arraynd< T, ndims > &)=default
Copy assignment (if !is_view() && rhs.is_view(), data is shared; otherwise data is copied)
arraynd(const arraynd< T, ndims > &)=default
Copy constructor (if rhs.is_view(), data is shared; otherwise data is copied)
arraynd< T, ndims > copy() const
Create a deep copy of the multidimensional array (data is copied).
Definition: arraynd.h:450
const arraynd< T, ndims - 1 > view_absorbed_axis(int64 idim) const
Create a const view with dimension idim absorbed into dimension idim - 1 (data is shared).
Definition: arraynd.h:537
~arraynd()=default
Destructor.
arraynd()
Constructs an arraynd object with dimensions of length zero.
Definition: arraynd.h:380
const arraynd< T, ndims > view() const
Create a const view of the multidimensional array (data is shared).
Definition: arraynd.h:436
arraynd< T, ndims > & operator=(arraynd< T, ndims > &&)=default
Move assignment (data is shared)
arraynd< T, ndims > copy_swapped_axes(int64 idim0, int64 idim1) const
Create a deep copy with dimensions idim0 and idim1 swapped (data is copied).
Definition: arraynd.h:502
arraynd(arraynd< T, ndims > &&)=default
Move constructor (data is shared)
const arraynd< T, ndims > view_swapped_axes(int64 idim0, int64 idim1) const
Create a const view with dimensions idim0 and idim1 swapped (data is shared).
Definition: arraynd.h:484
arraynd< T, ndims+1 > copy_subdivided_axis(int64 idim, const std::array< int64, 2 > &dims) const
Create a deep copy with dimension idim split into two dimensions with lengths given by dims (data is ...
Definition: arraynd.h:529
const arraynd< T, ndims+1 > view_subdivided_axis(int64 idim, const std::array< int64, 2 > &dims) const
Create a const view with dimension idim split into two dimensions with lengths given by dims (data is...
Definition: arraynd.h:511
arraynd< T, ndims - 1 > copy_absorbed_axis(int64 idim) const
Create a deep copy with dimension idim absorbed into dimension idim - 1 (data is copied).
Definition: arraynd.h:555
A data type which represents a range of array indices along a single dimension.
Definition: range.h:51
Definition: arraynd.h:1211
arraynd< T, 1 > array1d
Definition: arraynd.h:366
auto operator!(const arraynd< T, ndims > &arr)
Definition: arraynd.h:1078
bool any(const arraynd< bool, ndims > &arr)
Returns true if any element of arr is true.
Definition: arraynd.h:1105
auto operator+(const arraynd< T, ndims > &rhs)
Definition: arraynd.h:724
auto operator<(const arraynd< T, ndims > &lhs, const arraynd< T, ndims > &rhs)
Definition: arraynd.h:854
auto operator||(const arraynd< T, ndims > &lhs, const arraynd< T, ndims > &rhs)
Definition: arraynd.h:924
auto operator!=(const arraynd< T, ndims > &lhs, const arraynd< T, ndims > &rhs)
Definition: arraynd.h:904
auto operator-(const arraynd< T, ndims > &rhs)
Definition: arraynd.h:733
auto operator>=(const arraynd< T, ndims > &lhs, const arraynd< T, ndims > &rhs)
Definition: arraynd.h:884
bool all(const arraynd< bool, ndims > &arr)
Returns true if all elements of arr are true.
Definition: arraynd.h:1090
auto operator==(const arraynd< T, ndims > &lhs, const arraynd< T, ndims > &rhs)
Definition: arraynd.h:894
arraynd< T, ndims > replace(const arraynd< T, ndims > &lhs, const arraynd< bool, ndims > &selection, const U &rhs)
Returns a multidimensional array similar to arr but with elements for which selection(indices) is tru...
Definition: arraynd.h:1134
auto operator&&(const arraynd< T, ndims > &lhs, const arraynd< T, ndims > &rhs)
Definition: arraynd.h:914
std::ostream & operator<<(std::ostream &os, const arraynd< T, ndims > &rhs)
Definition: arraynd.h:1158
int64_t int64
Definition: number_types.h:15
auto operator>(const arraynd< T, ndims > &lhs, const arraynd< T, ndims > &rhs)
Definition: arraynd.h:864
bool aligned(const arraynd< T, ndims > &lhs, const arraynd< T, ndims > &rhs)
Definition: arraynd.h:713
arraynd< T, ndims > to(const arraynd< U, ndims > &arr)
Returns a multidimensional array with the elements of arr converted to type T.
Definition: arraynd.h:1121
auto operator<=(const arraynd< T, ndims > &lhs, const arraynd< T, ndims > &rhs)
Definition: arraynd.h:874
auto operator/(const arraynd< T, ndims > &lhs, const arraynd< T, ndims > &rhs)
Definition: arraynd.h:772
auto operator*(const arraynd< T, ndims > &lhs, const arraynd< T, ndims > &rhs)
Definition: arraynd.h:762
bool operator()(const sydevs::array1d< T > &lhs, const sydevs::array1d< T > &rhs) const
Definition: arraynd.h:1220