Add boundary test coverage: stableNorm, LinSpaced, complex GEMV, triangular solve

libeigen/eigen!2291

Co-authored-by: Rasmus Munk Larsen <rmlarsen@gmail.com>
This commit is contained in:
Rasmus Munk Larsen
2026-03-12 18:15:30 -07:00
parent 6b9275d1a8
commit c1faa74738
4 changed files with 401 additions and 0 deletions

View File

@@ -569,6 +569,88 @@ void product_custom_scalar_types() {
}
}
// Test complex GEMV with all conjugation combinations at sizes that
// exercise full, half, and quarter packet code paths.
// The GEMV kernels in GeneralMatrixVector.h use conj_helper at three
// packet levels. The existing product_extra tests cover conjugation
// but only at random sizes, never systematically at packet boundaries.
template <int>
void gemv_complex_conjugate() {
typedef std::complex<float> Scf;
typedef std::complex<double> Scd;
const Index PS_f = internal::packet_traits<Scf>::size;
const Index PS_d = internal::packet_traits<Scd>::size;
// Sizes chosen to exercise packet boundaries for both float and double.
const Index sizes[] = {1, 2, 3, 4, 5, 7, 8, 9, 15, 16, 17, 31, 32, 33};
for (int si = 0; si < 14; ++si) {
Index m = sizes[si];
// Test complex<float> GEMV with all conjugation combos.
{
typedef Matrix<Scf, Dynamic, Dynamic> Mat;
typedef Matrix<Scf, Dynamic, 1> Vec;
Mat A = Mat::Random(m, m);
Vec v = Vec::Random(m);
Vec res(m);
// A * v (no conjugation)
res.noalias() = A * v;
VERIFY_IS_APPROX(res, (A.eval() * v.eval()).eval());
// A.conjugate() * v
res.noalias() = A.conjugate() * v;
VERIFY_IS_APPROX(res, (A.conjugate().eval() * v.eval()).eval());
// A * v.conjugate()
res.noalias() = A * v.conjugate();
VERIFY_IS_APPROX(res, (A.eval() * v.conjugate().eval()).eval());
// A.conjugate() * v.conjugate()
res.noalias() = A.conjugate() * v.conjugate();
VERIFY_IS_APPROX(res, (A.conjugate().eval() * v.conjugate().eval()).eval());
// A.adjoint() * v (transpose + conjugate of lhs)
Vec res2(m);
res2.noalias() = A.adjoint() * v;
VERIFY_IS_APPROX(res2, (A.adjoint().eval() * v.eval()).eval());
// Row-major complex GEMV
typedef Matrix<Scf, Dynamic, Dynamic, RowMajor> RMat;
RMat B = A;
res.noalias() = B * v;
VERIFY_IS_APPROX(res, (A.eval() * v.eval()).eval());
res.noalias() = B.conjugate() * v;
VERIFY_IS_APPROX(res, (A.conjugate().eval() * v.eval()).eval());
}
// Test complex<double> GEMV with conjugation.
{
typedef Matrix<Scd, Dynamic, Dynamic> Mat;
typedef Matrix<Scd, Dynamic, 1> Vec;
Mat A = Mat::Random(m, m);
Vec v = Vec::Random(m);
Vec res(m);
res.noalias() = A.conjugate() * v;
VERIFY_IS_APPROX(res, (A.conjugate().eval() * v.eval()).eval());
res.noalias() = A * v.conjugate();
VERIFY_IS_APPROX(res, (A.eval() * v.conjugate().eval()).eval());
// Non-square: wide matrix × vector (exercises different cols path).
Mat C = Mat::Random(m, m + 3);
Vec w = Vec::Random(m + 3);
Vec res3(m);
res3.noalias() = C.conjugate() * w;
VERIFY_IS_APPROX(res3, (C.conjugate().eval() * w.eval()).eval());
}
}
(void)PS_f;
(void)PS_d;
}
EIGEN_DECLARE_TEST(product_extra) {
for (int i = 0; i < g_repeat; i++) {
CALL_SUBTEST_1(product_extra(
@@ -593,4 +675,7 @@ EIGEN_DECLARE_TEST(product_extra) {
CALL_SUBTEST_8(aliasing_with_resize<void>());
CALL_SUBTEST_9(product_custom_scalar_types<0>());
CALL_SUBTEST_10(test_small_block_correctness<0>());
// Complex GEMV conjugation at varied sizes (deterministic, outside g_repeat).
CALL_SUBTEST_11(gemv_complex_conjugate<0>());
}