CGLS and LSQR Solvers

This example shows how to use the pylops.optimization.leastsquares.cgls and pylops.optimization.leastsquares.lsqr PyLops solvers to minimize the following cost function:

\[J = \| \mathbf{y} - \mathbf{Ax} \|_2^2 + \epsilon \| \mathbf{x} \|_2^2\]

Note that the LSQR solver behaves in the same way as the scipy’s scipy.sparse.linalg.lsqr solver. However, our solver is also able to operate on cupy arrays and perform computations on a GPU.

import warnings

import matplotlib.pyplot as plt
import numpy as np

import pylops

plt.close("all")
warnings.filterwarnings("ignore")

Let’s define a matrix \(\mathbf{A}\) or size (N and M) and fill the matrix with random numbers

N, M = 20, 10
A = np.random.normal(0, 1, (N, M))
Aop = pylops.MatrixMult(A, dtype="float64")

x = np.ones(M)

We can now use the cgls solver to invert this matrix

y = Aop * x
xest, istop, nit, r1norm, r2norm, cost_cgls = pylops.optimization.basic.cgls(
    Aop, y, x0=np.zeros_like(x), niter=10, tol=1e-10, show=True
)

print(f"x= {x}")
print(f"cgls solution xest= {xest}")

Out:

CGLS
-----------------------------------------------------------------
The Operator Op has 20 rows and 10 cols
damp = 0.000000e+00     tol = 1.000000e-10      niter = 10
-----------------------------------------------------------------

    Itn          x[0]              r1norm         r2norm
     1        9.1362e-01         3.5210e+00     3.5210e+00
     2        1.1328e+00         1.9174e+00     1.9174e+00
     3        1.1030e+00         7.9210e-01     7.9210e-01
     4        1.0366e+00         3.9919e-01     3.9919e-01
     5        1.0086e+00         1.4627e-01     1.4627e-01
     6        1.0069e+00         8.0987e-02     8.0987e-02
     7        9.9981e-01         3.8979e-02     3.8979e-02
     8        9.9936e-01         1.9302e-02     1.9302e-02
     9        1.0006e+00         3.0820e-03     3.0820e-03
    10        1.0000e+00         3.6146e-15     3.6146e-15

Iterations = 10        Total time (s) = 0.00
-----------------------------------------------------------------

x= [1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]
cgls solution xest= [1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]

And the lsqr solver to invert this matrix

y = Aop * x
(
    xest,
    istop,
    itn,
    r1norm,
    r2norm,
    anorm,
    acond,
    arnorm,
    xnorm,
    var,
    cost_lsqr,
) = pylops.optimization.basic.lsqr(Aop, y, x0=np.zeros_like(x), niter=10, show=True)

print(f"x= {x}")
print(f"lsqr solution xest= {xest}")

Out:

LSQR
------------------------------------------------------------------------------------------
The Operator Op has 20 rows and 10 cols
damp = 0.00000000000000e+00     calc_var =      1
atol = 1.00e-08                 conlim = 1.00e+08
btol = 1.00e-08                 niter =       10
------------------------------------------------------------------------------------------
   Itn     x[0]      r1norm     r2norm   Compatible   LS     Norm A   Cond A
     0  0.0000e+00  1.650e+01  1.650e+01   1.0e+00  3.4e-01
     1  9.1362e-01  3.521e+00  3.521e+00   2.1e-01  1.4e-01  5.7e+00  1.0e+00
     2  1.1328e+00  1.917e+00  1.917e+00   1.2e-01  8.8e-02  7.3e+00  2.1e+00
     3  1.1030e+00  7.921e-01  7.921e-01   4.8e-02  3.9e-02  9.0e+00  3.5e+00
     4  1.0366e+00  3.992e-01  3.992e-01   2.4e-02  1.3e-02  1.1e+01  4.7e+00
     5  1.0086e+00  1.463e-01  1.463e-01   8.9e-03  5.1e-03  1.1e+01  6.2e+00
     6  1.0069e+00  8.099e-02  8.099e-02   4.9e-03  3.3e-03  1.2e+01  7.4e+00
     7  9.9981e-01  3.898e-02  3.898e-02   2.4e-03  1.5e-03  1.3e+01  8.8e+00
     8  9.9936e-01  1.930e-02  1.930e-02   1.2e-03  7.2e-04  1.4e+01  1.0e+01
     9  1.0006e+00  3.082e-03  3.082e-03   1.9e-04  8.3e-05  1.4e+01  1.2e+01
    10  1.0000e+00  4.480e-15  4.480e-15   2.7e-16  3.1e-16  1.4e+01  1.3e+01

LSQR finished, Op x - b is small enough, given atol, btol

istop =       1   r1norm = 4.5e-15   anorm = 1.4e+01   arnorm = 2.8e-14
itn   =      10   r2norm = 4.5e-15   acond = 1.3e+01   xnorm  = 3.2e+00
Total time (s) = 0.00
------------------------------------------------------------------------------------------

x= [1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]
lsqr solution xest= [1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]

Finally we show that the L2 norm of the residual of the two solvers decays in the same way, as LSQR is algebrically equivalent to CG on the normal equations and CGLS

plt.figure(figsize=(12, 3))
plt.plot(cost_cgls, "k", lw=2, label="CGLS")
plt.plot(cost_lsqr, "--r", lw=2, label="LSQR")
plt.title("Cost functions")
plt.legend()
plt.tight_layout()
Cost functions

Note that while we used a dense matrix here, any other linear operator can be fed to cgls and lsqr as is the case for any other PyLops solver.

Total running time of the script: ( 0 minutes 0.186 seconds)

Gallery generated by Sphinx-Gallery