mirror of
https://gitlab.com/libeigen/eigen.git
synced 2026-04-10 11:34:33 +08:00
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:
@@ -108,6 +108,119 @@ void trsolve(int size = Size, int cols = Cols) {
|
||||
}
|
||||
}
|
||||
|
||||
// Test triangular solve with non-unit inner stride at blocking boundary sizes.
|
||||
// The scalar fallback path in trsmKernelR (TriangularSolverMatrix.h lines 156-166)
|
||||
// is used when OtherInnerStride != 1. The existing bug 1741 test only uses
|
||||
// InnerStride=2 at random sizes. This exercises the scalar path at sizes that
|
||||
// trigger blocking transitions and tests additional configurations.
|
||||
template <int>
|
||||
void trsolve_strided_boundary() {
|
||||
typedef double Scalar;
|
||||
typedef Matrix<Scalar, Dynamic, Dynamic> MatrixX;
|
||||
|
||||
const int sizes[] = {1, 2, 3, 4, 8, 12, 16, 24, 32, 47, 48, 49, 64};
|
||||
for (int si = 0; si < 13; ++si) {
|
||||
int n = sizes[si];
|
||||
|
||||
MatrixX lhs = MatrixX::Random(n, n);
|
||||
lhs *= 0.1;
|
||||
lhs.diagonal().array() += 1.0;
|
||||
|
||||
// InnerStride = 2: ColMajor RHS, OnTheLeft, Lower
|
||||
{
|
||||
int cols = 5;
|
||||
MatrixX buffer(2 * n, 2 * cols);
|
||||
Map<MatrixX, 0, Stride<Dynamic, 2> > map(buffer.data(), n, cols, Stride<Dynamic, 2>(2 * n, 2));
|
||||
MatrixX ref(n, cols);
|
||||
buffer.setZero();
|
||||
map.setRandom();
|
||||
ref = map;
|
||||
lhs.triangularView<Lower>().solveInPlace(map);
|
||||
VERIFY_IS_APPROX(lhs.triangularView<Lower>().toDenseMatrix() * MatrixX(map), ref);
|
||||
}
|
||||
|
||||
// InnerStride = 2: Upper triangular
|
||||
{
|
||||
int cols = 5;
|
||||
MatrixX buffer(2 * n, 2 * cols);
|
||||
Map<MatrixX, 0, Stride<Dynamic, 2> > map(buffer.data(), n, cols, Stride<Dynamic, 2>(2 * n, 2));
|
||||
MatrixX ref(n, cols);
|
||||
buffer.setZero();
|
||||
map.setRandom();
|
||||
ref = map;
|
||||
lhs.triangularView<Upper>().solveInPlace(map);
|
||||
VERIFY_IS_APPROX(lhs.triangularView<Upper>().toDenseMatrix() * MatrixX(map), ref);
|
||||
}
|
||||
|
||||
// InnerStride = 2: UnitLower (tests the UnitDiag path without diagonal scaling)
|
||||
{
|
||||
int cols = 3;
|
||||
MatrixX buffer(2 * n, 2 * cols);
|
||||
Map<MatrixX, 0, Stride<Dynamic, 2> > map(buffer.data(), n, cols, Stride<Dynamic, 2>(2 * n, 2));
|
||||
MatrixX ref(n, cols);
|
||||
buffer.setZero();
|
||||
map.setRandom();
|
||||
ref = map;
|
||||
lhs.triangularView<UnitLower>().solveInPlace(map);
|
||||
VERIFY_IS_APPROX(lhs.triangularView<UnitLower>().toDenseMatrix() * MatrixX(map), ref);
|
||||
}
|
||||
|
||||
// InnerStride = 3: Less common stride to exercise the scalar path more thoroughly
|
||||
{
|
||||
int cols = 4;
|
||||
MatrixX buffer(3 * n, 3 * cols);
|
||||
Map<MatrixX, 0, Stride<Dynamic, 3> > map(buffer.data(), n, cols, Stride<Dynamic, 3>(3 * n, 3));
|
||||
MatrixX ref(n, cols);
|
||||
buffer.setZero();
|
||||
map.setRandom();
|
||||
ref = map;
|
||||
lhs.triangularView<Lower>().solveInPlace(map);
|
||||
VERIFY_IS_APPROX(lhs.triangularView<Lower>().toDenseMatrix() * MatrixX(map), ref);
|
||||
}
|
||||
|
||||
// Vector RHS with InnerStride = 2
|
||||
{
|
||||
typedef Matrix<Scalar, Dynamic, 1> VecX;
|
||||
VecX buffer(2 * n);
|
||||
Map<VecX, 0, InnerStride<2> > map(buffer.data(), n, InnerStride<2>(2));
|
||||
buffer.setZero();
|
||||
map.setRandom();
|
||||
VecX ref = map;
|
||||
lhs.triangularView<Lower>().solveInPlace(map);
|
||||
VERIFY_IS_APPROX(lhs.triangularView<Lower>().toDenseMatrix() * VecX(map), ref);
|
||||
}
|
||||
}
|
||||
|
||||
// Complex with non-unit stride: tests conjugation in the scalar fallback path.
|
||||
{
|
||||
typedef std::complex<double> CScalar;
|
||||
typedef Matrix<CScalar, Dynamic, Dynamic> CMatrixX;
|
||||
int n = 32;
|
||||
CMatrixX lhs = CMatrixX::Random(n, n);
|
||||
lhs *= CScalar(0.1);
|
||||
lhs.diagonal().array() += CScalar(1.0);
|
||||
|
||||
int cols = 4;
|
||||
CMatrixX buffer(2 * n, 2 * cols);
|
||||
Map<CMatrixX, 0, Stride<Dynamic, 2> > map(buffer.data(), n, cols, Stride<Dynamic, 2>(2 * n, 2));
|
||||
CMatrixX ref(n, cols);
|
||||
|
||||
// Conjugate Lower
|
||||
buffer.setZero();
|
||||
map.setRandom();
|
||||
ref = map;
|
||||
lhs.conjugate().triangularView<Lower>().solveInPlace(map);
|
||||
VERIFY_IS_APPROX(lhs.conjugate().triangularView<Lower>().toDenseMatrix() * CMatrixX(map), ref);
|
||||
|
||||
// Adjoint Upper
|
||||
buffer.setZero();
|
||||
map.setRandom();
|
||||
ref = map;
|
||||
lhs.adjoint().triangularView<Lower>().solveInPlace(map);
|
||||
VERIFY_IS_APPROX(lhs.adjoint().triangularView<Lower>().toDenseMatrix() * CMatrixX(map), ref);
|
||||
}
|
||||
}
|
||||
|
||||
EIGEN_DECLARE_TEST(product_trsolve) {
|
||||
for (int i = 0; i < g_repeat; i++) {
|
||||
// matrices
|
||||
@@ -134,4 +247,7 @@ EIGEN_DECLARE_TEST(product_trsolve) {
|
||||
CALL_SUBTEST_13((trsolve<float, 1, 2>()));
|
||||
CALL_SUBTEST_14((trsolve<float, 3, 1>()));
|
||||
}
|
||||
|
||||
// Strided solve at blocking boundaries (deterministic, outside g_repeat).
|
||||
CALL_SUBTEST_15(trsolve_strided_boundary<0>());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user