|
1 | 1 | "Pytest configuration for pyfixest tests." |
2 | 2 |
|
3 | 3 | import os |
4 | | - |
5 | | -import pytest |
6 | | - |
7 | | - |
8 | | -@pytest.fixture(scope="session", autouse=True) |
9 | | -def single_thread_blas(): |
10 | | - """ |
11 | | - Force single-threaded BLAS for deterministic HAC standard errors. |
12 | | -
|
13 | | - What Claude says: |
14 | | -
|
15 | | - Multi-threaded BLAS libraries (OpenBLAS, MKL, Accelerate) can produce |
16 | | - slightly different numerical results due to different parallel reduction |
17 | | - orders when computing matrix multiplications. This causes sporadic test |
18 | | - failures in HAC variance calculations even though both R and Python |
19 | | - implementations are mathematically correct. |
20 | | -
|
21 | | - The differences arise because floating-point arithmetic is not associative: |
22 | | - (a + b) + c ≠ a + (b + c) in IEEE 754. Different thread scheduling can |
23 | | - change the order of operations, leading to different rounding errors. |
24 | | -
|
25 | | - By forcing single-threaded execution, we ensure deterministic results |
26 | | - that match R's fixest package exactly. |
27 | | - """ |
28 | | - # Store original values to restore after tests |
29 | | - original_values = {} |
30 | | - |
31 | | - env_vars = [ |
32 | | - "OMP_NUM_THREADS", |
33 | | - "OPENBLAS_NUM_THREADS", |
34 | | - "MKL_NUM_THREADS", |
35 | | - "VECLIB_MAXIMUM_THREADS", |
36 | | - "NUMEXPR_NUM_THREADS", |
37 | | - ] |
38 | | - |
39 | | - for var in env_vars: |
40 | | - original_values[var] = os.environ.get(var) |
41 | | - os.environ[var] = "1" |
42 | | - |
43 | | - yield |
44 | | - |
45 | | - # Restore original values after all tests complete |
46 | | - for var, value in original_values.items(): |
47 | | - if value is None: |
48 | | - os.environ.pop(var, None) |
49 | | - else: |
50 | | - os.environ[var] = value |
| 4 | +import sys |
| 5 | + |
| 6 | +# Force single-threaded BLAS for deterministic HAC standard errors. |
| 7 | +# |
| 8 | +# Multi-threaded BLAS libraries (OpenBLAS, MKL, Accelerate) can produce |
| 9 | +# slightly different numerical results due to different parallel reduction |
| 10 | +# orders when computing matrix multiplications. This causes sporadic test |
| 11 | +# failures in HAC variance calculations even though both R and Python |
| 12 | +# implementations are mathematically correct. |
| 13 | +# |
| 14 | +# The differences arise because floating-point arithmetic is not associative: |
| 15 | +# (a + b) + c ≠ a + (b + c) in IEEE 754. Different thread scheduling can |
| 16 | +# change the order of operations, leading to different rounding errors. |
| 17 | +# |
| 18 | +# By forcing single-threaded execution, we ensure deterministic results |
| 19 | +# that match R's fixest package exactly. |
| 20 | +# |
| 21 | +# This must be set at module level (before numpy/scipy imports) because |
| 22 | +# BLAS libraries read these environment variables when first initialized. |
| 23 | + |
| 24 | +# Check if HAC tests are being run |
| 25 | +_run_hac_tests = any( |
| 26 | + arg in sys.argv for arg in ["test_hac_vs_fixest.py", "-m hac", "--markers=hac"] |
| 27 | +) or any("test_hac_vs_fixest" in arg for arg in sys.argv) |
| 28 | + |
| 29 | +if _run_hac_tests: |
| 30 | + os.environ["OMP_NUM_THREADS"] = "1" |
| 31 | + os.environ["OPENBLAS_NUM_THREADS"] = "1" |
| 32 | + os.environ["MKL_NUM_THREADS"] = "1" |
| 33 | + os.environ["VECLIB_MAXIMUM_THREADS"] = "1" |
| 34 | + os.environ["NUMEXPR_NUM_THREADS"] = "1" |
0 commit comments