From 1e179af3baaa468701f94876b574f9103b1d4dcf Mon Sep 17 00:00:00 2001 From: Timothy Nunn Date: Thu, 15 Jan 2026 16:27:34 +0000 Subject: [PATCH 1/2] Preempt possible unit test failures from ill-conditioned matrices --- tests/system_check.py | 62 ++++++++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 24 deletions(-) diff --git a/tests/system_check.py b/tests/system_check.py index 8d719a642a..502c82cd9b 100644 --- a/tests/system_check.py +++ b/tests/system_check.py @@ -1,27 +1,41 @@ -import os -import re +"""It is well-known at this point that PROCESS produces ever so slight different results depending upon +the operating system, system architecture, and the software versions installed on the system. This is +not surprising nor massively concerning for numeric scientific software. However, it can be problematic +for tests where the results we assert on change from system to system. + +We identify systems that will be succeptible to these tiny changes and skip the tests so as not to +create failures. We do this by checking the users systems results on an algorithm compared to some +known result. +This algorithm solves a system of equations that is very ill-conditioned where tiny numeric differences +can be identified and compared against a known system. +""" + +import numpy as np + + +def _hilbert_matrix(n): + """A matrix that is known to be ill-conditioned""" + return np.array( + [[1.0 / (i + j + 1) for j in range(n)] for i in range(n)], dtype=np.float64 + ) def system_compatible(): - """Check the system compatibility to ensure tests are not - overwritten with inaccurate data caused by floating point differences in - dynamically linked libraries provided by the OS. - - :return: is the system compatible with the test suite, and can it update the test - assets? - :rtype: boolean - """ - try: - shell_stream = os.popen("ldd --version") - - ldd_version = re.search(r"^ldd .+ (2.[0-9.]+).*", shell_stream.read()).group(1) - ldd_version_array = ldd_version.split(".") - major = ldd_version_array[0] - minor = ldd_version_array[1] - - if int(major) < 2 or (int(major) == 2 and int(minor) < 31): - return False - except AttributeError: - return False - - return True + """Check the system compatibility with numerically unstable tests.""" + # create an ill-conditioned system + a = _hilbert_matrix(10) + b = np.ones(10) + + # solve the ill-conditioned system + x = np.linalg.solve(a, b) + + # create a similar ill-conditioned system + a_perturbed = a.copy() + a_perturbed[0, 0] += np.finfo(float).eps + x_perturbed = np.linalg.solve(a_perturbed, b) + + # return the relative difference between the two solutions + rel_diff = np.linalg.norm(x - x_perturbed) / np.linalg.norm(x) + + # check that relative difference against a known solution + return rel_diff == 5.8813403984318865e-05 From 68d4a6fab5770eb67aae06863dabce82426a9a14 Mon Sep 17 00:00:00 2001 From: Timothy Nunn Date: Fri, 16 Jan 2026 09:26:27 +0000 Subject: [PATCH 2/2] Add tolerance to the Hilbert matrix system test --- tests/conftest.py | 2 +- tests/system_check.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 3d1e657cce..dadeb33d11 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -101,7 +101,7 @@ def skip_if_incompatible_system(): if not system_compatible(): pytest.skip( "This test could fail on your system due to differences caused by " - "floating-point rounding error" + "floating-point rounding differences in np.linalg.solve" ) diff --git a/tests/system_check.py b/tests/system_check.py index 502c82cd9b..5cd540ff34 100644 --- a/tests/system_check.py +++ b/tests/system_check.py @@ -11,6 +11,7 @@ """ import numpy as np +import pytest def _hilbert_matrix(n): @@ -38,4 +39,4 @@ def system_compatible(): rel_diff = np.linalg.norm(x - x_perturbed) / np.linalg.norm(x) # check that relative difference against a known solution - return rel_diff == 5.8813403984318865e-05 + return rel_diff == pytest.approx(5.8813403984318865e-05)