prtools 1.3.0__tar.gz → 1.3.1__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.
- {prtools-1.3.0/prtools.egg-info → prtools-1.3.1}/PKG-INFO +1 -1
- {prtools-1.3.0 → prtools-1.3.1}/prtools/__init__.py +1 -1
- prtools-1.3.1/prtools/backend/__init__.py +19 -0
- prtools-1.3.1/prtools/backend/_base.py +7 -0
- prtools-1.3.1/prtools/backend/jax.py +130 -0
- prtools-1.3.1/prtools/backend/numpy.py +13 -0
- {prtools-1.3.0 → prtools-1.3.1/prtools.egg-info}/PKG-INFO +1 -1
- {prtools-1.3.0 → prtools-1.3.1}/prtools.egg-info/SOURCES.txt +4 -0
- {prtools-1.3.0 → prtools-1.3.1}/pyproject.toml +0 -3
- {prtools-1.3.0 → prtools-1.3.1}/LICENSE +0 -0
- {prtools-1.3.0 → prtools-1.3.1}/NOTICE +0 -0
- {prtools-1.3.0 → prtools-1.3.1}/README.rst +0 -0
- {prtools-1.3.0 → prtools-1.3.1}/prtools/_backend.py +0 -0
- {prtools-1.3.0 → prtools-1.3.1}/prtools/array.py +0 -0
- {prtools-1.3.0 → prtools-1.3.1}/prtools/cost.py +0 -0
- {prtools-1.3.0 → prtools-1.3.1}/prtools/fourier.py +0 -0
- {prtools-1.3.0 → prtools-1.3.1}/prtools/misc.py +0 -0
- {prtools-1.3.0 → prtools-1.3.1}/prtools/segmented.py +0 -0
- {prtools-1.3.0 → prtools-1.3.1}/prtools/shape.py +0 -0
- {prtools-1.3.0 → prtools-1.3.1}/prtools/sparse.py +0 -0
- {prtools-1.3.0 → prtools-1.3.1}/prtools/stats.py +0 -0
- {prtools-1.3.0 → prtools-1.3.1}/prtools/zernike.py +0 -0
- {prtools-1.3.0 → prtools-1.3.1}/prtools.egg-info/dependency_links.txt +0 -0
- {prtools-1.3.0 → prtools-1.3.1}/prtools.egg-info/requires.txt +0 -0
- {prtools-1.3.0 → prtools-1.3.1}/prtools.egg-info/top_level.txt +0 -0
- {prtools-1.3.0 → prtools-1.3.1}/setup.cfg +0 -0
- {prtools-1.3.0 → prtools-1.3.1}/tests/test_array.py +0 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import importlib
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class BackendRegistry:
|
|
5
|
+
|
|
6
|
+
_BUILTIN_BACKEND = ['numpy', 'jax']
|
|
7
|
+
|
|
8
|
+
def _get_backend_module(self, backend):
|
|
9
|
+
return importlib.import_module(f'.{backend}', 'prtools.backend')
|
|
10
|
+
|
|
11
|
+
def load_numpy(self, backend):
|
|
12
|
+
backend = self._get_backend_module(backend)
|
|
13
|
+
return backend.Numpy()
|
|
14
|
+
|
|
15
|
+
def load_scipy(self, backend):
|
|
16
|
+
return self._get_backend_module(backend).Scipy()
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
registry = BackendRegistry()
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import importlib
|
|
2
|
+
from typing import NamedTuple
|
|
3
|
+
|
|
4
|
+
from ._base import _BackendLibrary
|
|
5
|
+
from prtools import __backend__
|
|
6
|
+
from prtools._backend import numpy as np
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Numpy(_BackendLibrary):
|
|
10
|
+
def __init__(self):
|
|
11
|
+
super().__init__(importlib.import_module('jax.numpy'))
|
|
12
|
+
|
|
13
|
+
def broadcast_to(self, array, shape):
|
|
14
|
+
# jax broadcast_to expects an array input
|
|
15
|
+
array = self.module.asarray(array)
|
|
16
|
+
return self.module.broadcast_to(array, shape)
|
|
17
|
+
|
|
18
|
+
def dot(self, a, b, out=None):
|
|
19
|
+
# jax.numpy.dot doesn't support the `out` parameter so we ignore it
|
|
20
|
+
return self.module.dot(a, b)
|
|
21
|
+
|
|
22
|
+
def max(self, a, *args, **kwargs):
|
|
23
|
+
# jax max expects an array input
|
|
24
|
+
array = self.module.asarray(a)
|
|
25
|
+
return self.module.max(array, *args, **kwargs)
|
|
26
|
+
|
|
27
|
+
def multiply(self, a, b, out=None):
|
|
28
|
+
# jax.numpy.multiply doesn't support the `out` parameter so we
|
|
29
|
+
# ignore it
|
|
30
|
+
return self.module.multiply(a, b)
|
|
31
|
+
|
|
32
|
+
def divide(self, a, b, out=None):
|
|
33
|
+
# jax.numpy.divide doesn't support the `out` parameter so we
|
|
34
|
+
# ignore it
|
|
35
|
+
return self.module.divide(a, b)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class Scipy(_BackendLibrary):
|
|
39
|
+
def __init__(self):
|
|
40
|
+
super().__init__(importlib.import_module('jax.scipy'))
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class OptimizeResult(dict):
|
|
44
|
+
"""Represents the optimization result.
|
|
45
|
+
|
|
46
|
+
Attributes
|
|
47
|
+
----------
|
|
48
|
+
x : ndarray
|
|
49
|
+
The solution of the optimization.
|
|
50
|
+
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
def __init__(self):
|
|
54
|
+
super().__init__()
|
|
55
|
+
|
|
56
|
+
#def __getattr__(self, name):
|
|
57
|
+
# try:
|
|
58
|
+
# return self[name]
|
|
59
|
+
# except KeyError as e:
|
|
60
|
+
# raise AttributeError(name) from e
|
|
61
|
+
|
|
62
|
+
#__setattr__ = dict.__setitem__
|
|
63
|
+
#__delattr__ = dict.__delitem__
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def lbfgs(fun, x0, tol, maxiter, callback=None):
|
|
67
|
+
"""Minimize a scalar function of one or more variables using the L-BFGS
|
|
68
|
+
algorithm
|
|
69
|
+
|
|
70
|
+
Parameters
|
|
71
|
+
----------
|
|
72
|
+
fun : callable
|
|
73
|
+
The objective function to be minimied
|
|
74
|
+
x0 : array_like
|
|
75
|
+
Initial starting guess
|
|
76
|
+
tol : float
|
|
77
|
+
Termination tolerance
|
|
78
|
+
maxiter : int
|
|
79
|
+
Maximum number of iterations
|
|
80
|
+
callback : callable, optional
|
|
81
|
+
Not currently implemented
|
|
82
|
+
|
|
83
|
+
Returns
|
|
84
|
+
-------
|
|
85
|
+
final_params :
|
|
86
|
+
|
|
87
|
+
final_state :
|
|
88
|
+
|
|
89
|
+
"""
|
|
90
|
+
if __backend__ != 'jax':
|
|
91
|
+
raise RuntimeError('JAX backend must be selected')
|
|
92
|
+
|
|
93
|
+
try:
|
|
94
|
+
import jax
|
|
95
|
+
import optax
|
|
96
|
+
import optax.tree_utils as otu
|
|
97
|
+
except ImportError as error:
|
|
98
|
+
raise ImportError('lbfgs requires jax and optax') from error
|
|
99
|
+
|
|
100
|
+
opt = optax.lbfgs()
|
|
101
|
+
value_and_grad_fun = optax.value_and_grad_from_state(fun)
|
|
102
|
+
|
|
103
|
+
def step(carry):
|
|
104
|
+
params, state = carry
|
|
105
|
+
value, grad = value_and_grad_fun(params, state=state)
|
|
106
|
+
updates, state = opt.update(
|
|
107
|
+
grad, state, params, value=value, grad=grad, value_fn=fun,
|
|
108
|
+
)
|
|
109
|
+
if callback:
|
|
110
|
+
res = {}
|
|
111
|
+
res['x'] = params
|
|
112
|
+
res['grad'] = grad
|
|
113
|
+
res['fun'] = value
|
|
114
|
+
res['nit'] = otu.tree_get(state, 'count')
|
|
115
|
+
jax.debug.callback(callback, res)
|
|
116
|
+
params = optax.apply_updates(params, updates)
|
|
117
|
+
return params, state
|
|
118
|
+
|
|
119
|
+
def continuing_criterion(carry):
|
|
120
|
+
_, state = carry
|
|
121
|
+
iter_num = otu.tree_get(state, 'count')
|
|
122
|
+
grad = otu.tree_get(state, 'grad')
|
|
123
|
+
err = otu.tree_l2_norm(grad)
|
|
124
|
+
return (iter_num == 0) | ((iter_num < maxiter) & (err >= tol))
|
|
125
|
+
|
|
126
|
+
init_carry = (x0, opt.init(x0))
|
|
127
|
+
final_params, final_state = jax.lax.while_loop(
|
|
128
|
+
continuing_criterion, step, init_carry
|
|
129
|
+
)
|
|
130
|
+
return final_params, final_state
|
|
@@ -18,4 +18,8 @@ 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
|
+
prtools/backend/__init__.py
|
|
22
|
+
prtools/backend/_base.py
|
|
23
|
+
prtools/backend/jax.py
|
|
24
|
+
prtools/backend/numpy.py
|
|
21
25
|
tests/test_array.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|