Core: Serve packets from Replicate evaluators when boundary-safe
libeigen/eigen!2751 Closes #1492 Co-authored-by: Rasmus Munk Larsen <rmlarsen@gmail.com>
This commit is contained in:
co-authored by
Rasmus Munk Larsen
parent
c80e7b89f2
commit
d25a9eafda
@@ -62,6 +62,69 @@ void replicate(const MatrixType& m) {
|
||||
VERIFY_IS_APPROX(vx1, v1.colwise().replicate(f2));
|
||||
}
|
||||
|
||||
// A Replicate packet cannot cross a replication boundary, so the evaluator may serve packets
|
||||
// exactly when the inner (storage-order) direction is not replicated; without the flag, colwise
|
||||
// and rowwise broadcast operations silently fall back to scalar traversal.
|
||||
template <typename Scalar>
|
||||
void check_replicate_evaluator_flags() {
|
||||
// Storage orders are pinned so the checks keep their meaning under EIGEN_DEFAULT_TO_ROW_MAJOR.
|
||||
typedef Matrix<Scalar, Dynamic, Dynamic, ColMajor> Mat;
|
||||
typedef Matrix<Scalar, Dynamic, Dynamic, RowMajor> RowMat;
|
||||
typedef Matrix<Scalar, Dynamic, 1> Vec;
|
||||
typedef Matrix<Scalar, 1, Dynamic> RowVec;
|
||||
enum { BasePacket = int(internal::evaluator<Mat>::Flags) & PacketAccessBit };
|
||||
|
||||
// Inner direction not replicated: packets serve from a single copy of the argument. The first
|
||||
// two are the shapes colwise (col-major) and rowwise (row-major) operations expand to.
|
||||
STATIC_CHECK((int(internal::evaluator<Replicate<Vec, 1, Dynamic> >::Flags) & PacketAccessBit) == int(BasePacket));
|
||||
STATIC_CHECK((int(internal::evaluator<Replicate<RowVec, Dynamic, 1> >::Flags) & PacketAccessBit) == int(BasePacket));
|
||||
STATIC_CHECK((int(internal::evaluator<Replicate<Mat, 1, 3> >::Flags) & PacketAccessBit) == int(BasePacket));
|
||||
STATIC_CHECK((int(internal::evaluator<Replicate<RowMat, 3, 1> >::Flags) & PacketAccessBit) == int(BasePacket));
|
||||
STATIC_CHECK(int(internal::evaluator<Replicate<Vec, 1, Dynamic> >::Alignment) ==
|
||||
int(internal::evaluator<Vec>::Alignment));
|
||||
|
||||
// Replicated inner direction (or factors unknown at compile time): a packet could cross a copy
|
||||
// boundary, so there is no packet access.
|
||||
STATIC_CHECK((int(internal::evaluator<Replicate<Mat, 3, 1> >::Flags) & PacketAccessBit) == 0);
|
||||
STATIC_CHECK((int(internal::evaluator<Replicate<Vec, Dynamic, 1> >::Flags) & PacketAccessBit) == 0);
|
||||
STATIC_CHECK((int(internal::evaluator<Replicate<Mat, Dynamic, Dynamic> >::Flags) & PacketAccessBit) == 0);
|
||||
}
|
||||
|
||||
// Exercise the (possibly vectorized) broadcast kernels with sizes that have partial-packet tails.
|
||||
template <typename Scalar>
|
||||
void replicate_broadcasts(Index rows, Index cols) {
|
||||
typedef Matrix<Scalar, Dynamic, Dynamic> Mat;
|
||||
typedef Matrix<Scalar, Dynamic, 1> Vec;
|
||||
typedef Matrix<Scalar, 1, Dynamic> RowVec;
|
||||
|
||||
Mat m = Mat::Random(rows, cols);
|
||||
Vec v = Vec::Random(rows);
|
||||
RowVec rv = RowVec::Random(cols);
|
||||
|
||||
Mat c = m;
|
||||
c.colwise() += v;
|
||||
for (Index j = 0; j < cols; ++j)
|
||||
for (Index i = 0; i < rows; ++i) VERIFY_IS_EQUAL(c(i, j), Scalar(m(i, j) + v(i)));
|
||||
|
||||
Mat r = m;
|
||||
r.rowwise() += rv;
|
||||
for (Index j = 0; j < cols; ++j)
|
||||
for (Index i = 0; i < rows; ++i) VERIFY_IS_EQUAL(r(i, j), Scalar(m(i, j) + rv(j)));
|
||||
|
||||
Mat h = m.template replicate<1, 3>();
|
||||
for (Index j = 0; j < 3 * cols; ++j)
|
||||
for (Index i = 0; i < rows; ++i) VERIFY_IS_EQUAL(h(i, j), m(i, j % cols));
|
||||
|
||||
Mat ver = m.template replicate<3, 1>();
|
||||
for (Index j = 0; j < cols; ++j)
|
||||
for (Index i = 0; i < 3 * rows; ++i) VERIFY_IS_EQUAL(ver(i, j), m(i % rows, j));
|
||||
|
||||
// A replicate nested inside a larger coefficient-wise expression.
|
||||
Mat sum = m + v.rowwise().replicate(cols);
|
||||
for (Index j = 0; j < cols; ++j)
|
||||
for (Index i = 0; i < rows; ++i) VERIFY_IS_EQUAL(sum(i, j), Scalar(m(i, j) + v(i)));
|
||||
}
|
||||
|
||||
EIGEN_DECLARE_TEST(array_replicate) {
|
||||
for (int i = 0; i < g_repeat; i++) {
|
||||
CALL_SUBTEST_1(replicate(Matrix<float, 1, 1>()));
|
||||
@@ -70,5 +133,11 @@ EIGEN_DECLARE_TEST(array_replicate) {
|
||||
CALL_SUBTEST_4(replicate(Vector4f()));
|
||||
CALL_SUBTEST_5(replicate(VectorXf(16)));
|
||||
CALL_SUBTEST_6(replicate(VectorXcd(10)));
|
||||
CALL_SUBTEST_7(check_replicate_evaluator_flags<float>());
|
||||
CALL_SUBTEST_7(replicate_broadcasts<float>(internal::random<Index>(1, 64), internal::random<Index>(1, 64)));
|
||||
CALL_SUBTEST_7(replicate_broadcasts<float>(17, 19));
|
||||
CALL_SUBTEST_8(check_replicate_evaluator_flags<double>());
|
||||
CALL_SUBTEST_8(replicate_broadcasts<double>(internal::random<Index>(1, 64), internal::random<Index>(1, 64)));
|
||||
CALL_SUBTEST_8(replicate_broadcasts<std::complex<float> >(9, 5));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user