Skip to content

Commit 7a88310

Browse files
authored
Merge pull request #107 from mrava87/dev
feature: started porting for PyLops v2
2 parents 97d24fd + c259543 commit 7a88310

File tree

11 files changed

+39
-28
lines changed

11 files changed

+39
-28
lines changed

environment-dev.yml

100755100644
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ dependencies:
77
- python>=3.8.12
88
- numpy>=1.15.0
99
- scipy>=1.8.0
10-
- pylops<2.0.0
10+
- pylops>=2.0.0
1111
- scikit-image
1212
- matplotlib
1313
- ipython

environment.yml

100755100644
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@ dependencies:
55
- python>=3.8.12
66
- numpy>=1.15.0
77
- scipy>=1.8.0
8-
- pylops<2.0.0
8+
- pylops>=2.0.0

pyproximal/optimization/primal.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
from math import sqrt
66
from pylops.optimization.leastsquares import RegularizedInversion
7+
from pylops.utils.backend import to_numpy
78
from pyproximal.proximal import L2
89

910

@@ -258,7 +259,7 @@ def ProximalGradient(proxf, proxg, x0, tau=None, beta=0.5,
258259
if iiter < 10 or niter - iiter < 10 or iiter % (niter // 10) == 0:
259260
pf, pg = proxf(x), proxg(x)
260261
msg = '%6g %12.5e %10.3e %10.3e %10.3e' % \
261-
(iiter + 1, x[0] if x.ndim == 1 else x[0, 0],
262+
(iiter + 1, np.real(to_numpy(x[0])) if x.ndim == 1 else np.real(to_numpy(x[0, 0])),
262263
pf, pg[0] if epsg_print == 'Multi' else pg,
263264
pf + np.sum(epsg * pg))
264265
print(msg)
@@ -1029,7 +1030,7 @@ def TwIST(proxg, A, b, x0, alpha=None, beta=None, eigs=None, niter=10,
10291030
if iiter < 10 or niter - iiter < 10 or iiter % (niter // 10) == 0:
10301031
pf, pg = proxf(x), proxg(x)
10311032
msg = '%6g %12.5e %10.3e %10.3e %10.3e' % \
1032-
(iiter + 1, x[0], pf, pg, pf + pg)
1033+
(iiter + 1, np.real(to_numpy(x[0])), pf, pg, pf + pg)
10331034
print(msg)
10341035
if show:
10351036
print('\nTotal time (s) = %.2f' % (time.time() - tstart))

pyproximal/optimization/primaldual.py

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import time
22
import numpy as np
33

4+
from pylops.utils.backend import get_array_module
45

5-
def PrimalDual(proxf, proxg, A, x0, tau, mu, z=None, theta=1., niter=10,
6-
gfirst=True, callback=None, callbacky=False, show=False):
6+
7+
def PrimalDual(proxf, proxg, A, x0, tau, mu, y0=None, z=None, theta=1., niter=10,
8+
gfirst=True, callback=None, callbacky=False, returny=False, show=False):
79
r"""Primal-dual algorithm
810
911
Solves the following (possibly) nonlinear minimization problem using
@@ -45,6 +47,8 @@ def PrimalDual(proxf, proxg, A, x0, tau, mu, z=None, theta=1., niter=10,
4547
mu : :obj:`float` or :obj:`np.ndarray`
4648
Stepsize of subgradient of :math:`g^*`. This can be constant
4749
or function of iterations (in the latter cases provided as np.ndarray)
50+
z0 : :obj:`numpy.ndarray`
51+
Initial auxiliary vector
4852
z : :obj:`numpy.ndarray`, optional
4953
Additional vector
5054
theta : :obj:`float`
@@ -62,6 +66,8 @@ def PrimalDual(proxf, proxg, A, x0, tau, mu, z=None, theta=1., niter=10,
6266
where ``x`` is the current model vector
6367
callbacky : :obj:`bool`, optional
6468
Modify callback signature to (``callback(x, y)``) when ``callbacky=True``
69+
returny : :obj:`bool`, optional
70+
Return also ``y``
6571
show : :obj:`bool`, optional
6672
Display iterations log
6773
@@ -102,13 +108,15 @@ def PrimalDual(proxf, proxg, A, x0, tau, mu, z=None, theta=1., niter=10,
102108
Imaging and Vision, 40, 8pp. 120-145. 2011.
103109
104110
"""
111+
ncp = get_array_module(x0)
112+
105113
# check if tau and mu are scalars or arrays
106114
fixedtau = fixedmu = False
107115
if isinstance(tau, (int, float)):
108-
tau = tau * np.ones(niter)
116+
tau = tau * ncp.ones(niter)
109117
fixedtau = True
110118
if isinstance(mu, (int, float)):
111-
mu = mu * np.ones(niter)
119+
mu = mu * ncp.ones(niter)
112120
fixedmu = True
113121

114122
if show:
@@ -128,8 +136,7 @@ def PrimalDual(proxf, proxg, A, x0, tau, mu, z=None, theta=1., niter=10,
128136

129137
x = x0.copy()
130138
xhat = x.copy()
131-
y = np.zeros(A.shape[0], dtype=x.dtype)
132-
139+
y = y0.copy() if y0 is not None else ncp.zeros(A.shape[0], dtype=x.dtype)
133140
for iiter in range(niter):
134141
xold = x.copy()
135142
if gfirst:
@@ -165,7 +172,10 @@ def PrimalDual(proxf, proxg, A, x0, tau, mu, z=None, theta=1., niter=10,
165172
if show:
166173
print('\nTotal time (s) = %.2f' % (time.time() - tstart))
167174
print('---------------------------------------------------------\n')
168-
return x
175+
if not returny:
176+
return x
177+
else:
178+
return x, y
169179

170180

171181
def AdaptivePrimalDual(proxf, proxg, A, x0, tau, mu,

pyproximal/projection/AffineSet.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
import numpy as np
2-
from scipy.sparse.linalg import lsqr
1+
from scipy.sparse.linalg import lsqr as sp_lsqr
32

3+
from pylops.optimization.basic import lsqr
4+
from pylops.utils.backend import get_array_module, get_module_name
45

56
class AffineSetProj():
67
r"""Affine set projection.
@@ -39,6 +40,9 @@ def __init__(self, Op, b, niter):
3940
self.niter = niter
4041

4142
def __call__(self, x):
42-
inv = lsqr(self.Op * self.Op.H, self.Op * x - self.b, iter_lim=self.niter)[0]
43-
y = x - self.Op.H * inv
43+
if get_module_name(get_array_module(x)) == 'numpy':
44+
inv = sp_lsqr(self.Op * self.Op.H, self.Op * x - self.b, iter_lim=self.niter)[0]
45+
else:
46+
inv = lsqr(self.Op * self.Op.H, self.Op * x - self.b, niter=self.niter)[0]
47+
y = x - self.Op.H * inv.ravel() # currently ravel is added to ensure that the output is always a vector
4448
return y

pyproximal/proximal/Nuclear.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import numpy as np
22

3-
from pylops.optimization.sparsity import _softthreshold
3+
from pylops.optimization.cls_sparsity import _softthreshold
44
from pyproximal.ProxOperator import _check_tau
55
from pyproximal.projection import NuclearBallProj
66
from pyproximal import ProxOperator

pyproximal/proximal/Orthogonal.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,11 @@ def __init__(self, f, Q, partial=False, b=None, alpha=1.):
6363
self.Q = Q
6464
self.partial = partial
6565
self.alpha = alpha
66-
self.b = b if b is not None else np.zeros(Q.shape[0], dtype=Q.dtype)
66+
self.b = b if b is not None else 0
6767

6868
def __call__(self, x):
6969
y = self.Q.matvec(x)
70-
if self.b is not None:
71-
y += self.b
70+
y += self.b
7271
f = self.f(y)
7372
return f
7473

@@ -81,10 +80,8 @@ def prox(self, x, tau):
8180
self.Q.rmatvec(self.f.prox(y + self.b, self.alpha * tau) -
8281
self.b))
8382
else:
84-
if self.b is not None:
85-
y = y + self.b
83+
y = y + self.b
8684
z = self.f.prox(y, tau)
87-
if self.b is not None:
88-
z = z - self.b
85+
z = z - self.b
8986
z = self.Q.rmatvec(z)
9087
return z

pyproximal/proximal/QuadraticEnvelope.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import numpy as np
22

3-
from pylops.optimization.sparsity import _hardthreshold
3+
from pylops.optimization.cls_sparsity import _hardthreshold
44
from pyproximal.ProxOperator import _check_tau
55
from pyproximal import ProxOperator
66

pyproximal/proximal/TV.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,12 @@ def __init__(self, dims, sigma=1., niter=10, rtol=1e-4, **kwargs):
4848
def __call__(self, x):
4949
x = x.reshape(self.dims)
5050
if self.ndim == 1:
51-
derivOp = FirstDerivative(self.dims[0], dims=None, dir=0, edge=False,
51+
derivOp = FirstDerivative(dims=self.dims[0], axis=0, edge=False,
5252
dtype=x.dtype, kind="forward")
5353
dx = derivOp @ x
5454
y = np.sum(np.abs(dx), axis=0)
5555
elif self.ndim >= 2:
5656
y = 0
57-
grads = []
5857
gradOp = Gradient(self.dims, edge=False, dtype=x.dtype, kind="forward")
5958
grads = gradOp.matvec(x.ravel())
6059
grads = grads.reshape((self.ndim, ) + self.dims)

requirements-dev.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
numpy>=1.15.0
22
scipy>=1.8.0
3-
pylops<=1.18.3
3+
pylops>=2.0.0
44
numba
55
scikit-image
66
matplotlib

0 commit comments

Comments
 (0)