Skip to content

Commit 330bcea

Browse files
authored
Merge pull request #153 from mrava87/tutorialcs
doc: added IHT to twist tutorial
2 parents 6fb31e3 + 2d129fb commit 330bcea

File tree

1 file changed

+58
-16
lines changed

1 file changed

+58
-16
lines changed

tutorials/twist.py

Lines changed: 58 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,26 @@
11
r"""
2-
ISTA, FISTA, and TWIST for Compressive sensing
3-
==============================================
2+
IHT, ISTA, FISTA, and TWIST for Compressive sensing
3+
===================================================
44
5-
In this example we want to compare three popular solvers in compressive
6-
sensing problem, namely :py:class:`pylops.optimization.sparsity.ista`,
7-
:py:class:`pylops.optimization.sparsity.fista`, and
8-
:py:class:`pyproximal.optimization.primal.TwIST`.
5+
In this example we want to compare four popular solvers in compressive
6+
sensing problem, namely IHT, ISTA, FISTA, and TwIST. The first three can
7+
be implemented using the same solver, namely the
8+
:py:class:`pyproximal.optimization.primal.ProximalGradient`, whilst the latter
9+
is implemented in :py:class:`pyproximal.optimization.primal.TwIST`.
910
10-
Whilst all solvers try to solve an unconstrained problem with a L1
11+
The IHT solver tries to solve the following unconstrained problem with a L0Ball
12+
regularization term:
13+
14+
.. math::
15+
J = \|\mathbf{d} - \mathbf{Op} \mathbf{x}\|_2 \; s.t. \; \|\mathbf{x}\|_0 \le K
16+
17+
The other solvers try instead to solve an unconstrained problem with a L1
1118
regularization term:
1219
1320
.. math::
1421
J = \|\mathbf{d} - \mathbf{Op} \mathbf{x}\|_2 + \epsilon \|\mathbf{x}\|_1
1522
16-
their convergence speed is different, which is something we want to focus in
23+
however their convergence speed is different, which is something we want to focus in
1724
this tutorial.
1825
1926
"""
@@ -27,6 +34,9 @@
2734
plt.close('all')
2835
np.random.seed(0)
2936

37+
def callback(x, pf, pg, eps, cost):
38+
cost.append(pf(x) + eps * pg(x))
39+
3040
###############################################################################
3141
# Let's start by creating a dense mixing matrix and a sparse signal.
3242
# Note that the mixing matrix leads to an underdetermined system of equations
@@ -45,19 +55,38 @@
4555
y = Aop * x
4656

4757
###############################################################################
48-
# We try now to recover the sparse signal with our 3 different solvers
49-
eps = 1e-2
58+
# We try now to recover the sparse signal with our 4 different solvers
59+
L = np.abs((Aop.H * Aop).eigs(1)[0])
60+
tau = 0.95 / L
61+
eps = 5e-3
5062
maxit = 100
5163

64+
# IHT
65+
l0 = pyproximal.proximal.L0Ball(3)
66+
l2 = pyproximal.proximal.L2(Op=Aop, b=y)
67+
costf1 = []
68+
x_iht = pyproximal.optimization.primal.ProximalGradient(l2, l0, tau=tau, x0=np.zeros(M),
69+
epsg=eps, niter=maxit, acceleration='fista', show=False)
70+
5271
# ISTA
53-
x_ista, niteri, costi = \
54-
pylops.optimization.sparsity.ista(Aop, y, niter=maxit, eps=eps, tol=1e-10,
55-
show=False)
72+
l1 = pyproximal.proximal.L1()
73+
l2 = pyproximal.proximal.L2(Op=Aop, b=y)
74+
costi = []
75+
x_ista = \
76+
pyproximal.optimization.primal.ProximalGradient(l2, l1, tau=tau, x0=np.zeros(M),
77+
epsg=eps, niter=maxit, show=False,
78+
callback=lambda x: callback(x, l2, l1, eps, costi))
79+
niteri = len(costi)
5680

5781
# FISTA
58-
x_fista, niterf, costf = \
59-
pylops.optimization.sparsity.fista(Aop, y, niter=maxit, eps=eps,
60-
tol=1e-10, show=False)
82+
l1 = pyproximal.proximal.L1()
83+
l2 = pyproximal.proximal.L2(Op=Aop, b=y)
84+
costf = []
85+
x_fista = \
86+
pyproximal.optimization.primal.ProximalGradient(l2, l1, tau=tau, x0=np.zeros(M),
87+
epsg=eps, niter=maxit, acceleration='fista', show=False,
88+
callback=lambda x: callback(x, l2, l1, eps, costf))
89+
niterf = len(costf)
6190

6291
# TWIST (Note that since the smallest eigenvalue is zero, we arbitrarily
6392
# choose a small value for the solver to converge stably)
@@ -73,6 +102,9 @@
73102
m, s, b = ax.stem(x, linefmt='k', basefmt='k',
74103
markerfmt='ko', label='True')
75104
plt.setp(m, markersize=10)
105+
m, s, b = ax.stem(x_iht, linefmt='--c', basefmt='--c',
106+
markerfmt='co', label='IHT')
107+
plt.setp(m, markersize=10)
76108
m, s, b = ax.stem(x_ista, linefmt='--r', basefmt='--r',
77109
markerfmt='ro', label='ISTA')
78110
plt.setp(m, markersize=7)
@@ -95,3 +127,13 @@
95127
ax.legend()
96128
ax.grid(True, which='both')
97129
plt.tight_layout()
130+
131+
###############################################################################
132+
# To conclude, given the nature of the problem (small number of non-zero coefficients),
133+
# the IHT solver shows the fastest convergence - note that we do not display the
134+
# cost function since this is a constrained problem. This is however greatly influenced
135+
# by the fact that we assume exact knowledge of the number of non-zero coefficients.
136+
# When this information is not available, IHT may become suboptimal. In this case the
137+
# FISTA solver should always be preferred (over ISTA) and TwIST represents an
138+
# alternative worth checking.
139+

0 commit comments

Comments
 (0)