Skip to content

Commit dae2f8e

Browse files
john-halloranJohn Halloran
andauthored
test: add initial test of optimizer (#167)
* test: add initial test of optimizer * style: switch to local imports and plural folders * style: add README to sNMF test --------- Co-authored-by: John Halloran <[email protected]>
1 parent 0bf62a8 commit dae2f8e

File tree

10 files changed

+2194
-7
lines changed

10 files changed

+2194
-7
lines changed

pyproject.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,3 +81,9 @@ exclude = '''
8181
| tests/data
8282
)/
8383
'''
84+
85+
[tool.pytest.ini_options]
86+
markers = [
87+
"slow: marks tests as slow (deselect with '-m \"not slow\"')",
88+
]
89+
testpaths = ["tests"]

src/diffpy/snmf/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
# package version
1919
from diffpy.snmf.version import __version__
2020

21+
__all__ = ["__version__", "SNMFOptimizer"]
22+
2123
# silence the pyflakes syntax checker
2224
assert __version__ or True
2325

src/diffpy/snmf/main.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import numpy as np
2-
from snmf_class import SNMFOptimizer
2+
3+
from diffpy.snmf.snmf_class import SNMFOptimizer
34

45
# Example input files (not provided)
5-
init_components_file = np.loadtxt("input/init_components.txt", dtype=float)
6-
source_matrix_file = np.loadtxt("input/source_matrix.txt", dtype=float)
7-
init_stretch_file = np.loadtxt("input/init_stretch.txt", dtype=float)
8-
init_weights_file = np.loadtxt("input/init_weights.txt", dtype=float)
6+
init_components_file = np.loadtxt("inputs/init_components.txt", dtype=float)
7+
source_matrix_file = np.loadtxt("inputs/source_matrix.txt", dtype=float)
8+
init_stretch_file = np.loadtxt("inputs/init_stretch.txt", dtype=float)
9+
init_weights_file = np.loadtxt("inputs/init_weights.txt", dtype=float)
910

1011
my_model = SNMFOptimizer(
1112
source_matrix=source_matrix_file,

src/diffpy/snmf/snmf_class.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import cvxpy as cp
22
import numpy as np
3-
from plotter import SNMFPlotter
43
from scipy.optimize import minimize
54
from scipy.sparse import coo_matrix, diags
65

6+
from diffpy.snmf.plotter import SNMFPlotter
7+
78

89
class SNMFOptimizer:
910
"""An implementation of stretched NMF (sNMF), including sparse stretched NMF.
@@ -625,7 +626,7 @@ def update_stretch(self):
625626
Updates matrix A using constrained optimization (equivalent to fmincon in MATLAB).
626627
"""
627628

628-
# Flatten A for compatibility with the optimizer (since SciPy expects 1D input)
629+
# Flatten A for compatibility with the optimizer (since SciPy expects 1D inputs)
629630
stretch_flat_initial = self.stretch.flatten()
630631

631632
# Define the optimization function
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
This test is a whole-program test of the SNMF Optimizer. It runs the optimization on known data with fixed, trusted settings, then asserts
2+
whether the objective function is below a certain value after exactly a certain number of iterations.
3+
It is a blunt-force instrument that can tell if a PR has completely broken things, but it will not catch regressions, and its method
4+
of using objective function only can inadverdently validate a degenerate result. Use with caution.
5+
6+
This test uses data published in:
7+
Stretched Non-negative Matrix Factorization[J].
8+
Section 5.4 XRD
9+
Tab. 7, Fig. 8 & 9
10+
Gu R, Rakita Y, Lan L, et al.
11+
Stretched Non-negative Matrix Factorization[J].
12+
arXiv preprint arXiv:2311.15173, 2023.
13+
and later republished as:
14+
Gu, R., Rakita, Y., Lan, L. et al. Stretched non-negative matrix factorization.
15+
npj Comput Mater 10, 193 (2024). https://doi.org/10.1038/s41524-024-01377-5
16+
Data description:
17+
"A stoichiometric mixture of 2:1 YOCl (>98% tetragonal phase) and MgMn2O4 (spinel phase) was uniformly mixed and sealed in a quartz capillary. It was then heated in a gradient furnance, meaning that each location on the quartz tube had a different temperature31. The absolute temperatures at each point along the sample were calibrated from the lattice expansion of a known calibration material, Ni. The data went from a low temperature of 368∘C to a highest temperature of 668∘C with a total of 20 individual temperature points. Using ‘pyFAI’32, the collected 2D diffraction patterns were then cleaned by masking the beam-stop and over-bright/dead pixels, followed by an azimuthal integration to gain 1D PXRD patterns. The 1D PXRD data was then used as inputs to the different NMF algorithms."
18+
The data was originally sourced from:
19+
O’Nolan D, Huang G, Kamm GE, et al (2020)
20+
A thermal-gradient approach to variable-temperature measurements resolved in space.
21+
Journal of Applied Crystallography 53(3):662–670.

0 commit comments

Comments
 (0)