SyDEVS  v0.7
Simulation-based analysis of complex systems involving people, devices, physical elements, and dynamic environments.
arraynd.h
Go to the documentation of this file.
1 #pragma once
2 #ifndef SYDEVS_ARRAYND_H_
3 #define SYDEVS_ARRAYND_H_
4 
6 #include <ostream>
7 
8 namespace sydevs {
9 
10 
186 template<typename T, int64 ndims>
187 class arraynd : public arraynd_base<T, ndims>
188 {
189 friend class arraynd<T, ndims+1>;
190 public:
197  arraynd();
198 
210  arraynd(const std::array<int64, ndims>& dims, const T& value);
211 
229  arraynd(const std::array<int64, ndims>& dims, const std::vector<T>& data);
230 
245  arraynd(const std::array<int64, ndims>& dims, std::function<T(const std::array<int64, ndims>& indices)> func);
246 
247  arraynd(const arraynd<T, ndims>&) = default;
249  arraynd(arraynd<T, ndims>&&) = default;
251  ~arraynd() = default;
252 
253  const arraynd<T, ndims-1> operator[](int64 index) const;
254  arraynd<T, ndims-1> operator[](int64 index);
255 
256  const arraynd<T, ndims> operator[](range r) const;
258 
259  const arraynd<T, ndims> view() const;
261  arraynd<T, ndims> copy() const;
262 
263  const arraynd<T, ndims> view_transposed() const;
266 
267  const arraynd<T, ndims> view_swapped_axes(int64 idim0, int64 idim1) const;
269  arraynd<T, ndims> copy_swapped_axes(int64 idim0, int64 idim1) const;
270 
271  const arraynd<T, ndims + 1> view_subdivided_axis(int64 idim, const std::array<int64, 2>& dims) const;
272  arraynd<T, ndims + 1> view_subdivided_axis(int64 idim, const std::array<int64, 2>& dims);
273  arraynd<T, ndims + 1> copy_subdivided_axis(int64 idim, const std::array<int64, 2>& dims) const;
274 
275  const arraynd<T, ndims - 1> view_absorbed_axis(int64 idim) const;
276  arraynd<T, ndims - 1> view_absorbed_axis(int64 idim);
277  arraynd<T, ndims - 1> copy_absorbed_axis(int64 idim) const;
278 
279 private:
280  arraynd(const arraynd<T, ndims+1>& rhs, int64 index, bool readonly);
281  arraynd(const arraynd<T, ndims>& rhs, range r, bool readonly);
282  arraynd(const arraynd<T, ndims>& rhs, bool is_view, bool readonly);
283 };
284 
285 
290 template<typename T>
291 class arraynd<T, 1> : public arraynd_base<T, 1>
292 {
293 friend class arraynd<T, 2>;
294 public:
298  arraynd();
299 
304  arraynd(const std::array<int64, 1>& dims, const T& value);
305 
320  arraynd(const std::array<int64, 1>& dims, const std::vector<T>& data);
321 
335  arraynd(const std::array<int64, 1>& dims, std::function<T(const std::array<int64, 1>& indices)> func);
336 
337  arraynd<T, 1>(const arraynd<T, 1>&) = default;
338  arraynd<T, 1>& operator=(const arraynd<T, 1>&) = default;
339  arraynd<T, 1>(arraynd<T, 1>&&) = default;
341  ~arraynd<T, 1>() = default;
342 
343  const T& operator[](int64 index) const;
344  T& operator[](int64 index);
345 
346  const arraynd<T, 1> operator[](range r) const;
348 
349  const arraynd<T, 1> view() const;
350  arraynd<T, 1> view();
351  arraynd<T, 1> copy() const;
352 
353  const arraynd<T, 2> view_subdivided_axis(int64 idim, const std::array<int64, 2>& dims) const;
354  arraynd<T, 2> view_subdivided_axis(int64 idim, const std::array<int64, 2>& dims);
355  arraynd<T, 2> copy_subdivided_axis(int64 idim, const std::array<int64, 2>& dims) const;
356 
357 private:
358  arraynd(const arraynd<T, 2>& rhs, int64 index, bool readonly);
359  arraynd(const arraynd<T, 1>& rhs, range r, bool readonly);
360  arraynd(const arraynd<T, 1>& rhs, bool is_view, bool readonly);
361 };
362 
363 
364 // n-dimensional array aliases
365 
366 template<typename T> using array1d = arraynd<T, 1>;
367 template<typename T> using array2d = arraynd<T, 2>;
368 template<typename T> using array3d = arraynd<T, 3>;
369 template<typename T> using array4d = arraynd<T, 4>;
370 template<typename T> using array5d = arraynd<T, 5>;
371 template<typename T> using array6d = arraynd<T, 6>;
372 template<typename T> using array7d = arraynd<T, 7>;
373 template<typename T> using array8d = arraynd<T, 8>;
374 template<typename T> using array9d = arraynd<T, 9>;
375 
376 
377 // n-dimensional array (ndims > 1) implementation
378 
379 template<typename T, int64 ndims>
381  : arraynd_base<T, ndims>()
382 {
383 }
384 
385 
386 template<typename T, int64 ndims>
387 arraynd<T, ndims>::arraynd(const std::array<int64, ndims>& dims, const T& value)
388  : arraynd_base<T, ndims>(dims, value)
389 {
390 }
391 
392 
393 template<typename T, int64 ndims>
394 arraynd<T, ndims>::arraynd(const std::array<int64, ndims>& dims, const std::vector<T>& data)
395  : arraynd_base<T, ndims>(dims, data)
396 {
397 }
398 
399 
400 template<typename T, int64 ndims>
401 arraynd<T, ndims>::arraynd(const std::array<int64, ndims>& dims, std::function<T(const std::array<int64, ndims>& indices)> func)
402  : arraynd_base<T, ndims>(dims, func)
403 {
404 }
405 
406 
407 template<typename T, int64 ndims>
408 const arraynd<T, ndims-1> arraynd<T, ndims>::operator[](int64 index) const
409 {
410  return arraynd<T, ndims-1>(*this, index, true);
411 }
412 
413 
414 template<typename T, int64 ndims>
416 {
417  return arraynd<T, ndims-1>(*this, index, this->is_readonly());
418 }
419 
420 
421 template<typename T, int64 ndims>
423 {
424  return arraynd<T, ndims>(*this, r, true);
425 }
426 
427 
428 template<typename T, int64 ndims>
430 {
431  return arraynd<T, ndims>(*this, r, this->is_readonly());
432 }
433 
434 
435 template<typename T, int64 ndims>
437 {
438  return arraynd<T, ndims>(*this, true, true);
439 }
440 
441 
442 template<typename T, int64 ndims>
444 {
445  return arraynd<T, ndims>(*this, true, this->is_readonly());
446 }
447 
448 
449 template<typename T, int64 ndims>
451 {
452  return arraynd<T, ndims>(*this, false, false);
453 }
454 
455 
456 template<typename T, int64 ndims>
458 {
459  auto arr = view();
460  this->transpose(arr);
461  return arr;
462 }
463 
464 
465 template<typename T, int64 ndims>
467 {
468  auto arr = view();
469  this->transpose(arr);
470  return arr;
471 }
472 
473 
474 template<typename T, int64 ndims>
476 {
477  auto arr = view();
478  this->transpose(arr);
479  return arr.copy();
480 }
481 
482 
483 template<typename T, int64 ndims>
485 {
486  auto arr = view();
487  this->swap_axes(arr, idim0, idim1);
488  return arr;
489 }
490 
491 
492 template<typename T, int64 ndims>
494 {
495  auto arr = view();
496  this->swap_axes(arr, idim0, idim1);
497  return arr;
498 }
499 
500 
501 template<typename T, int64 ndims>
503 {
504  auto arr = view();
505  this->swap_axes(arr, idim0, idim1);
506  return arr.copy();
507 }
508 
509 
510 template<typename T, int64 ndims>
511 const arraynd<T, ndims + 1> arraynd<T, ndims>::view_subdivided_axis(int64 idim, const std::array<int64, 2>& dims) const
512 {
513  auto arr = arraynd<T, ndims + 1>();
514  this->subdivide_axis(*this, arr, idim, dims);
515  return arr;
516 }
517 
518 
519 template<typename T, int64 ndims>
521 {
522  auto arr = arraynd<T, ndims + 1>();
523  this->subdivide_axis(*this, arr, idim, dims);
524  return arr;
525 }
526 
527 
528 template<typename T, int64 ndims>
529 arraynd<T, ndims + 1> arraynd<T, ndims>::copy_subdivided_axis(int64 idim, const std::array<int64, 2>& dims) const
530 {
531  auto arr0 = copy();
532  return arr0.view_subdivided_axis(idim, dims);
533 }
534 
535 
536 template<typename T, int64 ndims>
537 const arraynd<T, ndims - 1> arraynd<T, ndims>::view_absorbed_axis(int64 idim) const
538 {
539  auto arr = arraynd<T, ndims - 1>(std::array<int64, ndims - 1>(), std::vector<T>());
540  this->absorb_axis(*this, arr, idim);
541  return arr;
542 }
543 
544 
545 template<typename T, int64 ndims>
547 {
548  auto arr = arraynd<T, ndims - 1>(std::array<int64, ndims - 1>(), std::vector<T>());
549  this->absorb_axis(*this, arr, idim);
550  return arr;
551 }
552 
553 
554 template<typename T, int64 ndims>
556 {
557  auto arr0 = copy();
558  return arr0.view_absorbed_axis(idim);
559 }
560 
561 
562 template<typename T, int64 ndims>
563 arraynd<T, ndims>::arraynd(const arraynd<T, ndims+1>& rhs, int64 index, bool readonly)
564  : arraynd_base<T, ndims>(rhs, index, readonly)
565 {
566 }
567 
568 
569 template<typename T, int64 ndims>
570 arraynd<T, ndims>::arraynd(const arraynd<T, ndims>& rhs, range r, bool readonly)
571  : arraynd_base<T, ndims>(rhs, r, readonly)
572 {
573 }
574 
575 
576 template<typename T, int64 ndims>
577 arraynd<T, ndims>::arraynd(const arraynd<T, ndims>& rhs, bool is_view, bool readonly)
578  : arraynd_base<T, ndims>(rhs, is_view, readonly)
579 {
580 }
581 
582 
583 // 1-dimensional array implementation
584 
585 template<typename T>
587  : arraynd_base<T, 1>()
588 {
589 }
590 
591 
592 template<typename T>
593 arraynd<T, 1>::arraynd(const std::array<int64, 1>& dims, const T& value)
594  : arraynd_base<T, 1>(dims, value)
595 {
596 }
597 
598 
599 template<typename T>
600 arraynd<T, 1>::arraynd(const std::array<int64, 1>& dims, const std::vector<T>& data)
601  : arraynd_base<T, 1>(dims, data)
602 {
603 }
604 
605 
606 template<typename T>
607 arraynd<T, 1>::arraynd(const std::array<int64, 1>& dims, std::function<T(const std::array<int64, 1>& indices)> func)
608  : arraynd_base<T, 1>(dims, func)
609 {
610 }
611 
612 
613 template<typename T>
614 const T& arraynd<T, 1>::operator[](int64 index) const
615 {
617 }
618 
619 
620 template<typename T>
622 {
623  if (this->is_readonly()) throw std::logic_error("Attempt to obtain a non-const reference to readonly multidimensional array data");
625 }
626 
627 
628 template<typename T>
630 {
631  return arraynd<T, 1>(*this, r, true);
632 }
633 
634 
635 template<typename T>
637 {
638  return arraynd<T, 1>(*this, r, this->is_readonly());
639 }
640 
641 
642 template<typename T>
644 {
645  return arraynd<T, 1>(*this, true, true);
646 }
647 
648 
649 template<typename T>
651 {
652  return arraynd<T, 1>(*this, true, this->is_readonly());
653 }
654 
655 
656 template<typename T>
658 {
659  return arraynd<T, 1>(*this, false, false);
660 }
661 
662 
663 template<typename T>
664 const arraynd<T, 2> arraynd<T, 1>::view_subdivided_axis(int64 idim, const std::array<int64, 2>& dims) const
665 {
666  auto arr = arraynd<T, 2>();
667  this->subdivide_axis(*this, arr, idim, dims);
668  return arr;
669 }
670 
671 
672 template<typename T>
673 arraynd<T, 2> arraynd<T, 1>::view_subdivided_axis(int64 idim, const std::array<int64, 2>& dims)
674 {
675  auto arr = arraynd<T, 2>();
676  this->subdivide_axis(*this, arr, idim, dims);
677  return arr;
678 }
679 
680 
681 template<typename T>
682 arraynd<T, 2> arraynd<T, 1>::copy_subdivided_axis(int64 idim, const std::array<int64, 2>& dims) const
683 {
684  auto arr0 = copy();
685  return arr0.view_subdivided_axis(idim, dims);
686 }
687 
688 
689 template<typename T>
690 arraynd<T, 1>::arraynd(const arraynd<T, 2>& rhs, int64 index, bool readonly)
691  : arraynd_base<T, 1>(rhs, index, readonly)
692 {
693 }
694 
695 
696 template<typename T>
697 arraynd<T, 1>::arraynd(const arraynd<T, 1>& rhs, range r, bool readonly)
698  : arraynd_base<T, 1>(rhs, r, readonly)
699 {
700 }
701 
702 
703 template<typename T>
704 arraynd<T, 1>::arraynd(const arraynd<T, 1>& rhs, bool is_view, bool readonly)
705  : arraynd_base<T, 1>(rhs, is_view, readonly)
706 {
707 }
708 
709 
710 // multi-dimensional array operations
711 
712 template<typename T, int64 ndims>
713 bool aligned(const arraynd<T, ndims>& lhs, const arraynd<T, ndims>& rhs)
714 {
715  auto okay = true;
716  for (int64 idim = 0; okay && idim < ndims; ++idim) {
717  okay = (lhs.dims()[idim] == rhs.dims()[idim]);
718  }
719  return okay;
720 }
721 
722 
723 template<typename T, int64 ndims>
724 auto operator+(const arraynd<T, ndims>& rhs)
725 {
726  return arraynd<decltype(+(*rhs.data())), ndims>(rhs.dims(), [&rhs](const std::array<int64, ndims>& indices) {
727  return +rhs(indices);
728  });
729 }
730 
731 
732 template<typename T, int64 ndims>
733 auto operator-(const arraynd<T, ndims>& rhs)
734 {
735  return arraynd<decltype(-(*rhs.data())), ndims>(rhs.dims(), [&rhs](const std::array<int64, ndims>& indices) {
736  return -rhs(indices);
737  });
738 }
739 
740 
741 template<typename T, int64 ndims>
742 auto operator+(const arraynd<T, ndims>& lhs, const arraynd<T, ndims>& rhs)
743 {
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);
747  });
748 }
749 
750 
751 template<typename T, int64 ndims>
752 auto operator-(const arraynd<T, ndims>& lhs, const arraynd<T, ndims>& rhs)
753 {
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);
757  });
758 }
759 
760 
761 template<typename T, int64 ndims>
762 auto operator*(const arraynd<T, ndims>& lhs, const arraynd<T, ndims>& rhs)
763 {
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);
767  });
768 }
769 
770 
771 template<typename T, int64 ndims>
772 auto operator/(const arraynd<T, ndims>& lhs, const arraynd<T, ndims>& rhs)
773 {
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);
777  });
778 }
779 
780 
781 template<typename T, int64 ndims, typename U>
782 auto operator+(const arraynd<T, ndims>& lhs, const U& rhs)
783 {
784  return arraynd<decltype((*lhs.data()) + rhs), ndims>(lhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
785  return lhs(indices) + rhs;
786  });
787 }
788 
789 
790 template<typename T, int64 ndims, typename U>
791 auto operator-(const arraynd<T, ndims>& lhs, const U& rhs)
792 {
793  return arraynd<decltype((*lhs.data()) - rhs), ndims>(lhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
794  return lhs(indices) - rhs;
795  });
796 }
797 
798 
799 template<typename T, int64 ndims, typename U>
800 auto operator*(const arraynd<T, ndims>& lhs, const U& rhs)
801 {
802  return arraynd<decltype((*lhs.data()) * rhs), ndims>(lhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
803  return lhs(indices)*rhs;
804  });
805 }
806 
807 
808 template<typename T, int64 ndims, typename U>
809 auto operator/(const arraynd<T, ndims>& lhs, const U& rhs)
810 {
811  return arraynd<decltype((*lhs.data()) / rhs), ndims>(lhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
812  return lhs(indices)/rhs;
813  });
814 }
815 
816 
817 template<typename T, int64 ndims, typename U>
818 auto operator+(const U& lhs, const arraynd<T, ndims>& rhs)
819 {
820  return arraynd<decltype(lhs + (*rhs.data())), ndims>(rhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
821  return lhs + rhs(indices);
822  });
823 }
824 
825 
826 template<typename T, int64 ndims, typename U>
827 auto operator-(const U& lhs, const arraynd<T, ndims>& rhs)
828 {
829  return arraynd<decltype(lhs - (*rhs.data())), ndims>(rhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
830  return lhs - rhs(indices);
831  });
832 }
833 
834 
835 template<typename T, int64 ndims, typename U>
836 auto operator*(const U& lhs, const arraynd<T, ndims>& rhs)
837 {
838  return arraynd<decltype(lhs * (*rhs.data())), ndims>(rhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
839  return lhs*rhs(indices);
840  });
841 }
842 
843 
844 template<typename T, int64 ndims, typename U>
845 auto operator/(const U& lhs, const arraynd<T, ndims>& rhs)
846 {
847  return arraynd<decltype(lhs / (*rhs.data())), ndims>(rhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
848  return lhs/rhs(indices);
849  });
850 }
851 
852 
853 template<typename T, int64 ndims>
854 auto operator<(const arraynd<T, ndims>& lhs, const arraynd<T, ndims>& rhs)
855 {
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);
859  });
860 }
861 
862 
863 template<typename T, int64 ndims>
864 auto operator>(const arraynd<T, ndims>& lhs, const arraynd<T, ndims>& rhs)
865 {
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);
869  });
870 }
871 
872 
873 template<typename T, int64 ndims>
874 auto operator<=(const arraynd<T, ndims>& lhs, const arraynd<T, ndims>& rhs)
875 {
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);
879  });
880 }
881 
882 
883 template<typename T, int64 ndims>
884 auto operator>=(const arraynd<T, ndims>& lhs, const arraynd<T, ndims>& rhs)
885 {
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);
889  });
890 }
891 
892 
893 template<typename T, int64 ndims>
894 auto operator==(const arraynd<T, ndims>& lhs, const arraynd<T, ndims>& rhs)
895 {
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);
899  });
900 }
901 
902 
903 template<typename T, int64 ndims>
904 auto operator!=(const arraynd<T, ndims>& lhs, const arraynd<T, ndims>& rhs)
905 {
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);
909  });
910 }
911 
912 
913 template<typename T, int64 ndims>
914 auto operator&&(const arraynd<T, ndims>& lhs, const arraynd<T, ndims>& rhs)
915 {
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);
919  });
920 }
921 
922 
923 template<typename T, int64 ndims>
924 auto operator||(const arraynd<T, ndims>& lhs, const arraynd<T, ndims>& rhs)
925 {
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);
929  });
930 }
931 
932 
933 template<typename T, int64 ndims, typename U>
934 auto operator<(const arraynd<T, ndims>& lhs, const U& rhs)
935 {
936  return arraynd<decltype((*lhs.data()) < rhs), ndims>(lhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
937  return lhs(indices) < rhs;
938  });
939 }
940 
941 
942 template<typename T, int64 ndims, typename U>
943 auto operator>(const arraynd<T, ndims>& lhs, const U& rhs)
944 {
945  return arraynd<decltype((*lhs.data()) > rhs), ndims>(lhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
946  return lhs(indices) > rhs;
947  });
948 }
949 
950 
951 template<typename T, int64 ndims, typename U>
952 auto operator<=(const arraynd<T, ndims>& lhs, const U& rhs)
953 {
954  return arraynd<decltype((*lhs.data()) <= rhs), ndims>(lhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
955  return lhs(indices) <= rhs;
956  });
957 }
958 
959 
960 template<typename T, int64 ndims, typename U>
961 auto operator>=(const arraynd<T, ndims>& lhs, const U& rhs)
962 {
963  return arraynd<decltype((*lhs.data()) >= rhs), ndims>(lhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
964  return lhs(indices) >= rhs;
965  });
966 }
967 
968 
969 template<typename T, int64 ndims, typename U>
970 auto operator==(const arraynd<T, ndims>& lhs, const U& rhs)
971 {
972  return arraynd<decltype((*lhs.data()) == rhs), ndims>(lhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
973  return lhs(indices) == rhs;
974  });
975 }
976 
977 
978 template<typename T, int64 ndims, typename U>
979 auto operator!=(const arraynd<T, ndims>& lhs, const U& rhs)
980 {
981  return arraynd<decltype((*lhs.data()) != rhs), ndims>(lhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
982  return lhs(indices) != rhs;
983  });
984 }
985 
986 
987 template<typename T, int64 ndims, typename U>
988 auto operator&&(const arraynd<T, ndims>& lhs, const U& rhs)
989 {
990  return arraynd<decltype((*lhs.data()) && rhs), ndims>(lhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
991  return lhs(indices) && rhs;
992  });
993 }
994 
995 
996 template<typename T, int64 ndims, typename U>
997 auto operator||(const arraynd<T, ndims>& lhs, const U& rhs)
998 {
999  return arraynd<decltype((*lhs.data()) || rhs), ndims>(lhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
1000  return lhs(indices) || rhs;
1001  });
1002 }
1003 
1004 
1005 template<typename T, int64 ndims, typename U>
1006 auto operator<(const U& lhs, const arraynd<T, ndims>& rhs)
1007 {
1008  return arraynd<decltype(lhs < (*rhs.data())), ndims>(rhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
1009  return lhs < rhs(indices);
1010  });
1011 }
1012 
1013 
1014 template<typename T, int64 ndims, typename U>
1015 auto operator>(const U& lhs, const arraynd<T, ndims>& rhs)
1016 {
1017  return arraynd<decltype(lhs > (*rhs.data())), ndims>(rhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
1018  return lhs > rhs(indices);
1019  });
1020 }
1021 
1022 
1023 template<typename T, int64 ndims, typename U>
1024 auto operator<=(const U& lhs, const arraynd<T, ndims>& rhs)
1025 {
1026  return arraynd<decltype(lhs <= (*rhs.data())), ndims>(rhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
1027  return lhs <= rhs(indices);
1028  });
1029 }
1030 
1031 
1032 template<typename T, int64 ndims, typename U>
1033 auto operator>=(const U& lhs, const arraynd<T, ndims>& rhs)
1034 {
1035  return arraynd<decltype(lhs >= (*rhs.data())), ndims>(rhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
1036  return lhs >= rhs(indices);
1037  });
1038 }
1039 
1040 
1041 template<typename T, int64 ndims, typename U>
1042 auto operator==(const U& lhs, const arraynd<T, ndims>& rhs)
1043 {
1044  return arraynd<decltype(lhs == (*rhs.data())), ndims>(rhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
1045  return lhs == rhs(indices);
1046  });
1047 }
1048 
1049 
1050 template<typename T, int64 ndims, typename U>
1051 auto operator!=(const U& lhs, const arraynd<T, ndims>& rhs)
1052 {
1053  return arraynd<decltype(lhs != (*rhs.data())), ndims>(rhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
1054  return lhs != rhs(indices);
1055  });
1056 }
1057 
1058 
1059 template<typename T, int64 ndims, typename U>
1060 auto operator&&(const U& lhs, const arraynd<T, ndims>& rhs)
1061 {
1062  return arraynd<decltype(lhs && (*rhs.data())), ndims>(rhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
1063  return lhs && rhs(indices);
1064  });
1065 }
1066 
1067 
1068 template<typename T, int64 ndims, typename U>
1069 auto operator||(const U& lhs, const arraynd<T, ndims>& rhs)
1070 {
1071  return arraynd<decltype(lhs || (*rhs.data())), ndims>(rhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
1072  return lhs || rhs(indices);
1073  });
1074 }
1075 
1076 
1077 template<typename T, int64 ndims>
1079 {
1080  return arraynd<decltype(!(*arr.data())), ndims>(arr.dims(), [&arr](const std::array<int64, ndims>& indices) {
1081  return !arr(indices);
1082  });
1083 }
1084 
1085 
1089 template<int64 ndims>
1090 bool all(const arraynd<bool, ndims>& arr)
1091 {
1092  bool conjunction = true;
1093  arr.traverse([&conjunction](const std::array<int64, ndims>& indices, const bool& value) {
1094  conjunction = (conjunction && value);
1095  return conjunction;
1096  });
1097  return conjunction;
1098 }
1099 
1100 
1104 template<int64 ndims>
1105 bool any(const arraynd<bool, ndims>& arr)
1106 {
1107  bool disjunction = false;
1108  arr.traverse([&disjunction](const std::array<int64, ndims>& indices, const bool& value) {
1109  disjunction = (disjunction || value);
1110  return !disjunction;
1111  });
1112  return disjunction;
1113 }
1114 
1115 
1120 template<typename T, int64 ndims, typename U>
1122 {
1123  return arraynd<T, ndims>(arr.dims(), [&arr](const std::array<int64, ndims>& indices) {
1124  return static_cast<T>(arr(indices));
1125  });
1126 }
1127 
1128 
1133 template<typename T, int64 ndims, typename U>
1134 arraynd<T, ndims> replace(const arraynd<T, ndims>& lhs, const arraynd<bool, ndims>& selection, const U& rhs)
1135 {
1136  return arraynd<T, ndims>(lhs.dims(), [&lhs, &selection, &rhs](const std::array<int64, ndims>& indices) {
1137  return selection(indices) ? rhs : lhs(indices);
1138  });
1139 }
1140 
1141 
1147 template<typename T, int64 ndims, typename U>
1149 {
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);
1153  });
1154 }
1155 
1156 
1157 template<typename T, int64 ndims>
1158 std::ostream& operator<<(std::ostream& os, const arraynd<T, ndims>& rhs)
1159 {
1160  auto indices = std::array<int64, ndims>();
1161  for (int64 idim = 0; idim < ndims; ++idim) {
1162  indices[idim] = 0;
1163  }
1164  int64 offset = rhs.offset();
1165  int64 idim = 0;
1166  os << "{";
1167  while (idim >= 0) {
1168  if (indices[idim] < rhs.dims()[idim]) {
1169  // The index is not beyond the last element on the current axis.
1170  // Continue outputting the current sub-array.
1171  if (indices[idim] > 0) {
1172  // This is not the first element on the current axis.
1173  // Output a delimiter.
1174  os << ", ";
1175  }
1176  if (idim == ndims - 1) {
1177  // The current axis is the last one.
1178  // Output the current element and advance the index.
1179  os << rhs.data()[offset];
1180  ++indices[idim];
1181  offset += rhs.strides()[idim];
1182  }
1183  else {
1184  // The current axis is not the last one.
1185  // Start outputting a new sub-array.
1186  ++idim;
1187  os << "{";
1188  }
1189  }
1190  else {
1191  // The index is beyond the last element on the current axis.
1192  // Finish outputting the current sub-array.
1193  indices[idim] = 0;
1194  offset -= rhs.dims()[idim]*rhs.strides()[idim];
1195  --idim;
1196  if (idim >= 0) {
1197  ++indices[idim];
1198  offset += rhs.strides()[idim];
1199  os << "}";
1200  }
1201  }
1202  }
1203  os << "}";
1204  return os;
1205 }
1206 
1207 
1208 } // namespace
1209 
1210 
1211 namespace std {
1217 template<typename T>
1218 struct less<sydevs::array1d<T>>
1219 {
1220  bool operator()(const sydevs::array1d<T>& lhs, const sydevs::array1d<T>& rhs) const {
1221  return std::lexicographical_compare(lhs.data(), lhs.data() + lhs.size(),
1222  rhs.data(), rhs.data() + rhs.size());
1223  }
1224 };
1225 }
1226 
1227 
1228 #endif
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
Definition: arraynd.h:8
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