Add test coverage for transpose, reverse, bool redux, select, diagonal-of-product at boundaries

libeigen/eigen!2290

Co-authored-by: Rasmus Munk Larsen <rmlarsen@gmail.com>
This commit is contained in:
Rasmus Munk Larsen
2026-03-12 17:02:58 -07:00
parent 356a9ba1da
commit 6b9275d1a8
5 changed files with 209 additions and 0 deletions

View File

@@ -81,6 +81,79 @@ void diagonal_assert(const MatrixType& m) {
VERIFY_RAISES_ASSERT(m1.diagonal(-(rows + 1)));
}
// Test that (A * B).diagonal() gives the same result as (A * B).eval().diagonal().
// The diagonal-of-product path uses LazyProduct evaluation (see ProductEvaluators.h),
// which avoids computing the full product. Verify this optimization is correct.
template <typename Scalar>
void diagonal_of_product() {
const Index PS = internal::packet_traits<Scalar>::size;
const Index sizes[] = {1, 2, 3, PS - 1, PS, PS + 1, 2 * PS - 1, 2 * PS, 2 * PS + 1, 4 * PS, 4 * PS + 1};
typedef Matrix<Scalar, Dynamic, Dynamic> Mat;
typedef Matrix<Scalar, Dynamic, 1> Vec;
for (int si = 0; si < 11; ++si) {
Index n = sizes[si];
if (n <= 0) continue;
Mat A = Mat::Random(n, n);
Mat B = Mat::Random(n, n);
// Lazy diagonal vs explicit product diagonal
Vec diag_lazy = (A * B).diagonal();
Vec diag_explicit = (A * B).eval().diagonal();
VERIFY_IS_APPROX(diag_lazy, diag_explicit);
// Also test non-square: A is m×k, B is k×n
for (int k : {1, 3, (int)n}) {
if (k <= 0) continue;
Mat C = Mat::Random(n, k);
Mat D = Mat::Random(k, n);
Vec diag_lazy2 = (C * D).diagonal();
Vec diag_explicit2 = (C * D).eval().diagonal();
VERIFY_IS_APPROX(diag_lazy2, diag_explicit2);
}
}
}
// Test .select() at vectorization boundary sizes.
// select() uses CwiseTernaryOp which has packet-level evaluation with remainder handling.
template <typename Scalar>
void select_boundary() {
const Index PS = internal::packet_traits<Scalar>::size;
const Index sizes[] = {1, 2, 3, PS - 1, PS, PS + 1, 2 * PS - 1, 2 * PS, 2 * PS + 1, 4 * PS, 4 * PS + 1};
typedef Array<Scalar, Dynamic, 1> Arr;
for (int si = 0; si < 11; ++si) {
Index n = sizes[si];
if (n <= 0) continue;
Arr a = Arr::Random(n);
Arr b = Arr::Random(n);
auto cond = (a > Scalar(0));
// select with two arrays
Arr result = cond.select(a, b);
for (Index k = 0; k < n; ++k) {
Scalar expected = (a(k) > Scalar(0)) ? a(k) : b(k);
VERIFY_IS_APPROX(result(k), expected);
}
// select with scalar else
Arr result2 = cond.select(a, Scalar(0));
for (Index k = 0; k < n; ++k) {
Scalar expected = (a(k) > Scalar(0)) ? a(k) : Scalar(0);
VERIFY_IS_APPROX(result2(k), expected);
}
// select with scalar then
Arr result3 = cond.select(Scalar(42), b);
for (Index k = 0; k < n; ++k) {
Scalar expected = (a(k) > Scalar(0)) ? Scalar(42) : b(k);
VERIFY_IS_APPROX(result3(k), expected);
}
}
}
EIGEN_DECLARE_TEST(diagonal) {
for (int i = 0; i < g_repeat; i++) {
CALL_SUBTEST_1(diagonal(Matrix<float, 1, 1>()));
@@ -99,4 +172,14 @@ EIGEN_DECLARE_TEST(diagonal) {
CALL_SUBTEST_1(diagonal_assert(
MatrixXf(internal::random<int>(1, EIGEN_TEST_MAX_SIZE), internal::random<int>(1, EIGEN_TEST_MAX_SIZE))));
}
// Diagonal-of-product optimization (deterministic, outside g_repeat).
CALL_SUBTEST_3(diagonal_of_product<float>());
CALL_SUBTEST_3(diagonal_of_product<double>());
CALL_SUBTEST_3(diagonal_of_product<std::complex<float>>());
// Select at vectorization boundaries (deterministic, outside g_repeat).
CALL_SUBTEST_4(select_boundary<float>());
CALL_SUBTEST_4(select_boundary<double>());
CALL_SUBTEST_4(select_boundary<int>());
}