blob: 6d3022646b25c60ceaca07b7c4fdaee0346484a2 [file]
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// SPDX-FileCopyrightText: The Eigen Authors
// SPDX-License-Identifier: MPL-2.0
#ifndef EIGEN_PREDICATOR_H
#define EIGEN_PREDICATOR_H
// IWYU pragma: private
#include "./InternalHeaderCheck.h"
namespace Eigen {
namespace internal {
// Predicate reductions all_of and any_of. A predicate tests a scalar with operator() and a packet with
// packetOp, which returns a truth packet: each lane is zero where the predicate is false and, where it is true, the
// lane mask pcmp_* produces (all ones, or one for bool packets). Truth packets combine with pand and por, so the
// traversals below reduce and branch once per block of packets rather than once per packet. Results do not depend on
// the grouping, but a short-circuit may read past the deciding coefficient, up to the end of its block.
template <typename Scalar>
struct nonzero_predicate {
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool operator()(const Scalar& x) const { return x != Scalar(0); }
template <typename Packet>
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& x) const {
return pandnot(ptrue(x), pcmp_eq(x, pzero(x)));
}
};
template <typename Scalar>
struct functor_traits<nonzero_predicate<Scalar>> {
static constexpr bool PacketAccess = packet_traits<Scalar>::HasCmp;
// Accepts that ARMv7 NEON reads a subnormal float as zero: packets compare there already, and grouped scalar tests
// may be vectorized onto it. Testing float one at a time instead cost 0.7-0.85x at sizes with a scalar tail on
// Cortex-A72.
static constexpr bool GroupScalars = true;
};
template <typename Scalar>
struct isfinite_predicate {
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool operator()(const Scalar& x) const { return (numext::isfinite)(x); }
template <typename Packet>
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& x) const {
return pisfinite(x);
}
};
template <typename Scalar>
struct functor_traits<isfinite_predicate<Scalar>> {
static constexpr bool PacketAccess = packet_traits<Scalar>::HasCmp;
static constexpr bool GroupScalars = true;
};
// Separate specializations keep custom scalars that support only one of isApprox and isMuchSmallerThan compiling.
template <typename Scalar, bool Approximate>
struct fuzzy_constant_predicate {
using RealScalar = typename NumTraits<Scalar>::Real;
Scalar value;
RealScalar precision;
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool operator()(const Scalar& x) const {
return internal::isApprox(x, value, precision);
}
// Requires 0 <= precision <= 1 and a finite value. Then min(|x|, |v|) p = min(|x| p, |v| p) exactly, and |x| p is
// x copysign(p, v) where x has the sign of v; where it does not, |x - v| >= max(|x|, |v|) > p min(|x|, |v|) unless
// x = v = 0, and x copysign(p, v) <= 0 rejects it as well.
template <typename Packet>
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& x) const {
const Packet bound = pset1<Packet>(numext::abs(value) * precision);
const Packet scale = pset1<Packet>(numext::copysign(precision, value));
return pcmp_le(pabs(psub(x, pset1<Packet>(value))), pmin(pmul(x, scale), bound));
}
EIGEN_DEVICE_FUNC bool packetOpApplies() const {
return precision >= RealScalar(0) && precision <= RealScalar(1) && (numext::isfinite)(value);
}
};
template <typename Scalar>
struct fuzzy_constant_predicate<Scalar, false> {
Scalar value;
typename NumTraits<Scalar>::Real precision;
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool operator()(const Scalar& x) const {
return internal::isMuchSmallerThan(x, Scalar(1), precision);
}
template <typename Packet>
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetOp(const Packet& x) const {
return pcmp_le(pabs(x), pset1<Packet>(precision));
}
};
template <typename Scalar, bool Approximate>
struct functor_traits<fuzzy_constant_predicate<Scalar, Approximate>> {
// ARMv7 NEON flushes subnormal float operands and results; scalar VFP does not.
// Explicitly flushing would change exact-zero checks; normal operands can also have a subnormal difference.
static constexpr bool PacketAccess =
(std::is_same<Scalar, float>::value || std::is_same<Scalar, double>::value) &&
!(EIGEN_ARCH_ARM && std::is_same<Scalar, float>::value) && packet_traits<Scalar>::HasAbs &&
packet_traits<Scalar>::HasCmp &&
(!Approximate ||
(packet_traits<Scalar>::HasSub && packet_traits<Scalar>::HasMin && packet_traits<Scalar>::HasMul));
// Grouped scalar compares may be vectorized onto the unit PacketAccess excludes.
static constexpr bool GroupScalars = PacketAccess;
// The approximate test saturates the vector units, so larger blocks barely speed up full scans but read further
// past a deciding coefficient: 2 packets per exit is never slower than master's exit per packet.
static constexpr int BlockPackets = Approximate ? 2 : 8;
};
// A predicate's scalar test alone, tested one coefficient at a time.
template <typename Predicate>
struct scalar_predicate {
Predicate pred;
template <typename Scalar>
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool operator()(const Scalar& x) const {
return pred(x);
}
};
template <typename Predicate>
struct functor_traits<scalar_predicate<Predicate>> {
static constexpr bool PacketAccess = false;
};
// Searches for a coefficient on which the predicate is Target: any_of searches for true, all_of for false. Packets
// combine truth masks and test the combined mask; scalars search for a true test_scalar by OR, which vectorizes
// better than an AND of test results.
struct packet_predicate {
template <typename Predicate, typename Packet>
static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet apply(const Predicate& pred, const Packet& x) {
return pred.packetOp(x);
}
};
template <bool Target>
struct predicate_search;
template <>
struct predicate_search<true> : packet_predicate {
template <typename Packet>
static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE Packet combine(const Packet& a, const Packet& b) {
return por(a, b);
}
template <typename Packet>
static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool found(const Packet& m) {
return predux_any(m);
}
// Only the lanes set in a lane mask, as for a segment.
template <typename Packet>
static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool found_in(const Packet& m, const Packet& lanes) {
return predux_any(pand(m, lanes));
}
template <typename Predicate, typename Scalar>
static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool test_scalar(const Predicate& pred, const Scalar& x) {
return pred(x);
}
};
template <>
struct predicate_search<false> : packet_predicate {
template <typename Packet>
static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE Packet combine(const Packet& a, const Packet& b) {
return pand(a, b);
}
// pandnot rather than pnot, which some targets implement only bytewise.
template <typename Packet>
static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool found(const Packet& m) {
return predux_any(pandnot(ptrue(m), m));
}
template <typename Packet>
static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool found_in(const Packet& m, const Packet& lanes) {
return predux_any(pandnot(lanes, m));
}
template <typename Predicate, typename Scalar>
static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool test_scalar(const Predicate& pred, const Scalar& x) {
return !pred(x);
}
};
// all_of(nonzero) searches for zero lanes, x == 0 being the exact complement of x != 0: a single compare per packet
// and no complement of the combined mask, which some compilers otherwise lower through narrowing and widening.
// Scalars still test the predicate: a coefficient is found where it is false.
struct zero_lane_search : predicate_search<true> {
template <typename Predicate, typename Packet>
static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet apply(const Predicate&, const Packet& x) {
return pcmp_eq(x, pzero(x));
}
template <typename Predicate, typename Scalar>
static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool test_scalar(const Predicate& pred, const Scalar& x) {
return !pred(x);
}
};
// any_of on bool lanes reduces them directly, treating every nonzero byte as true as the scalar reduction does.
struct bool_lane_search : predicate_search<true> {
template <typename Predicate, typename Packet>
static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet apply(const Predicate&, const Packet& x) {
return x;
}
};
// any_of(nonzero) on integer lanes ORs the coefficients themselves and compares the OR with zero once per block: it
// is zero exactly where every coefficient is. Floating-point lanes keep the compare per packet: their OR can be a
// signaling NaN, which a floating-point compare would flag as an invalid operation.
struct or_lane_search : predicate_search<true> {
template <typename Predicate, typename Packet>
static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet apply(const Predicate&, const Packet& x) {
return x;
}
template <typename Packet>
static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool found(const Packet& m) {
return predux_any(pandnot(ptrue(m), pcmp_eq(m, pzero(m))));
}
template <typename Packet>
static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool found_in(const Packet& m, const Packet& lanes) {
return found(pand(m, lanes));
}
};
template <bool Target, typename Predicate>
struct predicate_search_for {
using type = predicate_search<Target>;
};
template <typename Scalar>
struct predicate_search_for<false, nonzero_predicate<Scalar>> {
using type = zero_lane_search;
};
template <typename Scalar>
struct predicate_search_for<true, nonzero_predicate<Scalar>> {
using type = std::conditional_t<std::is_integral<Scalar>::value, or_lane_search, predicate_search<true>>;
};
template <>
struct predicate_search_for<true, nonzero_predicate<bool>> {
using type = bool_lane_search;
};
// Coefficient access along one inner vector, or along the whole expression with linear access.
template <typename Evaluator, bool Linear = Evaluator::LinearAccess>
struct predicate_segment {
using Scalar = typename Evaluator::Scalar;
static constexpr bool FixedSize = Evaluator::RowsAtCompileTime > 0 && Evaluator::ColsAtCompileTime > 0;
static constexpr bool PlainLoad = int(Evaluator::CoeffReadCost) <= int(NumTraits<Scalar>::ReadCost);
const Evaluator& eval;
Index length;
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE predicate_segment(const Evaluator& evaluator, Index, Index size)
: eval(evaluator), length(size) {}
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index size() const { return length; }
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE typename Evaluator::CoeffReturnType coeff(Index i) const {
return eval.coeff(i);
}
template <typename Packet>
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packet(Index i) const {
return eval.template packet<Packet>(i);
}
template <typename Packet>
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetSegment(Index i, Index count) const {
return eval.template packetSegment<Packet>(i, 0, count);
}
};
template <typename Evaluator>
struct predicate_segment<Evaluator, false> {
using Scalar = typename Evaluator::Scalar;
static constexpr bool FixedSize =
(Evaluator::IsRowMajor ? Evaluator::ColsAtCompileTime : Evaluator::RowsAtCompileTime) > 0;
static constexpr bool PlainLoad = int(Evaluator::CoeffReadCost) <= int(NumTraits<Scalar>::ReadCost);
const Evaluator& eval;
Index outer;
Index length;
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE predicate_segment(const Evaluator& evaluator, Index j, Index size)
: eval(evaluator), outer(j), length(size) {}
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index size() const { return length; }
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE typename Evaluator::CoeffReturnType coeff(Index i) const {
return Evaluator::IsRowMajor ? eval.coeff(outer, i) : eval.coeff(i, outer);
}
template <typename Packet>
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packet(Index i) const {
return Evaluator::IsRowMajor ? eval.template packet<Packet>(outer, i) : eval.template packet<Packet>(i, outer);
}
template <typename Packet>
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packetSegment(Index i, Index count) const {
return Evaluator::IsRowMajor ? eval.template packetSegment<Packet>(outer, i, 0, count)
: eval.template packetSegment<Packet>(i, outer, 0, count);
}
};
// Whether a predicate's scalar tests may be grouped; predicates that do not say are tested one at a time.
template <typename Predicate, typename = void>
struct predicate_groups_scalars : std::false_type {};
template <typename Predicate>
struct predicate_groups_scalars<Predicate, void_t<decltype(functor_traits<Predicate>::GroupScalars)>>
: bool_constant<static_cast<bool>(functor_traits<Predicate>::GroupScalars)> {};
// Packets tested between exits on the long path; predicates that do not say test blocks of 8.
template <typename Predicate, typename = void>
struct predicate_block_packets : std::integral_constant<int, 8> {};
template <typename Predicate>
struct predicate_block_packets<Predicate, void_t<decltype(functor_traits<Predicate>::BlockPackets)>>
: std::integral_constant<int, functor_traits<Predicate>::BlockPackets> {};
// Scalar searches OR their tests without a branch per test; spelling a | b on the calls directly draws clang's
// -Wbitwise-instead-of-logical.
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool predicate_or(bool a, bool b) { return a | b; }
// At most three coefficients from i on, as straight-line tests.
template <typename Search, typename Segment, typename Predicate>
EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool predicate_search_upto3(const Segment& seg, Index i, Predicate pred) {
const Index size = seg.size();
if (i == size) return false;
bool b = Search::test_scalar(pred, seg.coeff(i));
if (i + 1 < size) b = predicate_or(b, Search::test_scalar(pred, seg.coeff(i + 1)));
if (i + 2 < size) b = predicate_or(b, Search::test_scalar(pred, seg.coeff(i + 2)));
return b;
}
template <typename Search, typename Segment, typename Predicate>
EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool predicate_search_scalar(const Segment& seg, Index i, Predicate pred) {
const Index size = seg.size();
for (; i + 3 < size; i += 4) {
bool b = predicate_or(
predicate_or(Search::test_scalar(pred, seg.coeff(i)), Search::test_scalar(pred, seg.coeff(i + 1))),
predicate_or(Search::test_scalar(pred, seg.coeff(i + 2)), Search::test_scalar(pred, seg.coeff(i + 3))));
if EIGEN_PREDICT_FALSE (b) return true;
}
return predicate_search_upto3<Search>(seg, i, pred);
}
// One coefficient at a time with an exit after each, a shape compilers do not vectorize.
template <typename Search, typename Segment, typename Predicate>
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool predicate_search_sequential(const Segment& seg, Index i, Predicate pred) {
for (const Index size = seg.size(); i < size; ++i)
if (Search::test_scalar(pred, seg.coeff(i))) return true;
return false;
}
// Scalar tests from i on: grouped only where the predicate allows it, since grouped scalar tests may be vectorized
// onto the unit a predicate excludes (ARMv7 NEON, which flushes subnormals, turns grouped float compares into vceq).
template <typename Search, typename Segment, typename Predicate>
EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool predicate_search_tail(const Segment& seg, Index i, Predicate pred) {
if (predicate_groups_scalars<Predicate>::value) return predicate_search_scalar<Search>(seg, i, pred);
return predicate_search_sequential<Search>(seg, i, pred);
}
// Scalar blocks OR their tests into an unsigned integer as wide as the scalar. gcc vectorizes that reduction but not an
// OR of bools, and a wider accumulator widens every test.
template <typename Scalar, typename Unsigned = typename numext::get_integer_by_size<sizeof(Scalar)>::unsigned_type>
struct predicate_block_accumulator {
using type = Unsigned;
};
template <typename Scalar>
struct predicate_block_accumulator<Scalar, void> {
using type = bool;
};
template <typename Search, typename Packet, bool Vectorize>
struct predicate_search_segment {
static constexpr Index ShortSize = 0;
// Without packets, blocks of 64 tests without an exit, which compilers vectorize, and one exit check per block;
// starting each block from the identity keeps its trip count regular once inlined. Only where the predicate allows
// grouped tests, as for predicate_search_tail.
template <typename Segment, typename Predicate>
static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool run(const Segment& seg, Predicate pred) {
if (!predicate_groups_scalars<Predicate>::value) return predicate_search_sequential<Search>(seg, 0, pred);
const Index size = seg.size();
// The shortest segments first, so they skip the block and group guards.
if (EIGEN_PREDICT_FALSE(size < 4)) return predicate_search_upto3<Search>(seg, 0, pred);
Index i = 0;
using Acc = typename predicate_block_accumulator<typename Segment::Scalar>::type;
for (; i + 64 <= size; i += 64) {
Acc b = 0;
for (Index k = 0; k < 64; ++k) b |= Acc(Search::test_scalar(pred, seg.coeff(i + k)));
if EIGEN_PREDICT_FALSE (b != Acc(0)) return true;
}
return predicate_search_scalar<Search>(seg, i, pred);
}
template <typename Segment, typename Predicate>
static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool run_short(const Segment& seg, Predicate pred) {
return run(seg, pred);
}
};
// first(count) is a packet whose first count lanes are all ones and whose other lanes are zero. table is one packet of
// 0xff bytes followed by one packet of zero bytes; an unaligned load that starts Size - count lanes into it reads count
// lanes of ones, then zeros. Bytes rather than Scalars, so that one table serves lanes of any width.
template <typename Packet, typename Bytes = std::make_index_sequence<2 * sizeof(Packet)>>
struct predicate_lane_table;
template <typename Packet, std::size_t... Byte>
struct predicate_lane_table<Packet, std::index_sequence<Byte...>> {
using Scalar = typename unpacket_traits<Packet>::type;
static constexpr Index Size = unpacket_traits<Packet>::size;
// Aligned to the packet, so that every load start is aligned to its Scalar.
alignas(sizeof(Packet)) static constexpr unsigned char table[2 * sizeof(Packet)] = {
(Byte < sizeof(Packet) ? 0xff : 0)...};
static EIGEN_STRONG_INLINE Packet first(Index count) {
return ploadu<Packet>(reinterpret_cast<const Scalar*>(table + (Size - count) * sizeof(Scalar)));
}
};
#if EIGEN_COMP_CXXVER < 17
template <typename Packet, std::size_t... Byte>
alignas(sizeof(Packet)) constexpr unsigned char predicate_lane_table<Packet, std::index_sequence<Byte...>>::table[];
#endif
template <typename Search, typename Packet>
struct predicate_search_segment<Search, Packet, true> {
// One helper per packet, taking its operands by reference and returning the mask by value: if the early inliner
// leaves it as a call, the caller needs no addressable packet temporaries.
template <typename Segment, typename Predicate>
static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet test(const Segment& seg, Index i, const Predicate& pred) {
return Search::apply(pred, seg.template packet<Packet>(i));
}
static constexpr Index PacketSize = unpacket_traits<Packet>::size;
// Segments shorter than ShortSize take run_short.
static constexpr Index ShortSize = 4 * PacketSize;
// Up to three packets (plus a ragged tail), the common short call: test them directly.
template <typename Segment, typename Predicate>
static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool run_short(const Segment& seg, Predicate pred) {
const Index size = seg.size();
Index i = 0;
if (PacketSize <= size) {
if (size < 2 * PacketSize) {
if (Search::found(test(seg, 0, pred))) return true;
i = PacketSize;
} else if (size < 3 * PacketSize) {
if (Search::found(Search::combine(test(seg, 0, pred), test(seg, PacketSize, pred)))) return true;
i = 2 * PacketSize;
} else {
if (Search::found(Search::combine(Search::combine(test(seg, 0, pred), test(seg, PacketSize, pred)),
test(seg, 2 * PacketSize, pred))))
return true;
i = 3 * PacketSize;
}
if (EIGEN_PREDICT_TRUE(i == size)) return false;
} else if (has_packet_segment<Packet>::value && Segment::PlainLoad && (Segment::FixedSize || size >= 4)) {
return run_partial(seg, pred, bool_constant<has_packet_segment<Packet>::value>());
} else if (size < 4 && predicate_groups_scalars<Predicate>::value) {
// Shorter than one packet and than a group of four: only these sizes reach this check.
return predicate_search_upto3<Search>(seg, 0, pred);
}
return predicate_search_tail<Search>(seg, i, pred);
}
// A segment shorter than one packet, of a compile-time length or of at least four coefficients: one masked load,
// with the lanes past the segment masked off. Shorter runtime lengths keep their scalar tests, which are faster than
// building the masks; a compile-time length folds them. Only for a segment that loads its coefficients
// (Segment::PlainLoad): an expression computes on the zeros past the segment too, and 0 / 0 there would raise
// FE_INVALID, which the scalar tests of the same coefficients do not.
template <typename Segment, typename Predicate>
static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool run_partial(const Segment& seg, Predicate pred, std::true_type) {
const Index size = seg.size();
return Search::found_in(Search::apply(pred, seg.template packetSegment<Packet>(0, size)),
predicate_lane_table<Packet>::first(size));
}
template <typename Segment, typename Predicate>
static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool run_partial(const Segment& seg, Predicate pred, std::false_type) {
return predicate_search_tail<Search>(seg, 0, pred);
}
template <int Block, typename Segment, typename Predicate>
static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool run_blocks(const Segment& seg, Predicate pred) {
const Index size = seg.size();
Index i = 0;
for (; i + Block * PacketSize <= size; i += Block * PacketSize) {
Packet m = test(seg, i, pred);
for (int k = 1; k < Block; ++k) m = Search::combine(m, test(seg, i + k * PacketSize, pred));
if EIGEN_PREDICT_FALSE (Search::found(m)) return true;
}
if (Block > 1 && i + PacketSize <= size) {
Packet m = test(seg, i, pred);
for (i += PacketSize; i + PacketSize <= size; i += PacketSize) m = Search::combine(m, test(seg, i, pred));
if (Search::found(m)) return true;
}
if (EIGEN_PREDICT_TRUE(i == size)) return false;
return predicate_search_tail<Search>(seg, i, pred);
}
template <typename Segment, typename Predicate>
static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool run(const Segment& seg, Predicate pred) {
const Index size = seg.size();
if (size < ShortSize) return run_short(seg, pred);
EIGEN_IF_CONSTEXPR (predicate_block_packets<Predicate>::value < 8) {
return run_blocks<predicate_block_packets<Predicate>::value>(seg, pred);
}
Index i = 0;
// Longer segments: the block loop is laid out off the fall-through path.
if (EIGEN_PREDICT_FALSE(8 * PacketSize <= size)) {
do {
Packet m = Search::combine(
Search::combine(Search::combine(test(seg, i + 0 * PacketSize, pred), test(seg, i + 1 * PacketSize, pred)),
Search::combine(test(seg, i + 2 * PacketSize, pred), test(seg, i + 3 * PacketSize, pred))),
Search::combine(Search::combine(test(seg, i + 4 * PacketSize, pred), test(seg, i + 5 * PacketSize, pred)),
Search::combine(test(seg, i + 6 * PacketSize, pred), test(seg, i + 7 * PacketSize, pred))));
if EIGEN_PREDICT_FALSE (Search::found(m)) return true;
i += 8 * PacketSize;
} while (i + 8 * PacketSize <= size);
}
if (i + 4 * PacketSize <= size) {
Packet m =
Search::combine(Search::combine(test(seg, i + 0 * PacketSize, pred), test(seg, i + 1 * PacketSize, pred)),
Search::combine(test(seg, i + 2 * PacketSize, pred), test(seg, i + 3 * PacketSize, pred)));
if (Search::found(m)) return true;
i += 4 * PacketSize;
}
if (i + PacketSize <= size) {
Packet m = test(seg, i, pred);
for (i += PacketSize; i + PacketSize <= size; i += PacketSize) m = Search::combine(m, test(seg, i, pred));
if (Search::found(m)) return true;
}
if (EIGEN_PREDICT_TRUE(i == size)) return false;
return predicate_search_tail<Search>(seg, i, pred);
}
};
template <typename Derived, typename Predicate>
struct predicate_reduction {
using Evaluator = visitor_evaluator<Derived>;
using Scalar = typename Derived::Scalar;
static constexpr bool LinearAccess = Evaluator::LinearAccess;
// A segment's compile-time length, so a short fixed-size segment uses a packet that fits it, as assignment does.
static constexpr int SegmentSizeAtCompileTime =
LinearAccess ? int(Derived::SizeAtCompileTime)
: int(Evaluator::IsRowMajor ? Derived::ColsAtCompileTime : Derived::RowsAtCompileTime);
using Packet = typename find_largest_packet<Scalar, SegmentSizeAtCompileTime>::type;
static constexpr bool Vectorize = Evaluator::PacketAccess && packet_traits<Scalar>::Vectorizable &&
(unpacket_traits<Packet>::size > 1) &&
static_cast<bool>(functor_traits<Predicate>::PacketAccess);
using Segment = predicate_segment<Evaluator>;
template <bool Target>
static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool search(const Derived& xpr, Predicate pred) {
using impl = predicate_search_segment<typename predicate_search_for<Target, Predicate>::type, Packet, Vectorize>;
Evaluator eval(xpr);
EIGEN_IF_CONSTEXPR (LinearAccess) {
return impl::run(Segment(eval, 0, eval.size()), pred);
} else {
// The inner size is read once: through the evaluator's reference to the expression, compilers reload it for
// every inner vector.
const Index innerSize = Evaluator::IsRowMajor ? eval.cols() : eval.rows();
const Index outerSize = Evaluator::IsRowMajor ? eval.rows() : eval.cols();
// Choosing the segment path once keeps the length dispatch out of the loop over short inner vectors.
if (innerSize < impl::ShortSize) {
for (Index j = 0; j < outerSize; ++j)
if (impl::run_short(Segment(eval, j, innerSize), pred)) return true;
} else {
for (Index j = 0; j < outerSize; ++j)
if (impl::run(Segment(eval, j, innerSize), pred)) return true;
}
return false;
}
}
};
/** \internal \returns true if \a pred holds for every coefficient of \a xpr. */
template <typename Derived, typename Predicate>
EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool all_of(const Derived& xpr, const Predicate& pred) {
return !predicate_reduction<Derived, Predicate>::template search<false>(xpr, pred);
}
/** \internal \returns true if \a pred holds for some coefficient of \a xpr. */
template <typename Derived, typename Predicate>
EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool any_of(const Derived& xpr, const Predicate& pred) {
return predicate_reduction<Derived, Predicate>::template search<true>(xpr, pred);
}
// The packet test of fuzzy_constant_predicate holds only where packetOpApplies; elsewhere it tests scalars.
template <typename Derived, typename Predicate>
EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool fuzzy_constant_all_of(const Derived& xpr, const Predicate& pred,
std::true_type) {
if (EIGEN_PREDICT_FALSE(!pred.packetOpApplies())) return all_of(xpr, scalar_predicate<Predicate>{pred});
return all_of(xpr, pred);
}
template <typename Derived, typename Predicate>
EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool fuzzy_constant_all_of(const Derived& xpr, const Predicate& pred,
std::false_type) {
return all_of(xpr, pred);
}
template <typename Derived, bool AlwaysTrue = NumTraits<typename traits<Derived>::Scalar>::IsInteger>
struct all_finite_impl {
static EIGEN_DEVICE_FUNC inline bool run(const Derived& /*derived*/) { return true; }
};
#if !defined(__FINITE_MATH_ONLY__) || !(__FINITE_MATH_ONLY__)
template <typename Derived>
struct all_finite_impl<Derived, false> {
static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool run(const Derived& derived) {
return all_of(derived, isfinite_predicate<typename traits<Derived>::Scalar>());
}
};
#endif
} // end namespace internal
/** \returns true if all coefficients are true
*
* Example: \include MatrixBase_all.cpp
* Output: \verbinclude MatrixBase_all.out
*
* \sa any(), Cwise::operator<()
*/
template <typename Derived>
EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool DenseBase<Derived>::all() const {
return internal::all_of(derived(), internal::nonzero_predicate<Scalar>());
}
/** \returns true if at least one coefficient is true
*
* \sa all()
*/
template <typename Derived>
EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool DenseBase<Derived>::any() const {
return internal::any_of(derived(), internal::nonzero_predicate<Scalar>());
}
template <typename Derived>
EIGEN_DEVICE_FUNC inline bool DenseBase<Derived>::hasNaN() const {
return derived().cwiseTypedNotEqual(derived()).any();
}
/** \returns true if \c *this contains only finite numbers, i.e., no NaN and no +/-INF values.
*
* \sa hasNaN()
*/
template <typename Derived>
EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool DenseBase<Derived>::allFinite() const {
return internal::all_finite_impl<Derived>::run(derived());
}
/** \returns true if all coefficients in this matrix are approximately equal to \a val, to within precision \a prec */
template <typename Derived>
EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool DenseBase<Derived>::isApproxToConstant(const Scalar& val,
const RealScalar& prec) const {
using Predicate = internal::fuzzy_constant_predicate<Scalar, true>;
return internal::fuzzy_constant_all_of(
derived(), Predicate{val, prec},
std::integral_constant<bool, internal::functor_traits<Predicate>::PacketAccess>());
}
/** \returns true if *this is approximately equal to the zero matrix,
* within the precision given by \a prec.
*
* Example: \include MatrixBase_isZero.cpp
* Output: \verbinclude MatrixBase_isZero.out
*
* \sa class CwiseNullaryOp, Zero()
*/
template <typename Derived>
EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool DenseBase<Derived>::isZero(const RealScalar& prec) const {
return internal::all_of(derived(), internal::fuzzy_constant_predicate<Scalar, false>{Scalar(0), prec});
}
} // end namespace Eigen
#endif // EIGEN_PREDICATOR_H