Ginkgo  Generated from tags/v1.0.0^0 branch based on master. Ginkgo version 1.0.0
A numerical linear algebra library targeting many-core architectures
range.hpp
1 /*******************************<GINKGO LICENSE>******************************
2 Copyright (c) 2017-2019, the Ginkgo authors
3 All rights reserved.
4 
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8 
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in the
14 documentation and/or other materials provided with the distribution.
15 
16 3. Neither the name of the copyright holder nor the names of its
17 contributors may be used to endorse or promote products derived from
18 this software without specific prior written permission.
19 
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
21 IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 ******************************<GINKGO LICENSE>*******************************/
32 
33 #ifndef GKO_CORE_BASE_RANGE_HPP_
34 #define GKO_CORE_BASE_RANGE_HPP_
35 
36 
37 #include <ginkgo/core/base/math.hpp>
38 #include <ginkgo/core/base/std_extensions.hpp>
39 #include <ginkgo/core/base/types.hpp>
40 #include <ginkgo/core/base/utils.hpp>
41 
42 
43 namespace gko {
44 
45 
73 struct span {
81  GKO_ATTRIBUTES constexpr span(size_type point) noexcept
82  : span{point, point + 1}
83  {}
84 
91  GKO_ATTRIBUTES constexpr span(size_type begin, size_type end) noexcept
92  : begin{begin}, end{end}
93  {}
94 
100  constexpr bool is_valid() const { return begin < end; }
101 
106 
110  const size_type end;
111 };
112 
113 
114 GKO_ATTRIBUTES GKO_INLINE constexpr bool operator<(const span &first,
115  const span &second)
116 {
117  return first.end < second.begin;
118 }
119 
120 
121 GKO_ATTRIBUTES GKO_INLINE constexpr bool operator<=(const span &first,
122  const span &second)
123 {
124  return first.end <= second.begin;
125 }
126 
127 
128 GKO_ATTRIBUTES GKO_INLINE constexpr bool operator>(const span &first,
129  const span &second)
130 {
131  return second < first;
132 }
133 
134 
135 GKO_ATTRIBUTES GKO_INLINE constexpr bool operator>=(const span &first,
136  const span &second)
137 {
138  return second <= first;
139 }
140 
141 
142 GKO_ATTRIBUTES GKO_INLINE constexpr bool operator==(const span &first,
143  const span &second)
144 {
145  return first.begin == second.begin && first.end == second.end;
146 }
147 
148 
149 GKO_ATTRIBUTES GKO_INLINE constexpr bool operator!=(const span &first,
150  const span &second)
151 {
152  return !(first == second);
153 }
154 
155 
156 namespace detail {
157 
158 
159 template <size_type CurrentDimension = 0, typename FirstRange,
160  typename SecondRange>
161 GKO_ATTRIBUTES constexpr GKO_INLINE
162  xstd::enable_if_t<(CurrentDimension >= max(FirstRange::dimensionality,
163  SecondRange::dimensionality)),
164  bool>
165  equal_dimensions(const FirstRange &, const SecondRange &)
166 {
167  return true;
168 }
169 
170 template <size_type CurrentDimension = 0, typename FirstRange,
171  typename SecondRange>
172 GKO_ATTRIBUTES constexpr GKO_INLINE
173  xstd::enable_if_t<(CurrentDimension < max(FirstRange::dimensionality,
174  SecondRange::dimensionality)),
175  bool>
176  equal_dimensions(const FirstRange &first, const SecondRange &second)
177 {
178  return first.length(CurrentDimension) == second.length(CurrentDimension) &&
179  equal_dimensions<CurrentDimension + 1>(first, second);
180 }
181 
182 
183 } // namespace detail
184 
185 
295 template <typename Accessor>
296 class range {
297 public:
301  using accessor = Accessor;
302 
306  static constexpr size_type dimensionality = accessor::dimensionality;
307 
316  template <typename... AccessorParams>
317  GKO_ATTRIBUTES constexpr explicit range(AccessorParams &&... params)
318  : accessor_{std::forward<AccessorParams>(params)...}
319  {}
320 
333  template <typename... DimensionTypes>
334  GKO_ATTRIBUTES constexpr auto operator()(DimensionTypes &&... dimensions)
335  const -> decltype(std::declval<accessor>()(
336  std::forward<DimensionTypes>(dimensions)...))
337  {
338  static_assert(sizeof...(dimensions) <= dimensionality,
339  "Too many dimensions in range call");
340  return accessor_(std::forward<DimensionTypes>(dimensions)...);
341  }
342 
351  template <typename OtherAccessor>
352  GKO_ATTRIBUTES const range &operator=(
353  const range<OtherAccessor> &other) const
354  {
355  GKO_ASSERT(detail::equal_dimensions(*this, other));
356  accessor_.copy_from(other);
357  return *this;
358  }
359 
373  GKO_ATTRIBUTES const range &operator=(const range &other) const
374  {
375  GKO_ASSERT(detail::equal_dimensions(*this, other));
376  accessor_.copy_from(other.get_accessor());
377  return *this;
378  }
379 
387  GKO_ATTRIBUTES constexpr size_type length(size_type dimension) const
388  {
389  return accessor_.length(dimension);
390  }
391 
399  GKO_ATTRIBUTES constexpr const accessor *operator->() const noexcept
400  {
401  return &accessor_;
402  }
403 
409  GKO_ATTRIBUTES constexpr const accessor &get_accessor() const noexcept
410  {
411  return accessor_;
412  }
413 
414 private:
415  accessor accessor_;
416 };
417 
418 
419 // implementation of range operations follows
420 // (you probably should not have to look at this unless you're interested in the
421 // gory details)
422 
423 
424 namespace detail {
425 
426 
427 enum class operation_kind { range_by_range, scalar_by_range, range_by_scalar };
428 
429 
430 template <typename Accessor, typename Operation>
431 struct implement_unary_operation {
432  using accessor = Accessor;
433  static constexpr size_type dimensionality = accessor::dimensionality;
434 
435  GKO_ATTRIBUTES constexpr explicit implement_unary_operation(
436  const Accessor &operand)
437  : operand{operand}
438  {}
439 
440  template <typename... DimensionTypes>
441  GKO_ATTRIBUTES constexpr auto operator()(
442  const DimensionTypes &... dimensions) const
443  -> decltype(Operation::evaluate(std::declval<accessor>(),
444  dimensions...))
445  {
446  return Operation::evaluate(operand, dimensions...);
447  }
448 
449  GKO_ATTRIBUTES constexpr size_type length(size_type dimension) const
450  {
451  return operand.length(dimension);
452  }
453 
454  template <typename OtherAccessor>
455  GKO_ATTRIBUTES void copy_from(const OtherAccessor &other) const = delete;
456 
457  const accessor operand;
458 };
459 
460 
461 template <operation_kind Kind, typename FirstOperand, typename SecondOperand,
462  typename Operation>
463 struct implement_binary_operation {};
464 
465 template <typename FirstAccessor, typename SecondAccessor, typename Operation>
466 struct implement_binary_operation<operation_kind::range_by_range, FirstAccessor,
467  SecondAccessor, Operation> {
468  using first_accessor = FirstAccessor;
469  using second_accessor = SecondAccessor;
470  static_assert(first_accessor::dimensionality ==
471  second_accessor::dimensionality,
472  "Both ranges need to have the same number of dimensions");
473  static constexpr size_type dimensionality = first_accessor::dimensionality;
474 
475  GKO_ATTRIBUTES explicit implement_binary_operation(
476  const FirstAccessor &first, const SecondAccessor &second)
477  : first{first}, second{second}
478  {
479  GKO_ASSERT(gko::detail::equal_dimensions(first, second));
480  }
481 
482  template <typename... DimensionTypes>
483  GKO_ATTRIBUTES constexpr auto operator()(
484  const DimensionTypes &... dimensions) const
485  -> decltype(Operation::evaluate_range_by_range(
486  std::declval<first_accessor>(), std::declval<second_accessor>(),
487  dimensions...))
488  {
489  return Operation::evaluate_range_by_range(first, second, dimensions...);
490  }
491 
492  GKO_ATTRIBUTES constexpr size_type length(size_type dimension) const
493  {
494  return first.length(dimension);
495  }
496 
497  template <typename OtherAccessor>
498  GKO_ATTRIBUTES void copy_from(const OtherAccessor &other) const = delete;
499 
500  const first_accessor first;
501  const second_accessor second;
502 };
503 
504 template <typename FirstOperand, typename SecondAccessor, typename Operation>
505 struct implement_binary_operation<operation_kind::scalar_by_range, FirstOperand,
506  SecondAccessor, Operation> {
507  using second_accessor = SecondAccessor;
508  static constexpr size_type dimensionality = second_accessor::dimensionality;
509 
510  GKO_ATTRIBUTES constexpr explicit implement_binary_operation(
511  const FirstOperand &first, const SecondAccessor &second)
512  : first{first}, second{second}
513  {}
514 
515  template <typename... DimensionTypes>
516  GKO_ATTRIBUTES constexpr auto operator()(
517  const DimensionTypes &... dimensions) const
518  -> decltype(Operation::evaluate_scalar_by_range(
519  std::declval<FirstOperand>(), std::declval<second_accessor>(),
520  dimensions...))
521  {
522  return Operation::evaluate_scalar_by_range(first, second,
523  dimensions...);
524  }
525 
526  GKO_ATTRIBUTES constexpr size_type length(size_type dimension) const
527  {
528  return second.length(dimension);
529  }
530 
531  template <typename OtherAccessor>
532  GKO_ATTRIBUTES void copy_from(const OtherAccessor &other) const = delete;
533 
534  const FirstOperand first;
535  const second_accessor second;
536 };
537 
538 template <typename FirstAccessor, typename SecondOperand, typename Operation>
539 struct implement_binary_operation<operation_kind::range_by_scalar,
540  FirstAccessor, SecondOperand, Operation> {
541  using first_accessor = FirstAccessor;
542  static constexpr size_type dimensionality = first_accessor::dimensionality;
543 
544  GKO_ATTRIBUTES constexpr explicit implement_binary_operation(
545  const FirstAccessor &first, const SecondOperand &second)
546  : first{first}, second{second}
547  {}
548 
549  template <typename... DimensionTypes>
550  GKO_ATTRIBUTES constexpr auto operator()(
551  const DimensionTypes &... dimensions) const
552  -> decltype(Operation::evaluate_range_by_scalar(
553  std::declval<first_accessor>(), std::declval<SecondOperand>(),
554  dimensions...))
555  {
556  return Operation::evaluate_range_by_scalar(first, second,
557  dimensions...);
558  }
559 
560  GKO_ATTRIBUTES constexpr size_type length(size_type dimension) const
561  {
562  return first.length(dimension);
563  }
564 
565  template <typename OtherAccessor>
566  GKO_ATTRIBUTES void copy_from(const OtherAccessor &other) const = delete;
567 
568  const first_accessor first;
569  const SecondOperand second;
570 };
571 
572 
573 } // namespace detail
574 
575 
576 #define GKO_ENABLE_UNARY_RANGE_OPERATION(_operation_name, _operator_name, \
577  _operator) \
578  namespace accessor { \
579  template <typename Operand> \
580  struct _operation_name \
581  : ::gko::detail::implement_unary_operation<Operand, \
582  ::gko::_operator> { \
583  using ::gko::detail::implement_unary_operation< \
584  Operand, ::gko::_operator>::implement_unary_operation; \
585  }; \
586  } \
587  GKO_BIND_UNARY_RANGE_OPERATION_TO_OPERATOR(_operation_name, _operator_name)
588 
589 
590 #define GKO_BIND_UNARY_RANGE_OPERATION_TO_OPERATOR(_operation_name, \
591  _operator_name) \
592  template <typename Accessor> \
593  GKO_ATTRIBUTES constexpr GKO_INLINE \
594  range<accessor::_operation_name<Accessor>> \
595  _operator_name(const range<Accessor> &operand) \
596  { \
597  return range<accessor::_operation_name<Accessor>>( \
598  operand.get_accessor()); \
599  } \
600  static_assert(true, \
601  "This assert is used to counter the false positive extra " \
602  "semi-colon warnings")
603 
604 
605 #define GKO_DEFINE_SIMPLE_UNARY_OPERATION(_name, ...) \
606  struct _name { \
607  private: \
608  template <typename Operand> \
609  GKO_ATTRIBUTES static constexpr auto simple_evaluate_impl( \
610  const Operand &operand) -> decltype(__VA_ARGS__) \
611  { \
612  return __VA_ARGS__; \
613  } \
614  \
615  public: \
616  template <typename AccessorType, typename... DimensionTypes> \
617  GKO_ATTRIBUTES static constexpr auto evaluate( \
618  const AccessorType &accessor, \
619  const DimensionTypes &... dimensions) \
620  -> decltype(simple_evaluate_impl(accessor(dimensions...))) \
621  { \
622  return simple_evaluate_impl(accessor(dimensions...)); \
623  } \
624  }
625 
626 
627 namespace accessor {
628 namespace detail {
629 
630 
631 // unary arithmetic
632 GKO_DEFINE_SIMPLE_UNARY_OPERATION(unary_plus, +operand);
633 GKO_DEFINE_SIMPLE_UNARY_OPERATION(unary_minus, -operand);
634 
635 // unary logical
636 GKO_DEFINE_SIMPLE_UNARY_OPERATION(logical_not, !operand);
637 
638 // unary bitwise
639 GKO_DEFINE_SIMPLE_UNARY_OPERATION(bitwise_not, ~(operand));
640 
641 // common functions
642 GKO_DEFINE_SIMPLE_UNARY_OPERATION(zero_operation, zero(operand));
643 GKO_DEFINE_SIMPLE_UNARY_OPERATION(one_operation, one(operand));
644 GKO_DEFINE_SIMPLE_UNARY_OPERATION(abs_operation, abs(operand));
645 GKO_DEFINE_SIMPLE_UNARY_OPERATION(real_operation, real(operand));
646 GKO_DEFINE_SIMPLE_UNARY_OPERATION(imag_operation, imag(operand));
647 GKO_DEFINE_SIMPLE_UNARY_OPERATION(conj_operation, conj(operand));
648 GKO_DEFINE_SIMPLE_UNARY_OPERATION(squared_norm_operation,
649  squared_norm(operand));
650 
651 } // namespace detail
652 } // namespace accessor
653 
654 
655 // unary arithmetic
656 GKO_ENABLE_UNARY_RANGE_OPERATION(unary_plus, operator+,
657  accessor::detail::unary_plus);
658 GKO_ENABLE_UNARY_RANGE_OPERATION(unary_minus, operator-,
659  accessor::detail::unary_minus);
660 
661 // unary logical
662 GKO_ENABLE_UNARY_RANGE_OPERATION(logical_not, operator!,
663  accessor::detail::logical_not);
664 
665 // unary bitwise
666 GKO_ENABLE_UNARY_RANGE_OPERATION(bitwise_not, operator~,
667  accessor::detail::bitwise_not);
668 
669 // common unary functions
670 GKO_ENABLE_UNARY_RANGE_OPERATION(zero_operation, zero,
671  accessor::detail::zero_operation);
672 GKO_ENABLE_UNARY_RANGE_OPERATION(one_operaton, one,
673  accessor::detail::one_operation);
674 GKO_ENABLE_UNARY_RANGE_OPERATION(abs_operaton, abs,
675  accessor::detail::abs_operation);
676 GKO_ENABLE_UNARY_RANGE_OPERATION(real_operaton, real,
677  accessor::detail::real_operation);
678 GKO_ENABLE_UNARY_RANGE_OPERATION(imag_operaton, imag,
679  accessor::detail::imag_operation);
680 GKO_ENABLE_UNARY_RANGE_OPERATION(conj_operaton, conj,
681  accessor::detail::conj_operation);
682 GKO_ENABLE_UNARY_RANGE_OPERATION(squared_norm_operaton, squared_norm,
683  accessor::detail::squared_norm_operation);
684 
685 namespace accessor {
686 
687 
688 template <typename Accessor>
690  using accessor = Accessor;
691  static constexpr size_type dimensionality = accessor::dimensionality;
692 
693  GKO_ATTRIBUTES constexpr explicit transpose_operation(
694  const Accessor &operand)
695  : operand{operand}
696  {}
697 
698  template <typename FirstDimensionType, typename SecondDimensionType,
699  typename... DimensionTypes>
700  GKO_ATTRIBUTES constexpr auto operator()(
701  const FirstDimensionType &first_dim,
702  const SecondDimensionType &second_dim,
703  const DimensionTypes &... dims) const
704  -> decltype(std::declval<accessor>()(second_dim, first_dim, dims...))
705  {
706  return operand(second_dim, first_dim, dims...);
707  }
708 
709  GKO_ATTRIBUTES constexpr size_type length(size_type dimension) const
710  {
711  return dimension < 2 ? operand.length(dimension ^ 1)
712  : operand.length(dimension);
713  }
714 
715  template <typename OtherAccessor>
716  GKO_ATTRIBUTES void copy_from(const OtherAccessor &other) const = delete;
717 
718  const accessor operand;
719 };
720 
721 
722 } // namespace accessor
723 
724 
725 GKO_BIND_UNARY_RANGE_OPERATION_TO_OPERATOR(transpose_operation, transpose);
726 
727 
728 #undef GKO_DEFINE_SIMPLE_UNARY_OPERATION
729 #undef GKO_ENABLE_UNARY_RANGE_OPERATION
730 
731 
732 #define GKO_ENABLE_BINARY_RANGE_OPERATION(_operation_name, _operator_name, \
733  _operator) \
734  namespace accessor { \
735  template <::gko::detail::operation_kind Kind, typename FirstOperand, \
736  typename SecondOperand> \
737  struct _operation_name \
738  : ::gko::detail::implement_binary_operation< \
739  Kind, FirstOperand, SecondOperand, ::gko::_operator> { \
740  using ::gko::detail::implement_binary_operation< \
741  Kind, FirstOperand, SecondOperand, \
742  ::gko::_operator>::implement_binary_operation; \
743  }; \
744  } \
745  GKO_BIND_RANGE_OPERATION_TO_OPERATOR(_operation_name, _operator_name); \
746  static_assert(true, \
747  "This assert is used to counter the false positive extra " \
748  "semi-colon warnings")
749 
750 
751 #define GKO_BIND_RANGE_OPERATION_TO_OPERATOR(_operation_name, _operator_name) \
752  template <typename Accessor> \
753  GKO_ATTRIBUTES constexpr GKO_INLINE range<accessor::_operation_name< \
754  ::gko::detail::operation_kind::range_by_range, Accessor, Accessor>> \
755  _operator_name(const range<Accessor> &first, \
756  const range<Accessor> &second) \
757  { \
758  return range<accessor::_operation_name< \
759  ::gko::detail::operation_kind::range_by_range, Accessor, \
760  Accessor>>(first.get_accessor(), second.get_accessor()); \
761  } \
762  \
763  template <typename FirstAccessor, typename SecondAccessor> \
764  GKO_ATTRIBUTES constexpr GKO_INLINE range<accessor::_operation_name< \
765  ::gko::detail::operation_kind::range_by_range, FirstAccessor, \
766  SecondAccessor>> \
767  _operator_name(const range<FirstAccessor> &first, \
768  const range<SecondAccessor> &second) \
769  { \
770  return range<accessor::_operation_name< \
771  ::gko::detail::operation_kind::range_by_range, FirstAccessor, \
772  SecondAccessor>>(first.get_accessor(), second.get_accessor()); \
773  } \
774  \
775  template <typename FirstAccessor, typename SecondOperand> \
776  GKO_ATTRIBUTES constexpr GKO_INLINE range<accessor::_operation_name< \
777  ::gko::detail::operation_kind::range_by_scalar, FirstAccessor, \
778  SecondOperand>> \
779  _operator_name(const range<FirstAccessor> &first, \
780  const SecondOperand &second) \
781  { \
782  return range<accessor::_operation_name< \
783  ::gko::detail::operation_kind::range_by_scalar, FirstAccessor, \
784  SecondOperand>>(first.get_accessor(), second); \
785  } \
786  \
787  template <typename FirstOperand, typename SecondAccessor> \
788  GKO_ATTRIBUTES constexpr GKO_INLINE range<accessor::_operation_name< \
789  ::gko::detail::operation_kind::scalar_by_range, FirstOperand, \
790  SecondAccessor>> \
791  _operator_name(const FirstOperand &first, \
792  const range<SecondAccessor> &second) \
793  { \
794  return range<accessor::_operation_name< \
795  ::gko::detail::operation_kind::scalar_by_range, FirstOperand, \
796  SecondAccessor>>(first, second.get_accessor()); \
797  } \
798  static_assert(true, \
799  "This assert is used to counter the false positive extra " \
800  "semi-colon warnings")
801 
802 
803 #define GKO_DEFINE_SIMPLE_BINARY_OPERATION(_name, ...) \
804  struct _name { \
805  private: \
806  template <typename FirstOperand, typename SecondOperand> \
807  GKO_ATTRIBUTES constexpr static auto simple_evaluate_impl( \
808  const FirstOperand &first, const SecondOperand &second) \
809  -> decltype(__VA_ARGS__) \
810  { \
811  return __VA_ARGS__; \
812  } \
813  \
814  public: \
815  template <typename FirstAccessor, typename SecondAccessor, \
816  typename... DimensionTypes> \
817  GKO_ATTRIBUTES static constexpr auto evaluate_range_by_range( \
818  const FirstAccessor &first, const SecondAccessor &second, \
819  const DimensionTypes &... dims) \
820  -> decltype(simple_evaluate_impl(first(dims...), second(dims...))) \
821  { \
822  return simple_evaluate_impl(first(dims...), second(dims...)); \
823  } \
824  \
825  template <typename FirstOperand, typename SecondAccessor, \
826  typename... DimensionTypes> \
827  GKO_ATTRIBUTES static constexpr auto evaluate_scalar_by_range( \
828  const FirstOperand &first, const SecondAccessor &second, \
829  const DimensionTypes &... dims) \
830  -> decltype(simple_evaluate_impl(first, second(dims...))) \
831  { \
832  return simple_evaluate_impl(first, second(dims...)); \
833  } \
834  \
835  template <typename FirstAccessor, typename SecondOperand, \
836  typename... DimensionTypes> \
837  GKO_ATTRIBUTES static constexpr auto evaluate_range_by_scalar( \
838  const FirstAccessor &first, const SecondOperand &second, \
839  const DimensionTypes &... dims) \
840  -> decltype(simple_evaluate_impl(first(dims...), second)) \
841  { \
842  return simple_evaluate_impl(first(dims...), second); \
843  } \
844  }
845 
846 
847 namespace accessor {
848 namespace detail {
849 
850 
851 // binary arithmetic
852 GKO_DEFINE_SIMPLE_BINARY_OPERATION(add, first + second);
853 GKO_DEFINE_SIMPLE_BINARY_OPERATION(sub, first - second);
854 GKO_DEFINE_SIMPLE_BINARY_OPERATION(mul, first *second);
855 GKO_DEFINE_SIMPLE_BINARY_OPERATION(div, first / second);
856 GKO_DEFINE_SIMPLE_BINARY_OPERATION(mod, first % second);
857 
858 // relational
859 GKO_DEFINE_SIMPLE_BINARY_OPERATION(less, first < second);
860 GKO_DEFINE_SIMPLE_BINARY_OPERATION(greater, first > second);
861 GKO_DEFINE_SIMPLE_BINARY_OPERATION(less_or_equal, first <= second);
862 GKO_DEFINE_SIMPLE_BINARY_OPERATION(greater_or_equal, first >= second);
863 GKO_DEFINE_SIMPLE_BINARY_OPERATION(equal, first == second);
864 GKO_DEFINE_SIMPLE_BINARY_OPERATION(not_equal, first != second);
865 
866 // binary logical
867 GKO_DEFINE_SIMPLE_BINARY_OPERATION(logical_or, first || second);
868 GKO_DEFINE_SIMPLE_BINARY_OPERATION(logical_and, first &&second);
869 
870 // binary bitwise
871 GKO_DEFINE_SIMPLE_BINARY_OPERATION(bitwise_or, first | second);
872 GKO_DEFINE_SIMPLE_BINARY_OPERATION(bitwise_and, first &second);
873 GKO_DEFINE_SIMPLE_BINARY_OPERATION(bitwise_xor, first ^ second);
874 GKO_DEFINE_SIMPLE_BINARY_OPERATION(left_shift, first << second);
875 GKO_DEFINE_SIMPLE_BINARY_OPERATION(right_shift, first >> second);
876 
877 // common binary functions
878 GKO_DEFINE_SIMPLE_BINARY_OPERATION(max_operation, max(first, second));
879 GKO_DEFINE_SIMPLE_BINARY_OPERATION(min_operation, min(first, second));
880 
881 } // namespace detail
882 } // namespace accessor
883 
884 
885 // binary arithmetic
886 GKO_ENABLE_BINARY_RANGE_OPERATION(add, operator+, accessor::detail::add);
887 GKO_ENABLE_BINARY_RANGE_OPERATION(sub, operator-, accessor::detail::sub);
888 GKO_ENABLE_BINARY_RANGE_OPERATION(mul, operator*, accessor::detail::mul);
889 GKO_ENABLE_BINARY_RANGE_OPERATION(div, operator/, accessor::detail::div);
890 GKO_ENABLE_BINARY_RANGE_OPERATION(mod, operator%, accessor::detail::mod);
891 
892 // relational
893 GKO_ENABLE_BINARY_RANGE_OPERATION(less, operator<, accessor::detail::less);
894 GKO_ENABLE_BINARY_RANGE_OPERATION(greater, operator>,
895  accessor::detail::greater);
896 GKO_ENABLE_BINARY_RANGE_OPERATION(less_or_equal, operator<=,
897  accessor::detail::less_or_equal);
898 GKO_ENABLE_BINARY_RANGE_OPERATION(greater_or_equal, operator>=,
899  accessor::detail::greater_or_equal);
900 GKO_ENABLE_BINARY_RANGE_OPERATION(equal, operator==, accessor::detail::equal);
901 GKO_ENABLE_BINARY_RANGE_OPERATION(not_equal, operator!=,
902  accessor::detail::not_equal);
903 
904 // binary logical
905 GKO_ENABLE_BINARY_RANGE_OPERATION(logical_or, operator||,
906  accessor::detail::logical_or);
907 GKO_ENABLE_BINARY_RANGE_OPERATION(logical_and, operator&&,
908  accessor::detail::logical_and);
909 
910 // binary bitwise
911 GKO_ENABLE_BINARY_RANGE_OPERATION(bitwise_or, operator|,
912  accessor::detail::bitwise_or);
913 GKO_ENABLE_BINARY_RANGE_OPERATION(bitwise_and, operator&,
914  accessor::detail::bitwise_and);
915 GKO_ENABLE_BINARY_RANGE_OPERATION(bitwise_xor, operator^,
916  accessor::detail::bitwise_xor);
917 GKO_ENABLE_BINARY_RANGE_OPERATION(left_shift, operator<<,
918  accessor::detail::left_shift);
919 GKO_ENABLE_BINARY_RANGE_OPERATION(right_shift, operator>>,
920  accessor::detail::right_shift);
921 
922 // common binary functions
923 GKO_ENABLE_BINARY_RANGE_OPERATION(max_operaton, max,
924  accessor::detail::max_operation);
925 GKO_ENABLE_BINARY_RANGE_OPERATION(min_operaton, min,
926  accessor::detail::min_operation);
927 
928 
929 // special binary range functions
930 namespace accessor {
931 
932 
933 template <gko::detail::operation_kind Kind, typename FirstAccessor,
934  typename SecondAccessor>
936  static_assert(Kind == gko::detail::operation_kind::range_by_range,
937  "Matrix multiplication expects both operands to be ranges");
938  using first_accessor = FirstAccessor;
939  using second_accessor = SecondAccessor;
940  static_assert(first_accessor::dimensionality ==
941  second_accessor::dimensionality,
942  "Both ranges need to have the same number of dimensions");
943  static constexpr size_type dimensionality = first_accessor::dimensionality;
944 
945  GKO_ATTRIBUTES explicit mmul_operation(const FirstAccessor &first,
946  const SecondAccessor &second)
947  : first{first}, second{second}
948  {
949  GKO_ASSERT(first.length(1) == second.length(0));
950  GKO_ASSERT(gko::detail::equal_dimensions<2>(first, second));
951  }
952 
953  template <typename FirstDimension, typename SecondDimension,
954  typename... DimensionTypes>
955  GKO_ATTRIBUTES auto operator()(const FirstDimension &row,
956  const SecondDimension &col,
957  const DimensionTypes &... rest) const
958  -> decltype(std::declval<FirstAccessor>()(row, 0, rest...) *
959  std::declval<SecondAccessor>()(0, col, rest...) +
960  std::declval<FirstAccessor>()(row, 1, rest...) *
961  std::declval<SecondAccessor>()(1, col, rest...))
962  {
963  using result_type =
964  decltype(first(row, 0, rest...) * second(0, col, rest...) +
965  first(row, 1, rest...) * second(1, col, rest...));
966  GKO_ASSERT(first.length(1) == second.length(0));
967  auto result = zero<result_type>();
968  const auto size = first.length(1);
969  for (auto i = zero(size); i < size; ++i) {
970  result += first(row, i, rest...) * second(i, col, rest...);
971  }
972  return result;
973  }
974 
975  GKO_ATTRIBUTES constexpr size_type length(size_type dimension) const
976  {
977  return dimension == 1 ? second.length(1) : first.length(dimension);
978  }
979 
980  template <typename OtherAccessor>
981  GKO_ATTRIBUTES void copy_from(const OtherAccessor &other) const = delete;
982 
983  const first_accessor first;
984  const second_accessor second;
985 };
986 
987 
988 } // namespace accessor
989 
990 
991 GKO_BIND_RANGE_OPERATION_TO_OPERATOR(mmul_operation, mmul);
992 
993 
994 #undef GKO_DEFINE_SIMPLE_BINARY_OPERATION
995 #undef GKO_ENABLE_BINARY_RANGE_OPERATION
996 
997 
998 } // namespace gko
999 
1000 
1001 #endif // GKO_CORE_BASE_RANGE_HPP_
Definition: range.hpp:900
Definition: range.hpp:895
Definition: range.hpp:889
const size_type end
End of the span.
Definition: range.hpp:110
Definition: range.hpp:893
Definition: range.hpp:899
Definition: range.hpp:675
constexpr const accessor & get_accessor() const noexcept
`Returns a reference to the accessor.
Definition: range.hpp:409
Definition: range.hpp:886
constexpr bool is_valid() const
Checks if a span is valid.
Definition: range.hpp:100
Definition: range.hpp:679
constexpr T zero()
Returns the additive identity for T.
Definition: math.hpp:292
constexpr span(size_type begin, size_type end) noexcept
Creates a span.
Definition: range.hpp:91
constexpr bool operator!=(const dim< Dimensionality, DimensionType > &x, const dim< Dimensionality, DimensionType > &y)
Checks if two dim objects are different.
Definition: dim.hpp:216
constexpr auto operator()(DimensionTypes &&... dimensions) const -> decltype(std::declval< accessor >()(std::forward< DimensionTypes >(dimensions)...))
Returns a value (or a sub-range) with the specified indexes.
Definition: range.hpp:334
Definition: range.hpp:683
constexpr T abs(const T &x)
Returns the absolute value of the object.
Definition: math.hpp:350
Definition: range.hpp:906
constexpr T imag(const T &)
Returns the imaginary part of the object.
Definition: math.hpp:425
Definition: range.hpp:657
std::size_t size_type
Integral type used for allocation quantities.
Definition: types.hpp:94
constexpr size_type length(size_type dimension) const
Returns the length of the specified dimension of the range.
Definition: range.hpp:387
Definition: range.hpp:890
Definition: range.hpp:659
Definition: range.hpp:677
The Ginkgo namespace.
Definition: abstract_factory.hpp:45
const range & operator=(const range &other) const
Assigns another range to this range.
Definition: range.hpp:373
Definition: range.hpp:916
Definition: range.hpp:918
Definition: range.hpp:671
constexpr T real(const T &x)
Returns the real part of the object.
Definition: math.hpp:409
Definition: range.hpp:667
constexpr const accessor * operator->() const noexcept
Returns a pointer to the accessor.
Definition: range.hpp:399
Definition: range.hpp:914
Definition: range.hpp:663
constexpr T min(const T &x, const T &y)
Returns the smaller of the arguments.
Definition: math.hpp:393
constexpr auto squared_norm(const T &x) -> decltype(real(conj(x) *x))
Returns the squared norm of the object.
Definition: math.hpp:456
Definition: range.hpp:673
Definition: range.hpp:908
Definition: range.hpp:926
Operations can be used to define functionalities whose implementations differ among devices...
Definition: executor.hpp:173
Accessor accessor
The type of the underlying accessor.
Definition: range.hpp:301
const range & operator=(const range< OtherAccessor > &other) const
Definition: range.hpp:352
T conj(const T &x)
Returns the conjugate of an object.
Definition: math.hpp:439
constexpr range(AccessorParams &&... params)
Creates a new range.
Definition: range.hpp:317
constexpr span(size_type point) noexcept
Creates a span representing a point point.
Definition: range.hpp:81
Definition: range.hpp:681
Definition: range.hpp:887
Definition: range.hpp:912
Definition: range.hpp:924
Definition: range.hpp:935
Definition: range.hpp:902
const size_type begin
Beginning of the span.
Definition: range.hpp:105
Definition: range.hpp:689
constexpr T max(const T &x, const T &y)
Returns the larger of the arguments.
Definition: math.hpp:373
Definition: range.hpp:888
A span is a lightweight structure used to create sub-ranges from other ranges.
Definition: range.hpp:73
A range is a multidimensional view of the memory.
Definition: range.hpp:296
Definition: range.hpp:897
Definition: range.hpp:920
constexpr dim< 2, DimensionType > transpose(const dim< 2, DimensionType > &dimensions) noexcept
Returns a dim<2> object with its dimensions swapped.
Definition: dim.hpp:234
constexpr T one()
Returns the multiplicative identity for T.
Definition: math.hpp:319