From 70eb09d6d5d8aa6e824ff99dc10d4f7f56269eb8 Mon Sep 17 00:00:00 2001 From: John Halloran Date: Sun, 12 Apr 2026 15:21:21 -0400 Subject: [PATCH 1/5] fix: use matplotlib-base when installing with conda-forge --- news/forge-cleanup.rst | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 news/forge-cleanup.rst diff --git a/news/forge-cleanup.rst b/news/forge-cleanup.rst new file mode 100644 index 00000000..17db9ea2 --- /dev/null +++ b/news/forge-cleanup.rst @@ -0,0 +1,23 @@ +**Added:** + +* + +**Changed:** + +* + +**Deprecated:** + +* + +**Removed:** + +* + +**Fixed:** + +* Use matplotlib-base when installing with conda-forge + +**Security:** + +* From 850b992ba214141038f84c5309c0bcd1aee54ed3 Mon Sep 17 00:00:00 2001 From: John Halloran Date: Sun, 12 Apr 2026 15:50:25 -0400 Subject: [PATCH 2/5] chore: add news item for previous commit --- news/forge-cleanup.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/news/forge-cleanup.rst b/news/forge-cleanup.rst index 17db9ea2..26c98cf2 100644 --- a/news/forge-cleanup.rst +++ b/news/forge-cleanup.rst @@ -4,7 +4,7 @@ **Changed:** -* +* Rename cli entrypoint to 'snmf' from 'diffpy.stretched-nmf' **Deprecated:** From fdf955361e88e242ca3e98982e146afb8adb6cc6 Mon Sep 17 00:00:00 2001 From: John Halloran Date: Sun, 12 Apr 2026 15:58:40 -0400 Subject: [PATCH 3/5] fix: produce an error if test files are missing --- news/forge-cleanup.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/news/forge-cleanup.rst b/news/forge-cleanup.rst index 26c98cf2..a0a0d602 100644 --- a/news/forge-cleanup.rst +++ b/news/forge-cleanup.rst @@ -16,6 +16,7 @@ **Fixed:** +* Produce an error if test files are missing * Use matplotlib-base when installing with conda-forge **Security:** From 1d486bc74f6ff159dfbf6ad5a01f64e69e269a10 Mon Sep 17 00:00:00 2001 From: John Halloran Date: Fri, 1 May 2026 11:41:48 -0400 Subject: [PATCH 4/5] fix: make fitting test self-contained --- tests/test_snmf_optimizer.py | 72 +++++++++++++----------------------- 1 file changed, 26 insertions(+), 46 deletions(-) diff --git a/tests/test_snmf_optimizer.py b/tests/test_snmf_optimizer.py index 27cae5d7..39406cf3 100644 --- a/tests/test_snmf_optimizer.py +++ b/tests/test_snmf_optimizer.py @@ -1,62 +1,42 @@ -from pathlib import Path - import numpy as np import pytest from diffpy.stretched_nmf.snmf_class import SNMFOptimizer -DATA_DIR = ( - Path(__file__).resolve().parents[1] - / "docs/examples/data/XRD-MgMnO-YCl-real" -) - -_required = [ - "init-components.txt", - "source-matrix.txt", - "init-stretch.txt", - "init-weights.txt", -] -_missing = [f for f in _required if not (DATA_DIR / f).exists()] - - -@pytest.fixture(scope="module") -def inputs(): - if _missing: - pytest.fail( - f"Missing required test data files in {DATA_DIR}: {_missing}" - ) - return { - "components": np.loadtxt( - DATA_DIR / "init-components.txt", dtype=float - ), - "source": np.loadtxt( - DATA_DIR / "source-matrix.txt", dtype=float, skiprows=4 - ), - "stretch": np.loadtxt(DATA_DIR / "init-stretch.txt", dtype=float), - "weights": np.loadtxt(DATA_DIR / "init-weights.txt", dtype=float), - } +def test_fit_recovers_rank_one_factors(): + expected_components = np.array( + [ + [0.20], + [0.75], + [1.20], + [0.80], + [0.30], + ] + ) + expected_weights = np.array( + [ + [0.20, 0.60, 1.00, 0.40], + ] + ) + source = expected_components @ expected_weights -@pytest.mark.slow -def test_final_objective_below_threshold(inputs): model = SNMFOptimizer( + n_components=1, show_plots=False, random_state=1, - min_iter=5, - max_iter=5, - rho=1e12, - eta=610, - ) - model.fit( - source_matrix=inputs["source"], - init_weights=inputs["weights"], - init_components=inputs["components"], - init_stretch=inputs["stretch"], + min_iter=0, + max_iter=2, + rho=0.0, + eta=0.0, ) + model.fit(source_matrix=source) - # Basic sanity check and the actual assertion assert np.isfinite(model.objective_function_) - assert model.objective_function_ < 5e6 + assert np.allclose( + model.components_, expected_components, rtol=0.2, atol=0.1 + ) + assert np.allclose(model.weights_, expected_weights, rtol=0.2, atol=0.1) @pytest.mark.parametrize( From a061c3e6bc67e75db05fc9955ac74648a335f0ca Mon Sep 17 00:00:00 2001 From: John Halloran Date: Fri, 1 May 2026 12:04:28 -0400 Subject: [PATCH 5/5] fix: don't pin to an unsupported python version --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0e4a84d1..6dd0307a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,5 +1,5 @@ default_language_version: - python: python3 + python: python3.13 ci: autofix_commit_msg: | [pre-commit.ci] auto fixes from pre-commit hooks