Skip to content

Commit 68e2894

Browse files
committed
Improving code style.
1 parent 1251dc7 commit 68e2894

File tree

2 files changed

+86
-87
lines changed

2 files changed

+86
-87
lines changed

pydmd/varprodmd.py

Lines changed: 73 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
"""
1818

1919
import warnings
20-
from typing import Any, Dict, Tuple, Union
20+
from typing import Any, Dict, Tuple, Union, Optional
21+
from types import MappingProxyType
2122
import numpy as np
2223
from scipy.optimize import OptimizeResult, least_squares
2324
from scipy.linalg import qr
@@ -26,35 +27,37 @@
2627
from .snapshots import Snapshots
2728

2829

29-
OPT_DEF_ARGS: Dict[str, Any] = { # pylint: disable=unused-variable
30-
"method": "trf",
31-
"tr_solver": "exact",
32-
"loss": "linear",
33-
"x_scale": "jac",
34-
"gtol": 1e-8,
35-
"xtol": 1e-8,
36-
"ftol": 1e-8,
37-
}
30+
OPT_DEF_ARGS = MappingProxyType(
31+
{
32+
"method": "trf",
33+
"tr_solver": "exact",
34+
"loss": "linear",
35+
"x_scale": "jac",
36+
"gtol": 1e-8,
37+
"xtol": 1e-8,
38+
"ftol": 1e-8,
39+
}
40+
)
3841

3942

40-
def __svht(
41-
sigma_svd: np.ndarray, # pylint: disable=unused-variable
43+
def _svht(
44+
sigma_svd: np.ndarray,
4245
rows: int,
4346
cols: int,
44-
sigma: float = None,
47+
sigma: Optional[float] = None,
4548
) -> int:
4649
"""
4750
Determine optimal rank for svd matrix approximation,
4851
based on https://arxiv.org/pdf/1305.5870.pdf.
4952
50-
:param sigma_svd: Diagonal matrix of "enonomy" SVD as 1d array.
53+
:param sigma_svd: Diagonal matrix of "enonomy" SVD as 1d array.
5154
:type sigma_svd: np.ndarray
5255
:param rows: Number of rows of original data matrix.
5356
:type cols: int
5457
:param cols: Number of columns of original data matrix.
5558
:type cols: int
5659
:param sigma: Signal noise level if known, defaults to None.
57-
:type sigma: float, optional
60+
:type sigma: Optional[float], optional
5861
:raises ValueError: sigma_svd must be a 1d-array else exception is raised.
5962
:return: Optimal rank.
6063
:rtype: int
@@ -95,7 +98,7 @@ def __svht(
9598
return rank[-1] + 1
9699

97100

98-
def __compute_rank(
101+
def _compute_rank(
99102
sigma_x: np.ndarray,
100103
rows: int,
101104
cols: int,
@@ -133,16 +136,16 @@ def __compute_rank(
133136
cumulative_energy = np.cumsum(sigma_x_square / sigma_x_square.sum())
134137
__rank = np.searchsorted(cumulative_energy, rank) + 1
135138
elif rank == 0:
136-
__rank = __svht(sigma_x, rows, cols, sigma)
139+
__rank = _svht(sigma_x, rows, cols, sigma)
137140
elif rank >= 1:
138141
__rank = int(rank)
139142
else:
140143
raise ValueError(f"Invalid rank specified, provided {rank}!")
141144
return min(__rank, sigma_x.size)
142145

143146

144-
def __compute_dmd_ev(
145-
x_current: np.ndarray, # pylint: disable=unused-variable
147+
def _compute_dmd_ev(
148+
x_current: np.ndarray,
146149
x_next: np.ndarray,
147150
rank: Union[float, int] = 0,
148151
) -> np.ndarray:
@@ -167,7 +170,7 @@ def __compute_dmd_ev(
167170
u_x, sigma_x, v_x_t = np.linalg.svd(
168171
x_current, full_matrices=False, hermitian=False
169172
)
170-
__rank = __compute_rank(
173+
__rank = _compute_rank(
171174
sigma_x, x_current.shape[0], x_current.shape[1], rank
172175
)
173176

@@ -185,7 +188,7 @@ def __compute_dmd_ev(
185188
return np.linalg.eigvals(a_approx)
186189

187190

188-
class __OptimizeHelper: # pylint: disable=too-few-public-methods
191+
class _OptimizeHelper: # pylint: disable=too-few-public-methods
189192
"""
190193
Helper Class to store intermediate results during the optimization.
191194
"""
@@ -201,11 +204,11 @@ def __init__(self, l_in: int, m_in: int, n_in: int) -> None:
201204
self.rho: np.ndarray = np.empty((m_in, n_in), dtype=np.complex128)
202205

203206

204-
def __compute_dmd_rho(
207+
def _compute_dmd_rho(
205208
alphas: np.ndarray,
206209
time: np.ndarray,
207210
data: np.ndarray,
208-
opthelper: __OptimizeHelper,
211+
opthelper: _OptimizeHelper,
209212
) -> np.ndarray:
210213
r"""
211214
Compute the real residual vector :math:`\boldsymbol{\rho}` for
@@ -223,7 +226,7 @@ def __compute_dmd_rho(
223226
:type data: np.ndarray
224227
:param opthelper: Optimization helper to speed up computations
225228
mainly for Jacobian.
226-
:type opthelper: __OptimizeHelper
229+
:type opthelper: _OptimizeHelper
227230
:return: 1d residual vector for Levenberg-Marquardt update
228231
:math:`\boldsymbol{\rho} \in \mathbb{R}^{2mn}`.
229232
:rtype: np.ndarray
@@ -234,37 +237,37 @@ def __compute_dmd_rho(
234237
__alphas.imag = alphas[alphas.shape[-1] // 2 :]
235238

236239
phi = np.exp(np.outer(time, __alphas))
237-
__u, __s, __v_t = np.linalg.svd(phi, hermitian=False, full_matrices=False)
238-
__idx = np.where(__s.real != 0.0)[0]
239-
__s_inv = np.zeros_like(__s)
240-
__s_inv[__idx] = np.reciprocal(__s[__idx])
240+
u_phi, s_phi, v_phi_t = np.linalg.svd(phi, full_matrices=False)
241+
idx = np.where(s_phi.real != 0.0)[0]
242+
s_phi_inv = np.zeros_like(s_phi)
243+
s_phi_inv[idx] = np.reciprocal(s_phi[idx])
241244

242-
rho = data - np.linalg.multi_dot([__u, __u.conj().T, data])
245+
rho = data - np.linalg.multi_dot([u_phi, u_phi.conj().T, data])
243246
rho_flat = np.ravel(rho)
244247
rho_out = np.zeros((2 * rho_flat.shape[-1],), dtype=np.float64)
245248
rho_out[: rho_flat.shape[-1]] = rho_flat.real
246249
rho_out[rho_flat.shape[-1] :] = rho_flat.imag
247250

248251
opthelper.phi = phi
249-
opthelper.u_svd = __u
250-
opthelper.s_inv = __s_inv
251-
opthelper.v_svd = __v_t.conj().T
252+
opthelper.u_svd = u_phi
253+
opthelper.s_inv = s_phi_inv
254+
opthelper.v_svd = v_phi_t.conj().T
252255
opthelper.rho = rho
253256
opthelper.b_matrix = np.linalg.multi_dot(
254257
[
255-
opthelper.v_svd * __s_inv.reshape((1, -1)),
258+
opthelper.v_svd * s_phi_inv[None],
256259
opthelper.u_svd.conj().T,
257260
data,
258261
]
259262
)
260263
return rho_out
261264

262265

263-
def __compute_dmd_jac(
266+
def _compute_dmd_jac(
264267
alphas: np.ndarray,
265268
time: np.ndarray,
266269
data: np.ndarray,
267-
opthelper: __OptimizeHelper,
270+
opthelper: _OptimizeHelper,
268271
) -> np.ndarray:
269272
r"""
270273
Compute the real Jacobian.
@@ -282,8 +285,8 @@ def __compute_dmd_jac(
282285
For DMD computation we set :math:`\boldsymbol{Y} = \boldsymbol{X}^T`.
283286
:type data: np.ndarray
284287
:param opthelper: Optimization helper to speed up computations
285-
mainly for Jacobian. The entities are computed in `__compute_dmd_rho`.
286-
:type opthelper: __OptimizeHelper
288+
mainly for Jacobian. The entities are computed in `_compute_dmd_rho`.
289+
:type opthelper: _OptimizeHelper
287290
:return: Jacobian :math:`\boldsymbol{J} \in \mathbb{R}^{mn \times 2l}`.
288291
:rtype: np.ndarray
289292
"""
@@ -295,42 +298,40 @@ def __compute_dmd_jac(
295298

296299
for j in range(__alphas.shape[-1]):
297300
d_phi_j = time * opthelper.phi[:, j]
298-
__outer = np.outer(d_phi_j, opthelper.b_matrix[j, :])
299-
__a_j = __outer - np.linalg.multi_dot(
300-
[opthelper.u_svd, opthelper.u_svd.conj().T, __outer]
301+
outer = np.outer(d_phi_j, opthelper.b_matrix[j])
302+
a_j = outer - np.linalg.multi_dot(
303+
[opthelper.u_svd, opthelper.u_svd.conj().T, outer]
301304
)
302-
__g_j = np.linalg.multi_dot(
305+
g_j = np.linalg.multi_dot(
303306
[
304-
opthelper.u_svd * opthelper.s_inv.reshape((1, -1)),
307+
opthelper.u_svd * opthelper.s_inv[None],
305308
np.outer(
306309
opthelper.v_svd[j, :].conj(), d_phi_j.conj() @ opthelper.rho
307310
),
308311
]
309312
)
310313
# Compute the jacobian J_mat_j = - (A_j + G_j).
311-
__jac = -__a_j - __g_j
312-
__jac_flat = np.ravel(__jac)
314+
jac = -a_j - g_j
315+
jac_flat = np.ravel(jac)
313316

314317
# construct the overall jacobian for optimized
315318
# J_real = |Re{J} -Im{J}|
316319
# |Im{J} Re{J}|
317320

318321
# construct real part for optimization
319-
jac_out[: jac_out.shape[0] // 2, j] = __jac_flat.real
320-
jac_out[jac_out.shape[0] // 2 :, j] = __jac_flat.imag
322+
jac_out[: jac_out.shape[0] // 2, j] = jac_flat.real
323+
jac_out[jac_out.shape[0] // 2 :, j] = jac_flat.imag
321324

322325
# construct imaginary part for optimization
323326
jac_out[
324327
: jac_out.shape[0] // 2, __alphas.shape[-1] + j
325-
] = -__jac_flat.imag
326-
jac_out[
327-
jac_out.shape[0] // 2 :, __alphas.shape[-1] + j
328-
] = __jac_flat.real
328+
] = -jac_flat.imag
329+
jac_out[jac_out.shape[0] // 2 :, __alphas.shape[-1] + j] = jac_flat.real
329330

330331
return jac_out
331332

332333

333-
def __varpro_preprocessing(
334+
def _varpro_preprocessing(
334335
data: np.ndarray,
335336
time: np.ndarray,
336337
rank: Union[float, int] = 0.0,
@@ -368,25 +369,25 @@ def __varpro_preprocessing(
368369
"""
369370

370371
u_r, s_r, v_r_t = np.linalg.svd(data, full_matrices=False)
371-
__rank = __compute_rank(s_r, data.shape[0], data.shape[1], rank)
372+
__rank = _compute_rank(s_r, data.shape[0], data.shape[1], rank)
372373
u_r = u_r[:, :__rank]
373374
s_r = s_r[:__rank]
374-
v_r = v_r_t[:__rank, :].conj().T
375-
data_out = v_r.conj().T * s_r.reshape((-1, 1)) if use_proj else data
375+
v_r = v_r_t[:__rank].conj().T
376+
data_out = v_r.conj().T * s_r[:, None] if use_proj else data
376377

377378
# trapezoidal derivative approximation
378379
y_out = (data_out[:, :-1] + data_out[:, 1:]) / 2.0
379380
dt_in = time[1:] - time[:-1]
380-
z_out = (data_out[:, 1:] - data_out[:, :-1]) / dt_in.reshape((1, -1))
381+
z_out = (data_out[:, 1:] - data_out[:, :-1]) / dt_in[None]
381382

382383
return z_out, y_out, data_out, u_r
383384

384385

385-
def __compute_dmd_varpro(
386+
def _compute_dmd_varpro(
386387
alphas_init: np.ndarray,
387388
time: np.ndarray,
388389
data: np.ndarray,
389-
opthelper: __OptimizeHelper,
390+
opthelper: _OptimizeHelper,
390391
**optargs,
391392
) -> OptimizeResult:
392393
r"""
@@ -400,17 +401,17 @@ def __compute_dmd_varpro(
400401
For DMD computation we set :math:`\boldsymbol{Y} = \boldsymbol{X}^T`.
401402
:type data: np.ndarray
402403
:param opthelper: Optimization helper to speed up computations
403-
mainly for Jacobian. The entities are computed in `__compute_dmd_rho`
404-
and are used in `__compute_dmd_jac`.
405-
:type opthelper: __OptimizeHelper
404+
mainly for Jacobian. The entities are computed in `_compute_dmd_rho`
405+
and are used in `_compute_dmd_jac`.
406+
:type opthelper: _OptimizeHelper
406407
:return: Optimization result.
407408
:rtype: OptimizeResult
408409
"""
409410

410411
return least_squares(
411-
__compute_dmd_rho,
412+
_compute_dmd_rho,
412413
alphas_init,
413-
__compute_dmd_jac,
414+
_compute_dmd_jac,
414415
**optargs,
415416
args=[time, data, opthelper],
416417
)
@@ -442,8 +443,8 @@ def select_best_samples_fast(data: np.ndarray, comp: float = 0.9) -> np.ndarray:
442443

443444
n_samples = int(data.shape[-1] * (1.0 - comp))
444445
pcolumn = qr(data, mode="economic", pivoting=True)[-1]
445-
__idx = pcolumn[:n_samples]
446-
return __idx
446+
447+
return pcolumn[:n_samples]
447448

448449

449450
def compute_varprodmd_any( # pylint: disable=unused-variable
@@ -501,8 +502,8 @@ def compute_varprodmd_any( # pylint: disable=unused-variable
501502
raise ValueError("time needs to be a 1D array")
502503

503504
# y_in, z_in, data_in, u_r
504-
res = __varpro_preprocessing(data, time, rank, use_proj)
505-
omegas = __compute_dmd_ev(res[0], res[1], res[-1].shape[-1])
505+
res = _varpro_preprocessing(data, time, rank, use_proj)
506+
omegas = _compute_dmd_ev(res[0], res[1], res[-1].shape[-1])
506507

507508
if compression > 0:
508509
indices = select_best_samples_fast(res[2], compression)
@@ -523,8 +524,8 @@ def compute_varprodmd_any( # pylint: disable=unused-variable
523524
)
524525
)
525526

526-
opthelper = __OptimizeHelper(res[-1].shape[-1], *res[2].shape)
527-
opt = __compute_dmd_varpro(
527+
opthelper = _OptimizeHelper(res[-1].shape[-1], *res[2].shape)
528+
opt = _compute_dmd_varpro(
528529
np.concatenate([omegas.real, omegas.imag]),
529530
time[indices],
530531
res[2][:, indices].T,
@@ -535,10 +536,10 @@ def compute_varprodmd_any( # pylint: disable=unused-variable
535536
omegas.imag = opt.x[opt.x.shape[-1] // 2 :]
536537
xi = res[-1] @ opthelper.b_matrix.T if use_proj else opthelper.b_matrix.T
537538
eigenf = np.linalg.norm(xi, axis=0)
538-
return xi / eigenf.reshape((1, -1)), omegas, eigenf, indices, opt
539+
return xi / eigenf[None], omegas, eigenf, indices, opt
539540

540541

541-
def optdmd_predict( # pylint: disable=unused-variable
542+
def optdmd_predict(
542543
phi: np.ndarray,
543544
omegas: np.ndarray,
544545
eigenf: np.ndarray,
@@ -565,7 +566,7 @@ def optdmd_predict( # pylint: disable=unused-variable
565566
:rtype: np.ndarray
566567
"""
567568

568-
return phi @ (np.exp(np.outer(omegas, time)) * eigenf.reshape(-1, 1))
569+
return phi @ (np.exp(np.outer(omegas, time)) * eigenf[:, None])
569570

570571

571572
class VarProOperator(DMDOperator):
@@ -927,7 +928,7 @@ def dynamics(self):
927928
"""
928929

929930
t_omega = np.exp(np.outer(self.eigs, self._original_time))
930-
return self.amplitudes.reshape(-1, 1) * t_omega
931+
return self.amplitudes[:, None] * t_omega
931932

932933
@property
933934
def frequency(self):

0 commit comments

Comments
 (0)