@@ -18,7 +18,7 @@ class SNMFOptimizer:
1818 ----------
1919 source_matrix : ndarray
2020 The original, unmodified data to be decomposed and later, compared against.
21- Shape is (length_of_signal, number_of_conditions ).
21+ Shape is (length_of_signal, number_of_signals ).
2222 stretch : ndarray
2323 The best guess (or while running, the current guess) for the stretching
2424 factor matrix.
@@ -47,14 +47,14 @@ class SNMFOptimizer:
4747 The number of components to extract from source_matrix. Must be provided when and only when
4848 Y0 is not provided.
4949 random_state : int
50- The seed for the initial guesses at the matrices (A, X , and Y ) created by
50+ The seed for the initial guesses at the matrices (stretch, components , and weights ) created by
5151 the decomposition.
5252 num_updates : int
53- The total number of times that any of (A, X , and Y ) have had their values changed.
53+ The total number of times that any of (stretch, components , and weights ) have had their values changed.
5454 If not terminated by other means, this value is used to stop when reaching max_iter.
5555 objective_function: float
5656 The value corresponding to the minimization of the difference between the source_matrix and the
57- products of A, X , and Y . For full details see the sNMF paper. Smaller corresponds to
57+ products of (stretch, components , and weights) . For full details see the sNMF paper. Smaller corresponds to
5858 better agreement and is desirable.
5959 objective_difference : float
6060 The change in the objective function value since the last update. A negative value
@@ -67,8 +67,8 @@ def __init__(
6767 init_weights = None ,
6868 init_components = None ,
6969 init_stretch = None ,
70- rho = 1e12 ,
71- eta = 610 ,
70+ rho = 0 ,
71+ eta = 0 ,
7272 max_iter = 500 ,
7373 tol = 5e-7 ,
7474 n_components = None ,
@@ -80,35 +80,36 @@ def __init__(
8080 ----------
8181 source_matrix : ndarray
8282 The data to be decomposed. Shape is (length_of_signal, number_of_conditions).
83- init_weights : ndarray
83+ init_weights : ndarray Optional Default = rng.beta(a=2.5, b=1.5, size=(n_components, n_signals))
8484 The initial guesses for the component weights at each stretching condition.
85- Shape is (number_of_components, number_of_conditions ) Must provide exactly one
85+ Shape is (number_of_components, number_of_signals ) Must provide exactly one
8686 of this or n_components.
87- init_components : ndarray
87+ init_components : ndarray Optional Default = rng.random((self.signal_length, self.n_components))
8888 The initial guesses for the intensities of each component per
8989 row/sample/angle. Shape is (length_of_signal, number_of_components).
90- init_stretch : ndarray
90+ init_stretch : ndarray Optional Default = np.ones((self.n_components, self.n_signals)) + self._rng.normal(
91+ 0, 1e-3, size=(self.n_components, self.n_signals)
9192 The initial guesses for the stretching factor for each component, at each
92- condition. Shape is (number_of_components, number_of_conditions ).
93- rho : float
93+ condition (for each signal) . Shape is (number_of_components, number_of_signals ).
94+ rho : float Optional Default = 0
9495 The stretching factor that influences the decomposition. Zero corresponds to no
9596 stretching present. Relatively insensitive and typically adjusted in powers of 10.
96- eta : float
97+ eta : int Optional Default = 0
9798 The sparsity factor that influences the decomposition. Should be set to zero for
9899 non-sparse data such as PDF. Can be used to improve results for sparse data such
99100 as XRD, but due to instability, should be used only after first selecting the
100101 best value for rho. Suggested adjustment is by powers of 2.
101- max_iter : int
102+ max_iter : int Optional Default = 500
102103 The maximum number of times to update each of A, X, and Y before stopping
103104 the optimization.
104- tol : float
105+ tol : float Optional Default = 5e-7
105106 The convergence threshold. This is the minimum fractional improvement in the
106107 objective function to allow without terminating the optimization. Note that
107108 a minimum of 20 updates are run before this parameter is checked.
108- n_components : int
109+ n_components : int Optional Default = None
109110 The number of components to extract from source_matrix. Must be provided when and only when
110111 Y0 is not provided.
111- random_state : int
112+ random_state : int Optional Default = None
112113 The seed for the initial guesses at the matrices (A, X, and Y) created by
113114 the decomposition.
114115 """
@@ -157,10 +158,10 @@ def __init__(
157158 self .weights = np .maximum (0 , self .weights )
158159
159160 # Second-order spline: Tridiagonal (-2 on diagonal, 1 on sub/superdiagonals)
160- self .spline_smooth_operator = 0.25 * diags (
161+ self ._spline_smooth_operator = 0.25 * diags (
161162 [1 , - 2 , 1 ], offsets = [0 , 1 , 2 ], shape = (self .n_signals - 2 , self .n_signals )
162163 )
163- self .spline_smooth_penalty = self .spline_smooth_operator .T @ self .spline_smooth_operator
164+ self ._spline_smooth_penalty = self ._spline_smooth_operator .T @ self ._spline_smooth_operator
164165
165166 # Set up residual matrix, objective function, and history
166167 self .residuals = self .get_residual_matrix ()
@@ -173,7 +174,7 @@ def __init__(
173174 self .grad_components = np .zeros_like (self .components ) # Gradient of X (zeros for now)
174175 self ._prev_grad_components = np .zeros_like (self .components ) # Previous gradient of X (zeros for now)
175176
176- regularization_term = 0.5 * rho * np .linalg .norm (self .spline_smooth_operator @ self .stretch .T , "fro" ) ** 2
177+ regularization_term = 0.5 * rho * np .linalg .norm (self ._spline_smooth_operator @ self .stretch .T , "fro" ) ** 2
177178 sparsity_term = eta * np .sum (np .sqrt (self .components )) # Square root penalty
178179 print (
179180 f"Start, Objective function: { self .objective_function :.5e} "
@@ -185,7 +186,7 @@ def __init__(
185186 self .optimize_loop ()
186187 # Print diagnostics
187188 regularization_term = (
188- 0.5 * rho * np .linalg .norm (self .spline_smooth_operator @ self .stretch .T , "fro" ) ** 2
189+ 0.5 * rho * np .linalg .norm (self ._spline_smooth_operator @ self .stretch .T , "fro" ) ** 2
189190 )
190191 sparsity_term = eta * np .sum (np .sqrt (self .components )) # Square root penalty
191192 print (
@@ -333,7 +334,7 @@ def get_objective_function(self, residuals=None, stretch=None):
333334 if stretch is None :
334335 stretch = self .stretch
335336 residual_term = 0.5 * np .linalg .norm (residuals , "fro" ) ** 2
336- regularization_term = 0.5 * self .rho * np .linalg .norm (self .spline_smooth_operator @ stretch .T , "fro" ) ** 2
337+ regularization_term = 0.5 * self .rho * np .linalg .norm (self ._spline_smooth_operator @ stretch .T , "fro" ) ** 2
337338 sparsity_term = self .eta * np .sum (np .sqrt (self .components )) # Square root penalty
338339 # Final objective function value
339340 function = residual_term + regularization_term + sparsity_term
@@ -652,7 +653,7 @@ def regularize_function(self, stretch=None):
652653 )
653654 der_reshaped = np .asarray (tiled_derivative ).reshape ((self .n_signals , self .n_components ), order = "F" )
654655 func_grad = (
655- der_reshaped .T + self .rho * stretch @ self .spline_smooth_operator .T @ self .spline_smooth_operator
656+ der_reshaped .T + self .rho * stretch @ self ._spline_smooth_operator .T @ self ._spline_smooth_operator
656657 )
657658
658659 return reg_func , func_grad
0 commit comments