SyDEVS  v0.6.7
Multiscale Simulation and Systems Modeling Library
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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;
248  arraynd<T, ndims>& operator=(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;
340  arraynd<T, 1>& operator=(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>
725 {
726  return rhs.copy();
727 }
728 
729 
730 template<typename T, int64 ndims>
732 {
733  return arraynd<T, ndims>(rhs.dims(), [&rhs](const std::array<int64, ndims>& indices) {
734  return -rhs(indices);
735  });
736 }
737 
738 
739 template<typename T, int64 ndims>
741 {
742  if (!aligned(lhs, rhs)) throw std::domain_error("Attempt to apply + operator to multidimensional arrays with inconsistent dimensions");
743  return arraynd<T, ndims>(lhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
744  return lhs(indices) + rhs(indices);
745  });
746 }
747 
748 
749 template<typename T, int64 ndims, typename U>
751 {
752  return arraynd<T, ndims>(lhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
753  return lhs(indices) + rhs;
754  });
755 }
756 
757 
758 template<typename T, int64 ndims, typename U>
760 {
761  return arraynd<T, ndims>(rhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
762  return lhs + rhs(indices);
763  });
764 }
765 
766 
767 template<typename T, int64 ndims>
769 {
770  if (!aligned(lhs, rhs)) throw std::domain_error("Attempt to apply - operator to multidimensional arrays with inconsistent dimensions");
771  return arraynd<T, ndims>(lhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
772  return lhs(indices) - rhs(indices);
773  });
774 }
775 
776 
777 template<typename T, int64 ndims, typename U>
779 {
780  return arraynd<T, ndims>(lhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
781  return lhs(indices) - rhs;
782  });
783 }
784 
785 
786 template<typename T, int64 ndims, typename U>
788 {
789  return arraynd<T, ndims>(rhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
790  return lhs - rhs(indices);
791  });
792 }
793 
794 
795 template<typename T, int64 ndims>
797 {
798  if (!aligned(lhs, rhs)) throw std::domain_error("Attempt to apply * operator to multidimensional arrays with inconsistent dimensions");
799  return arraynd<T, ndims>(lhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
800  return lhs(indices)*rhs(indices);
801  });
802 }
803 
804 
805 template<typename T, int64 ndims, typename U>
807 {
808  return arraynd<T, ndims>(lhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
809  return lhs(indices)*rhs;
810  });
811 }
812 
813 
814 template<typename T, int64 ndims, typename U>
816 {
817  return arraynd<T, ndims>(rhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
818  return lhs*rhs(indices);
819  });
820 }
821 
822 
823 template<typename T, int64 ndims>
825 {
826  if (!aligned(lhs, rhs)) throw std::domain_error("Attempt to apply / operator to multidimensional arrays with inconsistent dimensions");
827  return arraynd<T, ndims>(lhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
828  return lhs(indices)/rhs(indices);
829  });
830 }
831 
832 
833 template<typename T, int64 ndims, typename U>
835 {
836  return arraynd<T, ndims>(lhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
837  return lhs(indices)/rhs;
838  });
839 }
840 
841 
842 template<typename T, int64 ndims, typename U>
844 {
845  return arraynd<T, ndims>(rhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
846  return lhs/rhs(indices);
847  });
848 }
849 
850 
851 template<int64 ndims>
853 {
854  return arraynd<bool, ndims>(arr.dims(), [&arr](const std::array<int64, ndims>& indices) {
855  return !arr(indices);
856  });
857 }
858 
859 
863 template<int64 ndims>
864 bool all(const arraynd<bool, ndims>& arr)
865 {
866  bool conjunction = true;
867  arr.traverse([&conjunction](const std::array<int64, ndims>& indices, const bool& value) {
868  conjunction = (conjunction && value);
869  return conjunction;
870  });
871  return conjunction;
872 }
873 
874 
878 template<int64 ndims>
879 bool any(const arraynd<bool, ndims>& arr)
880 {
881  bool disjunction = false;
882  arr.traverse([&disjunction](const std::array<int64, ndims>& indices, const bool& value) {
883  disjunction = (disjunction || value);
884  return !disjunction;
885  });
886  return disjunction;
887 }
888 
889 
890 template<typename T, int64 ndims>
891 arraynd<bool, ndims> operator<(const arraynd<T, ndims>& lhs, const arraynd<T, ndims>& rhs)
892 {
893  if (!aligned(lhs, rhs)) throw std::domain_error("Attempt to apply < operator to multidimensional arrays with inconsistent dimensions");
894  return arraynd<bool, ndims>(lhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
895  return lhs(indices) < rhs(indices);
896  });
897 }
898 
899 
900 template<typename T, int64 ndims>
902 {
903  if (!aligned(lhs, rhs)) throw std::domain_error("Attempt to apply > operator to multidimensional arrays with inconsistent dimensions");
904  return arraynd<bool, ndims>(lhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
905  return lhs(indices) > rhs(indices);
906  });
907 }
908 
909 
910 template<typename T, int64 ndims>
911 arraynd<bool, ndims> operator<=(const arraynd<T, ndims>& lhs, const arraynd<T, ndims>& rhs)
912 {
913  if (!aligned(lhs, rhs)) throw std::domain_error("Attempt to apply <= operator to multidimensional arrays with inconsistent dimensions");
914  return arraynd<bool, ndims>(lhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
915  return lhs(indices) <= rhs(indices);
916  });
917 }
918 
919 
920 template<typename T, int64 ndims>
922 {
923  if (!aligned(lhs, rhs)) throw std::domain_error("Attempt to apply >= operator to multidimensional arrays with inconsistent dimensions");
924  return arraynd<bool, ndims>(lhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
925  return lhs(indices) >= rhs(indices);
926  });
927 }
928 
929 
930 template<typename T, int64 ndims>
932 {
933  if (!aligned(lhs, rhs)) throw std::domain_error("Attempt to apply == operator to multidimensional arrays with inconsistent dimensions");
934  return arraynd<bool, ndims>(lhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
935  return lhs(indices) == rhs(indices);
936  });
937 }
938 
939 
940 template<typename T, int64 ndims>
942 {
943  if (!aligned(lhs, rhs)) throw std::domain_error("Attempt to apply != operator to multidimensional arrays with inconsistent dimensions");
944  return arraynd<bool, ndims>(lhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
945  return lhs(indices) != rhs(indices);
946  });
947 }
948 
949 
950 template<int64 ndims>
952 {
953  if (!aligned(lhs, rhs)) throw std::domain_error("Attempt to apply && operator to multidimensional arrays with inconsistent dimensions");
954  return arraynd<bool, ndims>(lhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
955  return lhs(indices) && rhs(indices);
956  });
957 }
958 
959 
960 template<int64 ndims>
962 {
963  if (!aligned(lhs, rhs)) throw std::domain_error("Attempt to apply || operator to multidimensional arrays with inconsistent dimensions");
964  return arraynd<bool, ndims>(lhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
965  return lhs(indices) || rhs(indices);
966  });
967 }
968 
969 
970 template<typename T, int64 ndims, typename U>
971 arraynd<bool, ndims> operator<(const arraynd<T, ndims>& lhs, const U& rhs)
972 {
973  return arraynd<bool, ndims>(lhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
974  return lhs(indices) < rhs;
975  });
976 }
977 
978 
979 template<typename T, int64 ndims, typename U>
981 {
982  return arraynd<bool, ndims>(lhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
983  return lhs(indices) > rhs;
984  });
985 }
986 
987 
988 template<typename T, int64 ndims, typename U>
989 arraynd<bool, ndims> operator<=(const arraynd<T, ndims>& lhs, const U& rhs)
990 {
991  return arraynd<bool, ndims>(lhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
992  return lhs(indices) <= rhs;
993  });
994 }
995 
996 
997 template<typename T, int64 ndims, typename U>
999 {
1000  return arraynd<bool, ndims>(lhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
1001  return lhs(indices) >= rhs;
1002  });
1003 }
1004 
1005 
1006 template<typename T, int64 ndims, typename U>
1008 {
1009  return arraynd<bool, ndims>(lhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
1010  return lhs(indices) == rhs;
1011  });
1012 }
1013 
1014 
1015 template<typename T, int64 ndims, typename U>
1017 {
1018  return arraynd<bool, ndims>(lhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
1019  return lhs(indices) != rhs;
1020  });
1021 }
1022 
1023 
1024 template<int64 ndims>
1026 {
1027  return arraynd<bool, ndims>(lhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
1028  return lhs(indices) && rhs;
1029  });
1030 }
1031 
1032 
1033 template<int64 ndims>
1035 {
1036  return arraynd<bool, ndims>(lhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
1037  return lhs(indices) || rhs;
1038  });
1039 }
1040 
1041 
1042 template<typename T, int64 ndims, typename U>
1043 arraynd<bool, ndims> operator<(const U& lhs, const arraynd<T, ndims>& rhs)
1044 {
1045  return arraynd<bool, ndims>(rhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
1046  return lhs < rhs(indices);
1047  });
1048 }
1049 
1050 
1051 template<typename T, int64 ndims, typename U>
1053 {
1054  return arraynd<bool, ndims>(rhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
1055  return lhs > rhs(indices);
1056  });
1057 }
1058 
1059 
1060 template<typename T, int64 ndims, typename U>
1061 arraynd<bool, ndims> operator<=(const U& lhs, const arraynd<T, ndims>& rhs)
1062 {
1063  return arraynd<bool, ndims>(rhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
1064  return lhs <= rhs(indices);
1065  });
1066 }
1067 
1068 
1069 template<typename T, int64 ndims, typename U>
1071 {
1072  return arraynd<bool, ndims>(rhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
1073  return lhs >= rhs(indices);
1074  });
1075 }
1076 
1077 
1078 template<typename T, int64 ndims, typename U>
1080 {
1081  return arraynd<bool, ndims>(rhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
1082  return lhs == rhs(indices);
1083  });
1084 }
1085 
1086 
1087 template<typename T, int64 ndims, typename U>
1089 {
1090  return arraynd<bool, ndims>(rhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
1091  return lhs != rhs(indices);
1092  });
1093 }
1094 
1095 
1096 template<int64 ndims>
1098 {
1099  return arraynd<bool, ndims>(rhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
1100  return lhs && rhs(indices);
1101  });
1102 }
1103 
1104 
1105 template<int64 ndims>
1107 {
1108  return arraynd<bool, ndims>(rhs.dims(), [&lhs, &rhs](const std::array<int64, ndims>& indices) {
1109  return lhs || rhs(indices);
1110  });
1111 }
1112 
1113 
1118 template<typename T, int64 ndims, typename U>
1120 {
1121  return arraynd<T, ndims>(arr.dims(), [&arr](const std::array<int64, ndims>& indices) {
1122  return static_cast<T>(arr(indices));
1123  });
1124 }
1125 
1126 
1131 template<typename T, int64 ndims, typename U>
1132 arraynd<T, ndims> replace(const arraynd<T, ndims>& lhs, const arraynd<bool, ndims>& selection, const U& rhs)
1133 {
1134  return arraynd<T, ndims>(lhs.dims(), [&lhs, &selection, &rhs](const std::array<int64, ndims>& indices) {
1135  return selection(indices) ? rhs : lhs(indices);
1136  });
1137 }
1138 
1139 
1145 template<typename T, int64 ndims, typename U>
1147 {
1148  if (!aligned(lhs, rhs)) throw std::domain_error("Attempt to replace values using multidimensional arrays with inconsistent dimensions");
1149  return arraynd<T, ndims>(lhs.dims(), [&lhs, &selection, &rhs](const std::array<int64, ndims>& indices) {
1150  return selection(indices) ? rhs(indices) : lhs(indices);
1151  });
1152 }
1153 
1154 
1155 template<typename T, int64 ndims>
1156 std::ostream& operator<<(std::ostream& os, const arraynd<T, ndims>& rhs)
1157 {
1158  auto indices = std::array<int64, ndims>();
1159  for (int64 idim = 0; idim < ndims; ++idim) {
1160  indices[idim] = 0;
1161  }
1162  int64 offset = rhs.offset();
1163  int64 idim = 0;
1164  os << "{";
1165  while (idim >= 0) {
1166  if (indices[idim] < rhs.dims()[idim]) {
1167  // The index is not beyond the last element on the current axis.
1168  // Continue outputting the current sub-array.
1169  if (indices[idim] > 0) {
1170  // This is not the first element on the current axis.
1171  // Output a delimiter.
1172  os << ", ";
1173  }
1174  if (idim == ndims - 1) {
1175  // The current axis is the last one.
1176  // Output the current element and advance the index.
1177  os << rhs.data()[offset];
1178  ++indices[idim];
1179  offset += rhs.strides()[idim];
1180  }
1181  else {
1182  // The current axis is not the last one.
1183  // Start outputting a new sub-array.
1184  ++idim;
1185  os << "{";
1186  }
1187  }
1188  else {
1189  // The index is beyond the last element on the current axis.
1190  // Finish outputting the current sub-array.
1191  indices[idim] = 0;
1192  offset -= rhs.dims()[idim]*rhs.strides()[idim];
1193  --idim;
1194  if (idim >= 0) {
1195  ++indices[idim];
1196  offset += rhs.strides()[idim];
1197  os << "}";
1198  }
1199  }
1200  }
1201  os << "}";
1202  return os;
1203 }
1204 
1205 
1206 } // namespace
1207 
1208 
1209 namespace std {
1215 template<typename T>
1216 struct less<sydevs::array1d<T>>
1217 {
1218  bool operator()(const sydevs::array1d<T>& lhs, const sydevs::array1d<T>& rhs) const {
1219  return std::lexicographical_compare(lhs.data(), lhs.data() + lhs.size(),
1220  rhs.data(), rhs.data() + rhs.size());
1221  }
1222 };
1223 }
1224 
1225 
1226 #endif
arraynd< bool, ndims > operator==(const arraynd< T, ndims > &lhs, const arraynd< T, ndims > &rhs)
Definition: arraynd.h:931
arraynd< T, ndims > operator+(const arraynd< T, ndims > &rhs)
Definition: arraynd.h:724
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 data type which represents a range of array indices along a single dimension.
Definition: range.h:51
std::array< int64, ndims > dims() const
Returns the lengths of each dimension.
Definition: arraynd_base.h:197
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
bool aligned(const arraynd< T, ndims > &lhs, const arraynd< T, ndims > &rhs)
Definition: arraynd.h:713
const T * data() const
Returns a pointer to the element data (const).
Definition: arraynd_base.h:237
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
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
arraynd< T, 1 > array1d
Definition: arraynd.h:366
arraynd()
Constructs an arraynd object with dimensions of length zero.
Definition: arraynd.h:380
arraynd< bool, ndims > operator!(const arraynd< bool, ndims > &arr)
Definition: arraynd.h:852
~arraynd()=default
Destructor.
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< bool, ndims > operator>(const arraynd< T, ndims > &lhs, const arraynd< T, ndims > &rhs)
Definition: arraynd.h:901
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:1132
bool any(const arraynd< bool, ndims > &arr)
Returns true if any element of arr is true.
Definition: arraynd.h:879
A class template for a multidimensional array with elements of type T arranged in a lattice of ndims ...
Definition: arraynd.h:187
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:1119
A base class template for a multidimensional array with elements of type T arranged in a lattice of n...
Definition: arraynd_base.h:25
const arraynd< T, ndims > view_transposed() const
Create a const transposed view of the multidimensional array (data is shared).
Definition: arraynd.h:457
bool all(const arraynd< bool, ndims > &arr)
Returns true if all elements of arr are true.
Definition: arraynd.h:864
arraynd< bool, ndims > operator||(const arraynd< bool, ndims > &lhs, const arraynd< bool, ndims > &rhs)
Definition: arraynd.h:961
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 > 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
int64 size() const
Returns the total number of elements.
int64 offset() const
Returns the number of element-size steps in memory before the first element.
Definition: arraynd_base.h:229
bool operator()(const sydevs::array1d< T > &lhs, const sydevs::array1d< T > &rhs) const
Definition: arraynd.h:1218
arraynd< T, ndims > operator-(const arraynd< T, ndims > &rhs)
Definition: arraynd.h:731
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< bool, ndims > operator>=(const arraynd< T, ndims > &lhs, const arraynd< T, ndims > &rhs)
Definition: arraynd.h:921
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-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
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
A one-dimensional (1D) specialization of the arraynd multidimensional array template.
Definition: arraynd.h:291
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_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< bool, ndims > operator!=(const arraynd< T, ndims > &lhs, const arraynd< T, ndims > &rhs)
Definition: arraynd.h:941
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
arraynd< T, ndims > operator*(const arraynd< T, ndims > &lhs, const arraynd< T, ndims > &rhs)
Definition: arraynd.h:796
int64_t int64
Definition: number_types.h:14
const arraynd< T, ndims > view() const
Create a const view of the multidimensional array (data is shared).
Definition: arraynd.h:436
arraynd< bool, ndims > operator&&(const arraynd< bool, ndims > &lhs, const arraynd< bool, ndims > &rhs)
Definition: arraynd.h:951
arraynd< T, ndims > operator/(const arraynd< T, ndims > &lhs, const arraynd< T, ndims > &rhs)
Definition: arraynd.h:824