426template <
typename Func,
typename Evaluator>
427struct redux_impl<Func, Evaluator, LinearTraversal, CompleteUnrolling>
428 : redux_novec_linear_unroller<Func, Evaluator, 0, Evaluator::SizeAtCompileTime> {
429 using Base = redux_novec_linear_unroller<Func, Evaluator, 0, Evaluator::SizeAtCompileTime>;
430 using Scalar =
typename Evaluator::Scalar;
431 template <
typename XprType>
432 EIGEN_DEVICE_FUNC
static EIGEN_STRONG_INLINE Scalar run(
const Evaluator& eval,
const Func& func,
434 return Base::run(eval, func);
438template <
typename Func,
typename Evaluator>
439struct redux_impl<Func, Evaluator, LinearVectorizedTraversal, NoUnrolling> {
440 using Scalar =
typename Evaluator::Scalar;
441 using PacketScalar =
typename redux_traits<Func, Evaluator>::PacketType;
443 template <
typename XprType>
444 static Scalar run(
const Evaluator& eval,
const Func& func,
const XprType& xpr) {
445 const Index size = xpr.size();
447 constexpr Index packetSize = redux_traits<Func, Evaluator>::PacketSize;
448 constexpr int packetAlignment = unpacket_traits<PacketScalar>::alignment;
449 constexpr int alignment0 =
450 (bool(Evaluator::Flags & DirectAccessBit) && bool(packet_traits<Scalar>::AlignedOnScalar))
451 ?
int(packetAlignment)
453 constexpr int alignment = plain_enum_max(alignment0, Evaluator::Alignment);
454 const Index alignedStart = internal::first_default_aligned(xpr);
455 const Index alignedSize4 = numext::round_down(size - alignedStart, 4 * packetSize);
456 const Index alignedSize = numext::round_down(size - alignedStart, packetSize);
457 const Index alignedEnd4 = alignedStart + alignedSize4;
458 const Index alignedEnd = alignedStart + alignedSize;
460 constexpr Index maxSize = redux_max_size<XprType>::Size;
461 EIGEN_IF_CONSTEXPR (maxSize == Dynamic || maxSize >= packetSize) {
463 PacketScalar packet_res0 = eval.template packet<alignment, PacketScalar>(alignedStart);
464 EIGEN_IF_CONSTEXPR (maxSize == Dynamic || maxSize >= 4 * packetSize) {
467 PacketScalar packet_res1 = eval.template packet<alignment, PacketScalar>(alignedStart + packetSize);
468 PacketScalar packet_res2 = eval.template packet<alignment, PacketScalar>(alignedStart + 2 * packetSize);
469 PacketScalar packet_res3 = eval.template packet<alignment, PacketScalar>(alignedStart + 3 * packetSize);
470 for (Index index = alignedStart + 4 * packetSize; index < alignedEnd4; index += 4 * packetSize) {
471 packet_res0 = func.packetOp(packet_res0, eval.template packet<alignment, PacketScalar>(index));
473 func.packetOp(packet_res1, eval.template packet<alignment, PacketScalar>(index + packetSize));
475 func.packetOp(packet_res2, eval.template packet<alignment, PacketScalar>(index + 2 * packetSize));
477 func.packetOp(packet_res3, eval.template packet<alignment, PacketScalar>(index + 3 * packetSize));
482 const Index remSize = alignedSize - alignedSize4;
483 if (remSize >= packetSize) {
484 packet_res0 = func.packetOp(packet_res0, eval.template packet<alignment, PacketScalar>(alignedEnd4));
485 if (remSize >= 2 * packetSize) {
487 func.packetOp(packet_res1, eval.template packet<alignment, PacketScalar>(alignedEnd4 + packetSize));
488 if (remSize == 3 * packetSize)
489 packet_res2 = func.packetOp(
490 packet_res2, eval.template packet<alignment, PacketScalar>(alignedEnd4 + 2 * packetSize));
495 packet_res0 = func.packetOp(packet_res0, packet_res1);
496 packet_res2 = func.packetOp(packet_res2, packet_res3);
497 packet_res0 = func.packetOp(packet_res0, packet_res2);
500 EIGEN_IF_CONSTEXPR (maxSize == Dynamic || maxSize >= 2 * packetSize) {
501 if (!alignedSize4 && alignedSize > packetSize) {
504 func.packetOp(packet_res0, eval.template packet<alignment, PacketScalar>(alignedStart + packetSize));
505 EIGEN_IF_CONSTEXPR (maxSize == Dynamic || maxSize >= 3 * packetSize) {
506 if (alignedSize > 2 * packetSize)
507 packet_res0 = func.packetOp(
508 packet_res0, eval.template packet<alignment, PacketScalar>(alignedStart + 2 * packetSize));
512 res = func.predux(packet_res0);
514 for (Index index = 0; index < alignedStart; ++index) res = func(res, eval.coeff(index));
516 for (Index index = alignedEnd; index < size; ++index) res = func(res, eval.coeff(index));
522 for (Index index = 1; index < size; ++index) res = func(res, eval.coeff(index));
528template <
typename Func,
typename Evaluator,
int Unrolling>
529struct redux_impl<Func, Evaluator, SliceVectorizedTraversal, Unrolling> {
530 using Scalar =
typename Evaluator::Scalar;
531 using PacketType =
typename redux_traits<Func, Evaluator>::PacketType;
533 static constexpr Index PacketSize = redux_traits<Func, Evaluator>::PacketSize;
535 EIGEN_DEVICE_FUNC
static EIGEN_STRONG_INLINE PacketType packetAt(
const Evaluator& eval, Index j, Index i) {
536 return eval.template packetByOuterInner<Unaligned, PacketType>(j, i);
539 template <
typename XprType>
540 EIGEN_DEVICE_FUNC
static Scalar run(
const Evaluator& eval,
const Func& func,
const XprType& xpr) {
541 eigen_assert(xpr.rows() > 0 && xpr.cols() > 0 &&
"you are using an empty matrix");
542 const Index innerSize = xpr.innerSize();
543 const Index outerSize = xpr.outerSize();
544 const Index packetedInnerSize = numext::round_down(innerSize, PacketSize);
545 const Index quadInnerSize = numext::round_down(innerSize, 4 * PacketSize);
547 if (packetedInnerSize) {
550 PacketType packet_res0 = packetAt(eval, 0, 0);
553 PacketType packet_res1 = packetAt(eval, 0, PacketSize);
554 PacketType packet_res2 = packetAt(eval, 0, 2 * PacketSize);
555 PacketType packet_res3 = packetAt(eval, 0, 3 * PacketSize);
558 const Index remSize = packetedInnerSize - quadInnerSize;
559 for (Index j = 0; j < outerSize; ++j) {
560 for (Index i = (j == 0) ? 4 * PacketSize : 0; i < quadInnerSize; i += 4 * PacketSize) {
561 packet_res0 = func.packetOp(packet_res0, packetAt(eval, j, i));
562 packet_res1 = func.packetOp(packet_res1, packetAt(eval, j, i + PacketSize));
563 packet_res2 = func.packetOp(packet_res2, packetAt(eval, j, i + 2 * PacketSize));
564 packet_res3 = func.packetOp(packet_res3, packetAt(eval, j, i + 3 * PacketSize));
568 if (remSize >= PacketSize) {
569 packet_res0 = func.packetOp(packet_res0, packetAt(eval, j, quadInnerSize));
570 if (remSize >= 2 * PacketSize) {
571 packet_res1 = func.packetOp(packet_res1, packetAt(eval, j, quadInnerSize + PacketSize));
572 if (remSize == 3 * PacketSize)
573 packet_res2 = func.packetOp(packet_res2, packetAt(eval, j, quadInnerSize + 2 * PacketSize));
578 packet_res0 = func.packetOp(packet_res0, packet_res1);
579 packet_res2 = func.packetOp(packet_res2, packet_res3);
580 packet_res0 = func.packetOp(packet_res0, packet_res2);
581 }
else if (outerSize >= 4) {
584 PacketType packet_res1 = packetAt(eval, 1, 0);
585 PacketType packet_res2 = packetAt(eval, 2, 0);
586 PacketType packet_res3 = packetAt(eval, 3, 0);
587 for (Index i = PacketSize; i < packetedInnerSize; i += PacketSize) {
588 packet_res0 = func.packetOp(packet_res0, packetAt(eval, 0, i));
589 packet_res1 = func.packetOp(packet_res1, packetAt(eval, 1, i));
590 packet_res2 = func.packetOp(packet_res2, packetAt(eval, 2, i));
591 packet_res3 = func.packetOp(packet_res3, packetAt(eval, 3, i));
595 const Index quadOuterSize = numext::round_down(outerSize, 4);
596 for (Index j = 4; j < quadOuterSize; j += 4)
597 for (Index i = 0; i < packetedInnerSize; i += PacketSize) {
598 packet_res0 = func.packetOp(packet_res0, packetAt(eval, j, i));
599 packet_res1 = func.packetOp(packet_res1, packetAt(eval, j + 1, i));
600 packet_res2 = func.packetOp(packet_res2, packetAt(eval, j + 2, i));
601 packet_res3 = func.packetOp(packet_res3, packetAt(eval, j + 3, i));
603 for (Index j = quadOuterSize; j < outerSize; ++j)
604 for (Index i = 0; i < packetedInnerSize; i += PacketSize)
605 packet_res0 = func.packetOp(packet_res0, packetAt(eval, j, i));
607 packet_res0 = func.packetOp(packet_res0, packet_res1);
608 packet_res2 = func.packetOp(packet_res2, packet_res3);
609 packet_res0 = func.packetOp(packet_res0, packet_res2);
612 for (Index j = 0; j < outerSize; ++j)
613 for (Index i = (j == 0 ? PacketSize : 0); i < packetedInnerSize; i += PacketSize)
614 packet_res0 = func.packetOp(packet_res0, packetAt(eval, j, i));
617 res = func.predux(packet_res0);
618 for (Index j = 0; j < outerSize; ++j)
619 for (Index i = packetedInnerSize; i < innerSize; ++i) res = func(res, eval.coeffByOuterInner(j, i));
623 res = redux_impl<Func, Evaluator, DefaultTraversal, NoUnrolling>::run(eval, func, xpr);
630template <
typename Func,
typename Evaluator>
631struct redux_impl<Func, Evaluator, LinearVectorizedTraversal, CompleteUnrolling> {
632 using Scalar =
typename Evaluator::Scalar;
634 using PacketType =
typename redux_traits<Func, Evaluator>::PacketType;
635 static constexpr Index PacketSize = redux_traits<Func, Evaluator>::PacketSize;
636 static constexpr Index Size = Evaluator::SizeAtCompileTime;
637 static constexpr Index VectorizedSize = (int(Size) / int(PacketSize)) *
int(PacketSize);
639 template <
typename XprType>
640 EIGEN_DEVICE_FUNC
static EIGEN_STRONG_INLINE Scalar run(
const Evaluator& eval,
const Func& func,
const XprType& xpr) {
641 EIGEN_ONLY_USED_FOR_DEBUG(xpr);
642 eigen_assert(xpr.rows() > 0 && xpr.cols() > 0 &&
"you are using an empty matrix");
643 if (VectorizedSize > 0) {
644 Scalar res = func.predux(
645 redux_vec_linear_unroller<Func, Evaluator, 0, Size / PacketSize>::template run<PacketType>(eval, func));
646 if (VectorizedSize != Size)
648 res, redux_novec_linear_unroller<Func, Evaluator, VectorizedSize, Size - VectorizedSize>::run(eval, func));
651 return redux_novec_linear_unroller<Func, Evaluator, 0, Size>::run(eval, func);
657template <
typename XprType_>
658class redux_evaluator :
public internal::evaluator<const XprType_> {
659 using Base = internal::evaluator<const XprType_>;
662 using XprType = XprType_;
663 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
explicit redux_evaluator(
const XprType& xpr) : Base(xpr) {}
665 using Scalar =
typename XprType::Scalar;
666 using CoeffReturnType =
typename XprType::CoeffReturnType;
667 using PacketScalar =
typename XprType::PacketScalar;
670 MaxRowsAtCompileTime = XprType::MaxRowsAtCompileTime,
671 MaxColsAtCompileTime = XprType::MaxColsAtCompileTime,
674 Flags = Base::Flags & ~DirectAccessBit,
675 IsRowMajor = XprType::IsRowMajor,
676 SizeAtCompileTime = XprType::SizeAtCompileTime,
677 InnerSizeAtCompileTime = XprType::InnerSizeAtCompileTime
680 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeffByOuterInner(Index outer, Index inner)
const {
681 return Base::coeff(IsRowMajor ? outer : inner, IsRowMajor ? inner : outer);
684 template <
int LoadMode,
typename PacketType>
685 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packetByOuterInner(Index outer, Index inner)
const {
686 return Base::template packet<LoadMode, PacketType>(IsRowMajor ? outer : inner, IsRowMajor ? inner : outer);
689 template <
int LoadMode,
typename PacketType>
690 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packetSegmentByOuterInner(Index outer, Index inner, Index begin,
692 return Base::template packetSegment<LoadMode, PacketType>(IsRowMajor ? outer : inner, IsRowMajor ? inner : outer,
704template <
typename Func,
typename Evaluator>
705struct redux_has_runtime_unit_stride_path {
706 using XprType =
typename Evaluator::XprType;
707 using Scalar =
typename Evaluator::Scalar;
708 static constexpr bool value = bool(traits<XprType>::Flags & DirectAccessBit) &&
709 bool(functor_traits<Func>::PacketAccess) && bool(packet_traits<Scalar>::Vectorizable) &&
710 (int(inner_stride_at_compile_time<XprType>::value) != 1);
713template <
typename Func,
typename Evaluator,
typename XprType,
714 bool = redux_has_runtime_unit_stride_path<Func, Evaluator>::value>
715struct redux_dispatch {
716 static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
typename Evaluator::Scalar run(
const Evaluator& thisEval,
717 const Func& func,
const XprType& xpr) {
718 return redux_impl<Func, Evaluator>::run(thisEval, func, xpr);
727template <
typename Func,
typename Evaluator,
typename XprType>
728struct redux_dispatch<Func, Evaluator, XprType, true> {
729 using Scalar =
typename Evaluator::Scalar;
730 static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar run(
const Evaluator& thisEval,
const Func& func,
731 const XprType& xpr) {
732 if (xpr.innerStride() == 1 && (xpr.outerSize() == 1 || xpr.outerStride() == xpr.innerSize())) {
733 using PlainVector = Matrix<Scalar, Dynamic, 1>;
734 using MapType = Map<const PlainVector, Evaluator::Alignment>;
735 MapType contiguous(xpr.data(), xpr.size());
736 redux_evaluator<MapType> mapEval(contiguous);
737 return redux_impl<Func, redux_evaluator<MapType>>::run(mapEval, func, contiguous);
739 return redux_impl<Func, Evaluator>::run(thisEval, func, xpr);
761template <
typename Derived>
762template <
typename Func>
763EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
typename internal::traits<Derived>::Scalar DenseBase<Derived>::redux(
764 const Func& func)
const {
765 eigen_assert(this->rows() > 0 && this->cols() > 0 &&
"you are using an empty matrix");
767 using ThisEvaluator =
typename internal::redux_evaluator<Derived>;
768 ThisEvaluator thisEval(derived());
774 return internal::redux_dispatch<Func, ThisEvaluator, Derived>::run(thisEval, func, derived());
784template <
typename Derived>
785template <
int NaNPropagation>
787 return derived().redux(Eigen::internal::scalar_min_op<Scalar, Scalar, NaNPropagation>());
797template <
typename Derived>
798template <
int NaNPropagation>
800 return derived().redux(Eigen::internal::scalar_max_op<Scalar, Scalar, NaNPropagation>());