prtools 1.3.0__tar.gz → 1.3.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. {prtools-1.3.0/prtools.egg-info → prtools-1.3.2}/PKG-INFO +1 -1
  2. {prtools-1.3.0 → prtools-1.3.2}/prtools/__init__.py +4 -2
  3. {prtools-1.3.0 → prtools-1.3.2}/prtools/array.py +5 -4
  4. prtools-1.3.0/prtools/_backend.py → prtools-1.3.2/prtools/backend/__init__.py +42 -10
  5. prtools-1.3.2/prtools/backend/_base.py +7 -0
  6. prtools-1.3.2/prtools/backend/_jax.py +49 -0
  7. prtools-1.3.2/prtools/backend/_numpy.py +13 -0
  8. {prtools-1.3.0 → prtools-1.3.2}/prtools/cost.py +1 -1
  9. {prtools-1.3.0 → prtools-1.3.2}/prtools/fourier.py +1 -4
  10. prtools-1.3.2/prtools/jax.py +114 -0
  11. {prtools-1.3.0 → prtools-1.3.2}/prtools/misc.py +2 -2
  12. {prtools-1.3.0 → prtools-1.3.2}/prtools/segmented.py +1 -1
  13. {prtools-1.3.0 → prtools-1.3.2}/prtools/shape.py +1 -1
  14. {prtools-1.3.0 → prtools-1.3.2}/prtools/stats.py +1 -1
  15. {prtools-1.3.0 → prtools-1.3.2}/prtools/zernike.py +1 -1
  16. {prtools-1.3.0 → prtools-1.3.2/prtools.egg-info}/PKG-INFO +1 -1
  17. {prtools-1.3.0 → prtools-1.3.2}/prtools.egg-info/SOURCES.txt +7 -2
  18. {prtools-1.3.0 → prtools-1.3.2}/pyproject.toml +0 -3
  19. prtools-1.3.2/tests/test_array.py +67 -0
  20. prtools-1.3.2/tests/test_fourier.py +95 -0
  21. prtools-1.3.0/tests/test_array.py +0 -45
  22. {prtools-1.3.0 → prtools-1.3.2}/LICENSE +0 -0
  23. {prtools-1.3.0 → prtools-1.3.2}/NOTICE +0 -0
  24. {prtools-1.3.0 → prtools-1.3.2}/README.rst +0 -0
  25. {prtools-1.3.0 → prtools-1.3.2}/prtools/sparse.py +0 -0
  26. {prtools-1.3.0 → prtools-1.3.2}/prtools.egg-info/dependency_links.txt +0 -0
  27. {prtools-1.3.0 → prtools-1.3.2}/prtools.egg-info/requires.txt +0 -0
  28. {prtools-1.3.0 → prtools-1.3.2}/prtools.egg-info/top_level.txt +0 -0
  29. {prtools-1.3.0 → prtools-1.3.2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: prtools
3
- Version: 1.3.0
3
+ Version: 1.3.2
4
4
  Summary: Utility functions for image-based phase retrieval
5
5
  Author: Andy Kee
6
6
  License: MIT License
@@ -1,6 +1,6 @@
1
- __version__ = '1.3.0'
1
+ __version__ = '1.3.2'
2
2
 
3
- from prtools._backend import __backend__, use
3
+ from prtools.backend import __backend__, use
4
4
 
5
5
  from prtools.array import (
6
6
  centroid,
@@ -19,6 +19,8 @@ from prtools.cost import sserror
19
19
 
20
20
  from prtools.fourier import dft2, idft2
21
21
 
22
+ import prtools.jax
23
+
22
24
  from prtools.misc import (
23
25
  calcpsf,
24
26
  translation_defocus,
@@ -1,8 +1,8 @@
1
1
  import warnings
2
2
 
3
3
  from prtools import __backend__
4
- from prtools._backend import numpy as np
5
- from prtools._backend import scipy
4
+ from prtools.backend import numpy as np
5
+ from prtools.backend import scipy
6
6
 
7
7
 
8
8
  def centroid(a, where=None, kind='absolute', indexing='ij'):
@@ -265,8 +265,9 @@ def boundary(x, threshold=0):
265
265
  rows = np.any(x, axis=1)
266
266
  cols = np.any(x, axis=0)
267
267
 
268
- rmin, rmax = np.where(rows)[0][[0, -1]]
269
- cmin, cmax = np.where(cols)[0][[0, -1]]
268
+ idx = np.array((0, -1)) # https://github.com/andykee/prtools/issues/6
269
+ rmin, rmax = np.where(rows)[0][idx]
270
+ cmin, cmax = np.where(cols)[0][idx]
270
271
 
271
272
  return rmin, rmax, cmin, cmax
272
273
 
@@ -1,12 +1,22 @@
1
+ import importlib
1
2
  import sys
2
3
  import types
3
4
 
4
- from prtools.backend import registry
5
- from prtools.backend._base import _BackendLibrary
5
+ from ._base import BackendLibrary
6
6
 
7
7
 
8
- class _BackendName:
9
- """Helper class for storing the backend name - needed since strings are
8
+ def backend_available(name):
9
+ """Return True if backend library is available"""
10
+ try:
11
+ importlib.import_module(name)
12
+ except ImportError:
13
+ return False
14
+ else:
15
+ return True
16
+
17
+
18
+ class BackendName:
19
+ """Helper class for changing the backend name - needed since strings are
10
20
  immutable.
11
21
  """
12
22
 
@@ -23,10 +33,32 @@ class _BackendName:
23
33
  return self.name == other
24
34
 
25
35
 
26
- class _Backend(types.ModuleType):
27
- __backend__ = _BackendName(None)
28
- numpy = _BackendLibrary(None)
29
- scipy = _BackendLibrary(None)
36
+ class BackendRegistry:
37
+
38
+ _BUILTIN_BACKEND = ['numpy', 'jax']
39
+
40
+ def _get_backend_module(self, backend):
41
+ return importlib.import_module(f'._{backend}', 'prtools.backend')
42
+
43
+ def load_numpy(self, backend):
44
+ backend = self._get_backend_module(backend)
45
+ return backend.Numpy()
46
+
47
+ def load_scipy(self, backend):
48
+ return self._get_backend_module(backend).Scipy()
49
+
50
+
51
+ registry = BackendRegistry()
52
+
53
+ class Backend(types.ModuleType):
54
+
55
+ numpy = BackendLibrary(None)
56
+ scipy = BackendLibrary(None)
57
+
58
+ __backend__ = BackendName(None)
59
+
60
+ JAX_AVAILABLE = backend_available('jax') & backend_available('optax')
61
+ NUMPY_AVAILABLE = backend_available('numpy')
30
62
 
31
63
  @classmethod
32
64
  def use(cls, backend):
@@ -67,7 +99,7 @@ class _Backend(types.ModuleType):
67
99
 
68
100
 
69
101
  # use NumPy by default
70
- _Backend.use('numpy')
102
+ Backend.use('numpy')
71
103
 
72
104
  # https://stackoverflow.com/a/72911884
73
- sys.modules[__name__].__class__ = _Backend
105
+ sys.modules[__name__].__class__ = Backend
@@ -0,0 +1,7 @@
1
+
2
+ class BackendLibrary:
3
+ def __init__(self, module):
4
+ self.module = module
5
+
6
+ def __getattr__(self, name):
7
+ return getattr(self.module, name)
@@ -0,0 +1,49 @@
1
+ import importlib
2
+
3
+ from ._base import BackendLibrary
4
+
5
+
6
+ class Numpy(BackendLibrary):
7
+ def __init__(self):
8
+ super().__init__(importlib.import_module('jax.numpy'))
9
+
10
+ def broadcast_to(self, array, shape):
11
+ # jax numpy.broadcast_to expects an array input
12
+ array = self.module.asarray(array)
13
+ return self.module.broadcast_to(array, shape)
14
+
15
+ def divide(self, a, b, out=None):
16
+ # jax.numpy.divide doesn't support the `out` parameter so we
17
+ # ignore it
18
+ return self.module.divide(a, b)
19
+
20
+ def dot(self, a, b, out=None):
21
+ # jax.numpy.dot doesn't support the `out` parameter so we ignore it
22
+ return self.module.dot(a, b)
23
+
24
+ def floor(self, x, *args, **kwargs):
25
+ # jax numpy.floor expects a scalar or array input. It also doesn't
26
+ # support the `out` parameter
27
+ kwargs.pop('out', None)
28
+ x = self.module.asarray(x)
29
+ return self.module.floor(x, *args, **kwargs)
30
+
31
+ def max(self, a, *args, **kwargs):
32
+ # jax numpy.max expects an array input
33
+ array = self.module.asarray(a)
34
+ return self.module.max(array, *args, **kwargs)
35
+
36
+ def multiply(self, a, b, out=None):
37
+ # jax.numpy.multiply doesn't support the `out` parameter so we
38
+ # ignore it
39
+ return self.module.multiply(a, b)
40
+
41
+ def sum(self, a, *args, **kwargs):
42
+ kwargs.pop('out', None)
43
+ a = self.module.asarray(a)
44
+ return self.module.sum(a, *args, **kwargs)
45
+
46
+
47
+ class Scipy(BackendLibrary):
48
+ def __init__(self):
49
+ super().__init__(importlib.import_module('jax.scipy'))
@@ -0,0 +1,13 @@
1
+ from ._base import BackendLibrary
2
+
3
+
4
+ class Numpy(BackendLibrary):
5
+ def __init__(self):
6
+ import numpy
7
+ super().__init__(numpy)
8
+
9
+
10
+ class Scipy(BackendLibrary):
11
+ def __init__(self):
12
+ import scipy
13
+ super().__init__(scipy)
@@ -1,4 +1,4 @@
1
- from prtools._backend import numpy as np
1
+ from prtools.backend import numpy as np
2
2
 
3
3
 
4
4
  def sserror(data, est, mask=None, gain_bias_invariant=False, ghat=None):
@@ -1,7 +1,5 @@
1
- import functools
2
-
3
1
  from prtools import __backend__
4
- from prtools._backend import numpy as np
2
+ from prtools.backend import numpy as np
5
3
 
6
4
 
7
5
  def dft2(f, alpha, shape=None, shift=(0, 0), offset=(0, 0), unitary=True,
@@ -137,7 +135,6 @@ def _idft2_matrices(m, n, M, N, alphar, alphac, shiftr, shiftc, offsetr, offsetc
137
135
  return E1, E2
138
136
 
139
137
 
140
- @functools.lru_cache(maxsize=32)
141
138
  def _dft2_coords(m, n, M, N):
142
139
  # R and S are (r,c) coordinates in the (m x n) input plane f
143
140
  # V and U are (r,c) coordinates in the (M x N) output plane F
@@ -0,0 +1,114 @@
1
+ from dataclasses import dataclass
2
+ from typing import Any
3
+
4
+ from prtools import __backend__
5
+ from prtools.backend import JAX_AVAILABLE
6
+
7
+ if JAX_AVAILABLE:
8
+ import jax
9
+ import optax
10
+ import optax.tree_utils as otu
11
+
12
+
13
+ def register_dataclass(cls):
14
+ if JAX_AVAILABLE:
15
+ data_fields = ['x', 'n', 'grad', 'value', 'state']
16
+ meta_fields = []
17
+ cls = jax.tree_util.register_dataclass(cls,
18
+ data_fields=data_fields,
19
+ meta_fields=meta_fields)
20
+ return cls
21
+
22
+
23
+ @register_dataclass
24
+ @dataclass
25
+ class JaxOptimizeResult:
26
+ """Represents the optimization result."""
27
+ x: Any #: The solution of the optimization
28
+ n: Any #: Number of iterations performed by the optimizer
29
+ value: Any #: Value of objective function at x
30
+ grad: Any #: Value of objective function gradient at x
31
+ state: Any #: Optimizer state
32
+
33
+
34
+ def lbfgs(fun, x0, gtol=None, maxiter=None, callback=None):
35
+ """Minimize a scalar function of one or more variables using the L-BFGS
36
+ algorithm
37
+
38
+ Parameters
39
+ ----------
40
+ fun : callable
41
+ The objective function to be minimied
42
+ x0 : jax.Array
43
+ Initial guess
44
+ gtol : float
45
+ Iteration stops when ``l2_norm(grad) <= gtol``
46
+ maxiter : int
47
+ Maximum number of iterations
48
+ callback : callable, optional
49
+ A callable called after each iteration with the signature
50
+
51
+ .. code:: python
52
+
53
+ callback(intermediate_result: JaxOptimizeResult)
54
+
55
+ where ``intermediate_result`` is a :class:`JaxOptimizeResult`.
56
+
57
+ Returns
58
+ -------
59
+ res: JaxOptimizeResult
60
+ The optimization result. See :class:`JaxOptimizeResult` for a
61
+ description of attributes.
62
+
63
+ """
64
+ if not JAX_AVAILABLE:
65
+ message = "jax and optax must be installed to use method `lbfgs`."
66
+ raise ModuleNotFoundError(message)
67
+
68
+ if __backend__ != 'jax':
69
+ raise RuntimeError('JAX backend must be selected')
70
+
71
+ if not any((gtol, maxiter)):
72
+ raise ValueError('At least one termination tolerance must be specified.')
73
+
74
+ opt = optax.lbfgs()
75
+ value_and_grad_fun = optax.value_and_grad_from_state(fun)
76
+
77
+ def step(carry):
78
+ params, state = carry
79
+ value, grad = value_and_grad_fun(params, state=state)
80
+ updates, state = opt.update(
81
+ grad, state, params, value=value, grad=grad, value_fn=fun)
82
+ if callback:
83
+ res = JaxOptimizeResult(
84
+ n=otu.tree_get(state, 'count')-1,
85
+ x=params,
86
+ grad=grad,
87
+ value=value,
88
+ state=state)
89
+ jax.debug.callback(callback, res)
90
+ params = optax.apply_updates(params, updates)
91
+ return params, state
92
+
93
+ def continuing_criterion(carry):
94
+ _, state = carry
95
+ iter_num = otu.tree_get(state, 'count')
96
+ grad = otu.tree_get(state, 'grad')
97
+ grad_norm = otu.tree_l2_norm(grad)
98
+ return (iter_num == 0) | ((iter_num < maxiter) & (grad_norm >= gtol))
99
+
100
+ init_carry = (x0, opt.init(x0))
101
+ final_params, final_state = jax.lax.while_loop(
102
+ continuing_criterion, step, init_carry)
103
+
104
+ res = JaxOptimizeResult(
105
+ n=otu.tree_get(final_state, 'count'),
106
+ x=final_params,
107
+ grad=otu.tree_get(final_state, 'grad'),
108
+ value=otu.tree_get(final_state, 'value'),
109
+ state=final_state)
110
+
111
+ if callback:
112
+ jax.debug.callback(callback, res)
113
+
114
+ return res
@@ -1,5 +1,5 @@
1
1
  import prtools
2
- from prtools._backend import numpy as np
2
+ from prtools.backend import numpy as np
3
3
 
4
4
 
5
5
  def calcpsf(amp, opd, wavelength, sampling, shape, oversample=2,
@@ -18,7 +18,7 @@ def calcpsf(amp, opd, wavelength, sampling, shape, oversample=2,
18
18
  Propagation sampling term defined as
19
19
 
20
20
  .. math::
21
- \mbox{sampling} = \\frac{dx \ du}{z}
21
+ \mbox{sampling} = \frac{dx \ du}{z}
22
22
 
23
23
  where *dx* is the pupil plane spatial sampling, *du* is the image
24
24
  plane spatial sampling, and *z* is the propagation distance. If a
@@ -1,7 +1,7 @@
1
1
  import collections
2
2
 
3
3
  import prtools
4
- from prtools._backend import numpy as np
4
+ from prtools.backend import numpy as np
5
5
 
6
6
 
7
7
  def hex_segments(rings, seg_radius, seg_gap, rotate=False, antialias=True,
@@ -1,5 +1,5 @@
1
1
  from prtools import __backend__
2
- from prtools._backend import numpy as np
2
+ from prtools.backend import numpy as np
3
3
 
4
4
 
5
5
  def mesh(shape, shift=(0, 0), angle=0, indexing='ij'):
@@ -1,5 +1,5 @@
1
1
  import prtools
2
- from prtools._backend import numpy as np
2
+ from prtools.backend import numpy as np
3
3
 
4
4
 
5
5
  def ee(a, energy=0.8, center=None):
@@ -1,7 +1,7 @@
1
1
  from math import factorial
2
2
 
3
3
  import prtools
4
- from prtools._backend import numpy as np
4
+ from prtools.backend import numpy as np
5
5
 
6
6
 
7
7
  def zernike(mask, index, normalize=True, rho=None, theta=None):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: prtools
3
- Version: 1.3.0
3
+ Version: 1.3.2
4
4
  Summary: Utility functions for image-based phase retrieval
5
5
  Author: Andy Kee
6
6
  License: MIT License
@@ -3,10 +3,10 @@ NOTICE
3
3
  README.rst
4
4
  pyproject.toml
5
5
  prtools/__init__.py
6
- prtools/_backend.py
7
6
  prtools/array.py
8
7
  prtools/cost.py
9
8
  prtools/fourier.py
9
+ prtools/jax.py
10
10
  prtools/misc.py
11
11
  prtools/segmented.py
12
12
  prtools/shape.py
@@ -18,4 +18,9 @@ prtools.egg-info/SOURCES.txt
18
18
  prtools.egg-info/dependency_links.txt
19
19
  prtools.egg-info/requires.txt
20
20
  prtools.egg-info/top_level.txt
21
- tests/test_array.py
21
+ prtools/backend/__init__.py
22
+ prtools/backend/_base.py
23
+ prtools/backend/_jax.py
24
+ prtools/backend/_numpy.py
25
+ tests/test_array.py
26
+ tests/test_fourier.py
@@ -36,8 +36,5 @@ Documentation = "https://andykee.github.io/prtools/"
36
36
  [project.optional-dependencies]
37
37
  jax = ["jax", "optax"]
38
38
 
39
- [tool.setuptools]
40
- packages = ["prtools"]
41
-
42
39
  [tool.setuptools.dynamic]
43
40
  version = {attr = "prtools.__version__"}
@@ -0,0 +1,67 @@
1
+ import warnings
2
+
3
+ import numpy as np
4
+ import pytest
5
+
6
+ import prtools
7
+ from .import BACKENDS
8
+
9
+
10
+ @pytest.mark.parametrize('backend', BACKENDS)
11
+ def test_centroid(backend):
12
+ prtools.use(backend)
13
+ x = np.zeros((5, 5))
14
+ x[2, 2] = 1
15
+ assert np.array_equal(prtools.centroid(x), [2, 2])
16
+
17
+
18
+ @pytest.mark.parametrize('backend', BACKENDS)
19
+ def test_centroid_where(backend):
20
+ prtools.use(backend)
21
+ x = np.zeros((5, 5))
22
+ x[2, 2] = 1
23
+ x[1, 1] = 1
24
+ mask = np.ones_like(x)
25
+ mask[1, 1] = 0
26
+ assert np.array_equal(prtools.centroid(x, where=mask), [2, 2])
27
+
28
+
29
+ @pytest.mark.parametrize('backend', BACKENDS)
30
+ def test_centroid_nan(backend):
31
+ prtools.use(backend)
32
+ x = np.zeros((5, 5))
33
+ x[2, 2] = 1
34
+ x[2, 3] = np.nan
35
+ assert np.array_equal(prtools.centroid(x), [2, 2])
36
+
37
+
38
+ x, _ = np.meshgrid(range(10), range(10))
39
+ x[2, 2] = 100
40
+
41
+
42
+ @pytest.mark.parametrize('backend', BACKENDS)
43
+ def test_medfix(backend):
44
+ prtools.use(backend)
45
+ m = np.zeros_like(x)
46
+ m[2, 2] = 1
47
+ y = prtools.medfix(x, mask=m, kernel=(3, 3))
48
+ assert y[2, 2] == 2
49
+
50
+
51
+ @pytest.mark.parametrize('backend', BACKENDS)
52
+ def test_medfix_bigmask(backend):
53
+ prtools.use(backend)
54
+ m = np.zeros_like(x)
55
+ m[2:6, 2:6] = 1
56
+ with warnings.catch_warnings():
57
+ warnings.simplefilter('error')
58
+ y = prtools.medfix(x, mask=m, kernel=(3, 3))
59
+ assert np.all(np.isnan(y[3:5, 3:5]))
60
+
61
+
62
+ @pytest.mark.parametrize('backend', BACKENDS)
63
+ def test_boundary(backend):
64
+ prtools.use(backend)
65
+ x = np.zeros((10, 10))
66
+ x[3:7, 2:8] = 1
67
+ assert np.array_equal(prtools.boundary(x), (3, 6, 2, 7))
@@ -0,0 +1,95 @@
1
+ import numpy as np
2
+ import pytest
3
+
4
+ import prtools
5
+ from .import BACKENDS
6
+
7
+
8
+ @pytest.mark.parametrize('backend', BACKENDS)
9
+ def test_dft2_even(backend):
10
+ prtools.use(backend)
11
+ n = 10
12
+ f = np.random.rand(n, n) + 1j * np.random.rand(n, n)
13
+
14
+ F_dft = prtools.dft2(f, 1/n, unitary=False)
15
+ F_fft = np.fft.fftshift(np.fft.fft2(np.fft.ifftshift(f)))
16
+
17
+ assert np.allclose(F_dft, F_fft, atol=1e-5)
18
+
19
+
20
+ @pytest.mark.parametrize('backend', BACKENDS)
21
+ def test_idft2_even(backend):
22
+ prtools.use(backend)
23
+ n = 10
24
+ F = np.random.rand(n, n) + 1j * np.random.rand(n, n)
25
+
26
+ f_dft = prtools.idft2(F, 1/n, unitary=False)
27
+ f_fft = np.fft.fftshift(np.fft.ifft2(np.fft.ifftshift(F)))
28
+
29
+ assert np.allclose(f_dft, f_fft, atol=1e-5)
30
+
31
+
32
+ @pytest.mark.parametrize('backend', BACKENDS)
33
+ def test_dft2_odd(backend):
34
+ prtools.use(backend)
35
+ n = 11
36
+ f = np.random.rand(n, n) + 1j * np.random.rand(n, n)
37
+
38
+ F_dft = prtools.dft2(f, 1/n, unitary=False)
39
+ F_fft = np.fft.fftshift(np.fft.fft2(np.fft.ifftshift(f)))
40
+
41
+ print(F_dft.dtype)
42
+ print(F_fft.dtype)
43
+ assert np.allclose(F_dft, F_fft, atol=1e-5)
44
+
45
+
46
+ @pytest.mark.parametrize('backend', BACKENDS)
47
+ def test_idft2_odd(backend):
48
+ prtools.use(backend)
49
+ n = 11
50
+ F = np.random.rand(n, n) + 1j * np.random.rand(n, n)
51
+
52
+ f_dft = prtools.idft2(F, 1/n, unitary=False)
53
+ f_fft = np.fft.fftshift(np.fft.ifft2(np.fft.ifftshift(F)))
54
+
55
+ assert np.allclose(f_dft, f_fft, atol=1e-5)
56
+
57
+
58
+ @pytest.mark.parametrize('backend', BACKENDS)
59
+ def test_dft2_unitary(backend):
60
+ prtools.use(backend)
61
+ n = 10
62
+ f = np.random.rand(n, n) + 1j * np.random.rand(n, n)
63
+ f_power = np.sum(np.abs(f)**2)
64
+
65
+ F = prtools.dft2(f, 1/n, unitary=True)
66
+ F_power = np.sum(np.abs(F)**2)
67
+
68
+ assert np.allclose(f_power, F_power)
69
+
70
+
71
+ @pytest.mark.parametrize('backend', BACKENDS)
72
+ def test_dft2_shift(backend):
73
+ prtools.use(backend)
74
+ n = 100
75
+ shift = np.round(np.random.uniform(low=-25, high=25, size=2))
76
+ f = np.ones((n, n))
77
+
78
+ F = prtools.dft2(f, 1/n, shift=shift)
79
+
80
+ (xc, yc) = (np.floor(n/2), np.floor(n/2))
81
+ (x, y) = prtools.centroid(np.abs(F)**2)
82
+ observed_shift = (x-xc, y-yc)
83
+ assert np.array_equal(shift, observed_shift)
84
+
85
+
86
+ @pytest.mark.parametrize('backend', BACKENDS)
87
+ def test_dft2_rectangle(backend):
88
+ prtools.use(backend)
89
+ m, n = 10, 11
90
+ f = np.random.rand(m, n) + 1j * np.random.rand(m, n)
91
+
92
+ F_dft = prtools.dft2(f, [1/m, 1/n], unitary=False)
93
+ F_fft = np.fft.fftshift(np.fft.fft2(np.fft.ifftshift(f)))
94
+
95
+ assert np.allclose(F_dft, F_fft, atol=1e-5)
@@ -1,45 +0,0 @@
1
- import warnings
2
-
3
- import numpy as np
4
-
5
- import prtools
6
-
7
-
8
- def test_centroid():
9
- x = np.zeros((5,5))
10
- x[2,2] = 1
11
- assert(np.array_equal(prtools.centroid(x), [2,2]))
12
-
13
-
14
- def test_centroid_where():
15
- x = np.zeros((5,5))
16
- x[2,2] = 1
17
- x[1,1] = 1
18
- mask = np.ones_like(x)
19
- mask[1,1] = 0
20
- assert(np.array_equal(prtools.centroid(x, where=mask), [2,2]))
21
-
22
-
23
- def test_centroid_nan():
24
- x = np.zeros((5,5))
25
- x[2,2] = 1
26
- x[2,3] = np.nan
27
- assert(np.array_equal(prtools.centroid(x), [2,2]))
28
-
29
-
30
- x, _ = np.meshgrid(range(10), range(10))
31
- x[2,2] = 100
32
-
33
- def test_medfix():
34
- m = np.zeros_like(x)
35
- m[2,2] = 1
36
- y = prtools.medfix(x, mask=m, kernel=(3,3))
37
- assert(y[2,2] == 2)
38
-
39
- def test_medfix_bigmask():
40
- m = np.zeros_like(x)
41
- m[2:6, 2:6] = 1
42
- with warnings.catch_warnings():
43
- warnings.simplefilter('error')
44
- y = prtools.medfix(x, mask=m, kernel=(3,3))
45
- assert(np.all(np.isnan(y[3:5,3:5])))
File without changes
File without changes
File without changes
File without changes
File without changes