Add test coverage for strided maps, triangular blocking, and mixed storage orders

libeigen/eigen!2288

Co-authored-by: Rasmus Munk Larsen <rmlarsen@gmail.com>
This commit is contained in:
Rasmus Munk Larsen
2026-03-12 14:07:21 -07:00
parent 93aa959b8a
commit 15cae83485
3 changed files with 202 additions and 2 deletions

View File

@@ -167,12 +167,83 @@ void check_const_correctness(const PlainObjectType&) {
// verify that map-to-const don't have LvalueBit
typedef std::add_const_t<PlainObjectType> ConstPlainObjectType;
VERIFY(!(internal::traits<Map<ConstPlainObjectType> >::Flags & LvalueBit));
VERIFY(!(internal::traits<Map<ConstPlainObjectType, AlignedMax> >::Flags & LvalueBit));
VERIFY(!(internal::traits<Map<ConstPlainObjectType>>::Flags & LvalueBit));
VERIFY(!(internal::traits<Map<ConstPlainObjectType, AlignedMax>>::Flags & LvalueBit));
VERIFY(!(Map<ConstPlainObjectType>::Flags & LvalueBit));
VERIFY(!(Map<ConstPlainObjectType, AlignedMax>::Flags & LvalueBit));
}
// Test Map with InnerStride at vectorization boundary sizes.
// Strided Maps exercise different traversal paths (SliceVectorized or Default)
// in assignment and reductions.
template <typename Scalar>
void map_inner_stride_boundary() {
const Index PS = internal::packet_traits<Scalar>::size;
const Index sizes[] = {1, 2, 3, PS - 1, PS, PS + 1, 2 * PS, 2 * PS + 1, 4 * PS, 4 * PS + 1};
for (int si = 0; si < 10; ++si) {
const Index n = sizes[si];
if (n <= 0) continue;
typedef Matrix<Scalar, Dynamic, 1> Vec;
// InnerStride<2>: every other element
Vec data = Vec::Random(2 * n);
Map<Vec, 0, InnerStride<2>> strided(data.data(), n);
// Test assignment to/from strided map
Vec dense = strided;
for (Index k = 0; k < n; ++k) VERIFY_IS_APPROX(dense(k), data(2 * k));
// Test scalar operations on strided map
Vec result = Scalar(2) * strided;
for (Index k = 0; k < n; ++k) VERIFY_IS_APPROX(result(k), Scalar(2) * data(2 * k));
// Test strided map + dense vector
Vec other = Vec::Random(n);
Vec sum_result = strided + other;
for (Index k = 0; k < n; ++k) VERIFY_IS_APPROX(sum_result(k), data(2 * k) + other(k));
// Test writing to strided map
Map<Vec, 0, InnerStride<2>> strided_dst(data.data(), n);
strided_dst = other;
for (Index k = 0; k < n; ++k) VERIFY_IS_APPROX(data(2 * k), other(k));
}
}
// Test Map with OuterStride on matrices at boundary sizes.
template <typename Scalar>
void map_outer_stride_boundary() {
const Index PS = internal::packet_traits<Scalar>::size;
typedef Matrix<Scalar, Dynamic, Dynamic> Mat;
// Test various inner dimensions around packet size
const Index inner_sizes[] = {1, PS - 1, PS, PS + 1, 2 * PS, 2 * PS + 1};
const Index outer_stride = 64; // large enough for any inner size
const Index cols = 4;
for (int si = 0; si < 6; ++si) {
Index rows = inner_sizes[si];
if (rows <= 0) continue;
typedef Matrix<Scalar, Dynamic, 1> Vec;
Vec data = Vec::Random(outer_stride * cols);
Map<Mat, 0, OuterStride<>> mapped(data.data(), rows, cols, OuterStride<>(outer_stride));
// Test that mapped values match expected layout
Mat dense = mapped;
for (Index j = 0; j < cols; ++j)
for (Index i = 0; i < rows; ++i) VERIFY_IS_APPROX(dense(i, j), data(j * outer_stride + i));
// Test reduction on mapped matrix
Scalar ref_sum(0);
for (Index j = 0; j < cols; ++j)
for (Index i = 0; i < rows; ++i) ref_sum += data(j * outer_stride + i);
VERIFY_IS_APPROX(mapped.sum(), ref_sum);
// Test matrix product with mapped matrix
Vec x = Vec::Random(cols);
Vec y = mapped * x;
Vec y_ref = dense * x;
VERIFY_IS_APPROX(y, y_ref);
}
}
EIGEN_DECLARE_TEST(mapped_matrix) {
for (int i = 0; i < g_repeat; i++) {
CALL_SUBTEST_1(map_class_vector(Matrix<float, 1, 1>()));
@@ -197,4 +268,10 @@ EIGEN_DECLARE_TEST(mapped_matrix) {
CALL_SUBTEST_9(map_static_methods(VectorXcd(8)));
CALL_SUBTEST_10(map_static_methods(VectorXf(12)));
}
// Strided map tests at vectorization boundaries (deterministic, outside g_repeat).
CALL_SUBTEST_12(map_inner_stride_boundary<float>());
CALL_SUBTEST_12(map_inner_stride_boundary<double>());
CALL_SUBTEST_13(map_outer_stride_boundary<float>());
CALL_SUBTEST_13(map_outer_stride_boundary<double>());
}