Esempio n. 1
0
    def from_data_mapper_and_regularization(
        cls,
        visibilities: vis.Visibilities,
        noise_map: vis.VisibilitiesNoiseMap,
        transformer: trans.TransformerNUFFT,
        mapper: typing.Union[mappers.MapperRectangular, mappers.MapperVoronoi],
        regularization: reg.Regularization,
        settings=SettingsInversion(),
    ):

        regularization_matrix = regularization.regularization_matrix_from_mapper(
            mapper=mapper
        )

        Aop = pylops.MatrixMult(sparse.bsr_matrix(mapper.mapping_matrix))

        Fop = transformer

        Op = Fop * Aop

        curvature_matrix_approx = np.multiply(
            np.sum(noise_map.weight_list_ordered_1d),
            mapper.mapping_matrix.T @ mapper.mapping_matrix,
        )

        preconditioner_matrix = np.add(curvature_matrix_approx, regularization_matrix)

        preconditioner_inverse_matrix = np.linalg.inv(preconditioner_matrix)

        MOp = pylops.MatrixMult(sparse.bsr_matrix(preconditioner_inverse_matrix))

        log_det_curvature_reg_matrix_term = 2.0 * np.sum(
            np.log(np.diag(np.linalg.cholesky(preconditioner_matrix)))
        )

        reconstruction = pylops.NormalEquationsInversion(
            Op=Op,
            Regs=None,
            epsNRs=[1.0],
            data=visibilities.ordered_1d,
            Weight=pylops.Diagonal(diag=noise_map.weight_list_ordered_1d),
            NRegs=[pylops.MatrixMult(sparse.bsr_matrix(regularization_matrix))],
            M=MOp,
            tol=settings.tolerance,
            atol=settings.tolerance,
            **dict(maxiter=settings.maxiter),
        )

        return InversionInterferometerLinearOperator(
            visibilities=visibilities,
            noise_map=noise_map,
            transformer=transformer,
            mapper=mapper,
            regularization=regularization,
            regularization_matrix=regularization_matrix,
            reconstruction=np.real(reconstruction),
            settings=settings,
            log_det_curvature_reg_matrix_term=log_det_curvature_reg_matrix_term,
        )
Esempio n. 2
0
def inpainting_ista_once(Y, D, maskvec, n_nonzero_coefs, sigma=0.001, rc_min=0.01):
    coef = np.zeros((D.shape[1], Y.shape[1]))
    for k in tqdm(range(Y.shape[1])):
        nonzero_pos = np.nonzero(maskvec[:, k])[0]
        D_sub = D[nonzero_pos, :]
        Y_sub = Y[:, k:k + 1][nonzero_pos]

        # ISTA
        coef[:, k] = ISTA_Inpainting2(D_sub, Y_sub, n_nonzero_coefs, max_iter=1000)[:, 0]
        coef[:, k] = pylops.optimization.sparsity.ISTA(pylops.MatrixMult(D_sub), Y_sub[:, 0], 5000, eps=1e-2, tol=1e-3, returninfo=True)[0]

    return coef
Esempio n. 3
0
    def decode_lasso(self, results):
        #lasso = LassoLars(alpha=self.l)
        #lasso = Lasso(alpha=self.l, max_iter=1000)
        #lasso = LassoCV(n_alphas=100)
        #lasso.fit(self.M.T, results)

        temp_mat = (self.M.T).astype(float)
        #temp_mat=np.matrix(temp_mat)
        #print(np.shape(temp_mat))

        #print('best lambda = ', lasso.alpha_)
        #answer = lasso.coef_
        #Using ISTA
        #temp_mat=pylops.MatrixMult(temp_mat)
        #answer = pylops.optimization.sparsity.ISTA(temp_mat, results, 10000, eps=self.l, tol=0, returninfo=True)[0]
        #Using OMP
        #print(type(temp_mat))
        temp_mat = pylops.MatrixMult(temp_mat)
        #print(temp_mat)
        answer = pylops.optimization.sparsity.OMP(temp_mat,
                                                  results,
                                                  10000,
                                                  sigma=0.4)[0]
        #Using spgl1 lasso
        #[answer,r,g,info] = spg.spg_lasso(temp_mat,results,1e-4);
        #Using ISTA function
        #answer = fista(temp_mat, results, self.l, 10000)[0]
        #print(answer)

        score = math.sqrt(np.linalg.norm(answer - self.conc) / self.d)
        infected = (answer != 0.).astype(np.int32)

        # Compute stats
        tpos = (infected * self.arr)
        fneg = (1 - infected) * self.arr
        fpos = infected * (1 - self.arr)

        tp = sum(tpos)
        fp = sum(fpos)
        fn = sum(fneg)

        return score, tp, fp, fn
Esempio n. 4
0
plt.close('all')
np.random.seed(0)

###############################################################################
# Let's start with a simple example, where we create a dense mixing matrix
# and a sparse signal and we use OMP and ISTA to recover such a signal.
# Note that the mixing matrix leads to an underdetermined system of equations
# (:math:`N < M`) so being able to add some extra prior information regarding
# the sparsity of our desired model is essential to be able to invert
# such a system.

N, M = 15, 20
A = np.random.randn(N, M)
A = A / np.linalg.norm(A, axis=0)
Aop = pylops.MatrixMult(A)

x = np.random.rand(M)
x[x < 0.9] = 0
y = Aop * x

# MP/OMP
eps = 1e-2
maxit = 500
x_mp = pylops.optimization.sparsity.OMP(Aop,
                                        y,
                                        maxit,
                                        niter_inner=0,
                                        sigma=1e-4)[0]
x_omp = pylops.optimization.sparsity.OMP(Aop, y, maxit, sigma=1e-4)[0]
Esempio n. 5
0
epsI = np.sqrt(1e-4)

xne = \
    pylops.optimization.leastsquares.NormalEquationsInversion(Rop, [D2op], y,
                                                              epsI=epsI,
                                                              epsRs=[epsR],
                                                              returninfo=False,
                                                              **dict(maxiter=50))

###############################################################################
# Note that in case we have access to a fast implementation for the chain of
# forward and adjoint for the regularization operator
# (i.e., :math:`\nabla^T\nabla`), we can modify our call to
# :py:func:`pylops.optimization.leastsquares.NormalEquationsInversion` as
# follows:
ND2op = pylops.MatrixMult((D2op.H * D2op).tosparse())  # mimic fast D^T D

xne1 = \
    pylops.optimization.leastsquares.NormalEquationsInversion(Rop, [], y,
                                                              NRegs=[ND2op],
                                                              epsI=epsI,
                                                              epsNRs=[epsR],
                                                              returninfo=False,
                                                              **dict(maxiter=50))

###############################################################################
# We can do the same while using
# :py:func:`pylops.optimization.leastsquares.RegularizedInversion`
# which solves the following augmented problem
#
#   .. math::
In this example we will consider the BlockDiagonal operator which contains
:class:`pylops.basicoperators.MatrixMult` operators along its main diagonal.
"""
import numpy as np
import matplotlib.pyplot as plt

import pylops

plt.close('all')

###############################################################################
# Let's start by creating N MatrixMult operators and the BlockDiag operator
N = 100
Nops = 32
Ops = [
    pylops.MatrixMult(np.random.normal(0., 1., (N, N))) for _ in range(Nops)
]

Op = pylops.BlockDiag(Ops, nproc=1)

###############################################################################
# We can now perform a scalability test on the forward operation
workers = [2, 3, 4]
compute_times, speedup = \
    pylops.utils.multiproc.scalability_test(Op, np.ones(Op.shape[1]),
                                            workers=workers, forward=True)
plt.figure(figsize=(12, 3))
plt.plot(workers, speedup, 'ko-')
plt.xlabel('# Workers')
plt.ylabel('Speed Up')
plt.title('Forward scalability test')
Esempio n. 7
0
import numpy as np

import matplotlib.pyplot as plt

import pylops

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

###############################################################################
# Let's define a matrix :math:`\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.solver.cgls(Aop, y, x0=np.zeros_like(x),
                                    niter=10, tol=1e-10, show=True)

print('x= %s' % x)
print('cgls solution xest= %s' % xest)

###############################################################################
Esempio n. 8
0
import matplotlib.pyplot as plt
import matplotlib.gridspec as pltgs

import pylops
from pylops.utils import dottest

plt.close('all')

###############################################################################
# Let's start with something very simple. We will make a :py:class:`pylops.MatrixMult`
# operator and verify that its implementation passes the dot-test.
# For this time, we will do this step-by-step, replicating what happens in the
# :py:func:`pylops.utils.dottest` routine.
N, M = 5, 3
Mat = np.arange(N * M).reshape(N, M)
Op = pylops.MatrixMult(Mat)

v = np.random.randn(N)
u = np.random.randn(M)

# Op * u
y = Op.matvec(u)
# Op'* v
x = Op.rmatvec(v)

yy = np.dot(y, v)  # (Op  * u)' * v
xx = np.dot(u, x)  # u' * (Op' * v)

print('Dot-test %e' % np.abs((yy - xx) / ((yy + xx + 1e-15) / 2)))

###############################################################################
Esempio n. 9
0
from scipy.sparse import rand
from scipy.sparse.linalg import lsqr

import pylops

plt.close("all")
warnings.filterwarnings("ignore")
# sphinx_gallery_thumbnail_number = 2

###############################################################################
# Let's define the sizes of the matrix :math:`\mathbf{A}` (``N`` and ``M``) and
# fill the matrix with random numbers

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

x = np.ones(M)

###############################################################################
# We can now apply the forward operator to create the data vector :math:`\mathbf{y}`
# and use ``/`` to solve the system by means of an explicit solver.

y = Aop * x
xest = Aop / y

###############################################################################
# Let's visually plot the system of equations we just solved.
gs = pltgs.GridSpec(1, 6)
fig = plt.figure(figsize=(7, 3))
ax = plt.subplot(gs[0, 0])
Esempio n. 10
0
import matplotlib.pyplot as plt
import numpy as np

import pylops

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

###############################################################################
# Let's define a matrix :math:`\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.solver.cgls(
    Aop, y, x0=np.zeros_like(x), niter=10, tol=1e-10, show=True
)

print("x= %s" % x)
print("cgls solution xest= %s" % xest)

###############################################################################
Esempio n. 11
0
    def decode_lasso(self,
                     results,
                     algo='lasso',
                     prefer_recall=False,
                     compute_stats=True):
        determined = 0
        overdetermined = 0
        # Add check if system is determined or overdetermined
        if self.t == self.n:
            determined = 1
        elif self.t > self.n:
            overdetermined = 1

        prob1 = None
        prob0 = None
        answer_high_precision = np.zeros(self.n)
        if algo == 'lasso':
            #lasso = LassoLars(alpha=self.l)
            lasso = Lasso(alpha=self.l, max_iter=10000)
            #lasso = LassoCV(n_alphas=100)
            lasso.fit(self.M.T, results)
            #print('best lambda = ', lasso.alpha_)
            answer = lasso.coef_
        elif algo == 'OMP':
            temp_mat = (self.M.T).astype(float)
            temp_mat = pylops.MatrixMult(temp_mat)
            answer = pylops.optimization.sparsity.OMP(temp_mat,
                                                      results,
                                                      10000,
                                                      sigma=0.001)[0]
        elif algo == 'NNOMP':
            # Max d that can be detected by NNOMP is equal to number of rows
            answer = nnompcv.nnomp(self.M.T.astype('float'),
                                   0,
                                   results,
                                   0,
                                   self.t,
                                   cv=False)
        elif algo == 'NNOMPCV':
            temp_mat = (self.M.T).astype(float)
            mr = math.ceil(0.9 * temp_mat.shape[1])
            m = temp_mat.shape[1]
            Ar = temp_mat[0:mr, :]
            Acv = temp_mat[mr + 1:m, :]
            yr = results[0:mr]
            ycv = results[mr + 1:m]
            #print('yo')
            # Max d that can be detected by NNOMP is equal to number of rows
            answer = nnompcv.nnomp(Ar, Acv, yr, ycv, self.t, cv=True)
        elif algo == 'NNOMP_loo_cv':
            answer, prob1, prob0 = self.decode_nnomp_multi_split_cv(
                results, 'loo_splits')
        elif algo == 'NNOMP_random_cv':
            # Skip cross-validation for really small cases
            if np.sum(results) == 0:
                answer = np.zeros(self.n)
            elif self.t < 4:

                # Max d that can be detected by NNOMP is equal to number of rows
                answer = nnompcv.nnomp(self.M.T.astype('float'),
                                       0,
                                       results,
                                       0,
                                       self.t,
                                       cv=False)
            else:
                answer, prob1, prob0 = self.decode_nnomp_multi_split_cv(
                    results, 'random_splits')
        elif algo.startswith('combined_COMP_'):
            #print('Doing ', algo)
            l = len('combined_COMP_')
            secondary_algo = algo[l:]
            answer, infected, prob1, prob0, determined, overdetermined =\
                self.decode_comp_combined(results, secondary_algo,
                compute_stats=compute_stats)
        elif algo.startswith('precise_SBL_'):
            # e.g. combined_SBL_clustered_combined_COMP_SBL
            # e.g. combined_SBL_clustered_COMP
            l = len('precise_SBL_')
            primary_algo = 'combined_COMP_SBL_clustered'
            secondary_algo = algo[l:]
            assert secondary_algo not in [
                'SBL_clustered', 'combined_COMP_SBL_clustered'
            ]

            y = results
            # First run SBL_clustered to get precise results
            # Then run secondary algorithm to get high recall results
            # "answer" is those from high recall ones.
            # we'll create "answer_precise_SBL" and "infected_precise_SBL".
            # infected_dd will become union of infected_dd and infected_precise_SBL
            # Hence surep will contain results from SBL_clustered as well.
            answer_high_precision = self.get_high_precision_algo_answer(
                primary_algo, y)
            answer = self.get_high_recall_algo_answer(secondary_algo, y)
        elif algo == 'SBL':
            A = self.M.T
            y = results

            answer = sbl.sbl(A, y)
        elif algo == 'l1ls':
            A = self.M.T
            y = results
            if np.all(y == 0):
                answer = np.zeros(self.n)
            else:
                answer = l1ls.l1ls(A, y, self.l, self.tau)
        elif algo == 'l1ls_cv':
            A = self.M.T
            y = results
            sigval = 0.01 * np.mean(y)
            if np.all(y == 0):
                answer = np.zeros(self.n)
            else:
                answer = l1ls.l1ls_cv(A, y, sigval, self.tau)
        elif algo in algos.algo_dict:
            params = {'A': self.M.T, 'y': results}
            res = algos.algo_dict[algo](params)
            answer = res["x_est"]
        else:
            raise ValueError('No such algorithm %s' % algo)

        score = np.linalg.norm(answer - self.conc) / math.sqrt(self.t)
        infected = (answer != 0.).astype(np.int32)

        if prob1 is None:
            assert prob0 is None
            prob1 = np.array(infected)
            prob0 = np.array(1 - infected)

        num_unconfident_negatives = 0
        if prefer_recall:
            # Report the unconfident -ves as +ve
            negatives = (infected == 0).astype(np.int32)
            unconfident_negatives = negatives * (prob0 < 0.6).astype(np.int32)
            num_unconfident_negatives = np.sum(unconfident_negatives)
            infected = infected + unconfident_negatives

        # Get definite defects
        y = results
        bool_y = (y > 0).astype(np.int32)
        _infected_comp, infected_dd, _score, _tp, _fp, _fn, surep, _unsurep, _ =\
            self.decode_comp_new(bool_y, compute_stats=compute_stats)

        #print(infected.shape)
        #print(infected_dd.shape)
        # Compare definite defects with ours to detect if our algorithm doesn't
        # detect something that should definitely have been detected
        wrongly_undetected = np.sum(infected_dd - infected_dd * infected)

        # Add infections from high precision algo
        infected_high_precision = (answer_high_precision > 0).astype(np.int32)
        # For ease of implementation we add above to infected_dd. This will become
        # sure_list later
        infected_dd = (infected_dd + infected_high_precision > 0).astype(
            np.int32)
        infected = (infected + infected_dd > 0).astype(np.int32)

        if compute_stats:
            # re-compute surep from above infected_dd
            surep = np.sum(infected_dd)

            # Compute stats
            tpos = (infected * self.arr)
            fneg = (1 - infected) * self.arr
            fpos = infected * (1 - self.arr)

            tp = sum(tpos)
            fp = sum(fpos)
            fn = sum(fneg)

            # The following assertion is no longer valid due to infected_high_precision
            # being added to infected_dd, for precise_SBL_FOO algorithms. We'll ignore
            # the assertion for now.
            try:
                assert surep <= tp
            except:
                if not algo.startswith('precise_SBL_'):
                    raise
            # Following stat is not valid in some cases when using precise_SBL_
            unsurep = tp + fp - surep
        else:
            tp = 0
            fp = 0
            fn = 0
            surep = 0
            unsurep = 0

        num_infected_in_test = np.zeros(self.t, dtype=np.int32)
        for test in range(self.t):
            for person in range(self.n):
                if infected[person] > 0 and self.M[person, test] == 1:
                    num_infected_in_test[test] += 1

        return answer, infected, infected_dd, prob1, prob0, score, tp, fp, fn,\
            num_unconfident_negatives, determined, overdetermined, surep,\
            unsurep, wrongly_undetected, num_infected_in_test
Esempio n. 12
0
import pylops

plt.close('all')
np.random.seed(0)

###############################################################################
# Let's start with a simple example, where we create a dense mixing matrix
# and a sparse signal and we use OMP and ISTA to recover such a signal.
# Note that the mixing matrix leads to an underdetermined system of equations
# (:math:`N < M`) so being able to add some extra prior information regarding
# the sparsity of our desired model is essential to be able to invert
# such a system.

N, M = 15, 20
Aop = pylops.MatrixMult(np.random.randn(N, M))

x = np.random.rand(M)
x[x < 0.9] = 0
y = Aop * x

# ISTA
eps = 0.5
maxit = 1000
x_omp = pylops.optimization.sparsity.OMP(Aop, y, maxit, sigma=1e-4)[0]
x_ista = pylops.optimization.sparsity.ISTA(Aop,
                                           y,
                                           maxit,
                                           eps=eps,
                                           tol=0,
                                           returninfo=True)[0]
Esempio n. 13
0
import matplotlib.pyplot as plt
import matplotlib.gridspec as pltgs

import pylops

plt.close('all')
# sphinx_gallery_thumbnail_number = 2

###############################################################################
# Let's define the sizes of the matrix :math:`\mathbf{A}` (``N`` and ``M``) and
# fill the matrix with random numbers

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

x = np.ones(M)

###############################################################################
# We can now apply the forward operator to create the data vector :math:`\mathbf{y}`
# and use ``/`` to solve the system by means of an explicit solver.

y = Aop * x
xest = Aop / y

###############################################################################
# Let's visually plot the system of equations we just solved.
gs = pltgs.GridSpec(1, 6)
fig = plt.figure(figsize=(7, 3))
ax = plt.subplot(gs[0, 0])
Esempio n. 14
0
plt.plot(x, x, 'k', lw=2, label='x')
plt.plot(x, xp, 'r', lw=2, label='prox(x)')
plt.plot(x, xdp, 'b', lw=2, label='dualprox(x)')
plt.xlabel('x')
plt.title(r'$||x-b||_2^2$')
plt.legend()
plt.tight_layout()

###############################################################################
# Finally we can also multiply x by a matrix A
x = np.arange(-1, 1, 0.1)
nx = len(x)
ny = nx * 2
A = np.random.normal(0, 1, (ny, nx))

l2 = pyproximal.L2(sigma=2., b=np.ones(ny), Op=pylops.MatrixMult(A))
print('||Ax-b||_2^2: ', l2(x))

tau = 2
xp = l2.prox(x, tau)
xdp = l2.proxdual(x, tau)

plt.figure(figsize=(7, 2))
plt.plot(x, x, 'k', lw=2, label='x')
plt.plot(x, xp, 'r', lw=2, label='prox(x)')
plt.plot(x, xdp, 'b', lw=2, label='dualprox(x)')
plt.xlabel('x')
plt.title(r'$||Ax-b||_2^2$')
plt.legend()
plt.tight_layout()
Esempio n. 15
0
m1, m2 = np.meshgrid(m1, m2, indexing='ij')
mgrid = np.vstack((m1.ravel(), m2.ravel()))
J = 0.5 * np.sum(mgrid * np.dot(G, mgrid), axis=0) - np.dot(d, mgrid)
J = J.reshape(nm1, nm2)

###############################################################################
# We can now define the upper and lower bounds of the box and again we create
# a grid to display alongside the solution
lower = 1.5
upper = 3
indic = (mgrid > lower) & (mgrid < upper)
indic = indic[0].reshape(nm1, nm2) & indic[1].reshape(nm1, nm2)

###############################################################################
# We can now define both the quadratic functional and the box
l2 = pyproximal.L2(Op=pylops.MatrixMult(G), b=d, niter=2)
ind = pyproximal.Box(lower, upper)


###############################################################################
# We are now ready to solve our problem. All we need to do is to choose an
# initial guess for the proximal gradient algorithm
def callback(x):
    mhist.append(x)


m0 = np.array([4, 3])

mhist = [
    m0,
]
Esempio n. 16
0
                 color='black')
    ax7.errorbar(np.sqrt(u_points**2 + v_points**2),
                 phase[ind],
                 yerr=phase_err[ind],
                 fmt='o',
                 color='black')

    values = range(len(lambd_values3))
    jet = plt.get_cmap('jet')
    cNorm = colors.Normalize(vmin=0, vmax=values[-1])
    scalarMap = cm.ScalarMappable(norm=cNorm, cmap=jet)
    ii = 0
    for m in lambd_values3:
        colorVal = scalarMap.to_rgba(values[ii])
        sigma = m
        Aop = pylops.MatrixMult(dict_0)
        X_mp = sparsity.OMP(Aop,
                            Y,
                            niter_outer=1000,
                            niter_inner=1000,
                            sigma=sigma)
        rec = np.dot(dict_0, X_mp[0])
        u_points = u[ind] / waves
        v_points = v[ind] / waves
        ax6.plot(np.sqrt(u_points**2 + v_points**2),
                 rec[0:len(ind)],
                 'o',
                 label=str(np.round(alpha, 3)),
                 zorder=500,
                 alpha=0.5,
                 color=colorVal)
Esempio n. 17
0
import pylops

plt.close('all')
np.random.seed(0)

###############################################################################
# To start we create the forward problem

n = 5
x = np.arange(n) + 1.

# make A
Ar = np.random.normal(0, 1, (n, n))
Ai = np.random.normal(0, 1, (n, n))
A = Ar + 1j * Ai
Aop = pylops.MatrixMult(A, dtype=np.complex)
y = Aop @ x

###############################################################################
# Let's check we can solve this problem using the first formulation
A1op = Aop.toreal(forw=False, adj=True)
xinv = A1op.div(y)

print('xinv=%s\n' % xinv)

###############################################################################
# Let's now see how we formulate the second problem
Amop = pylops.MemoizeOperator(Aop, max_neval=10)
Arop = Amop.toreal()
Aiop = Amop.toimag()
Esempio n. 18
0
import pylops

import pyproximal

plt.close('all')

###############################################################################
# To start with cosider the most complete case when both :math:`\mathbf{Op}` and
# :math:`\mathbf{Op}` are non-null.
x = np.arange(-5, 5, 0.1)
nx = len(x)

A = np.random.normal(0, 1, (nx, nx))
A = A.T @ A
c = 2.
quad = pyproximal.Quadratic(Op=pylops.MatrixMult(A), b=np.ones_like(x), c=c,
                            niter=500)
print('1/2 x^T Op x + b^T x + c: ', quad(x))

tau = 4
xp = quad.prox(x, tau)
xdp = quad.proxdual(x, tau)

plt.figure(figsize=(7, 2))
plt.plot(x, x, 'k', lw=2, label='x')
plt.plot(x, xp, 'r', lw=2, label='prox(x)')
plt.plot(x, xdp, 'b', lw=2, label='dualprox(x)')
plt.xlabel('x')
plt.title(r'$\frac{1}{2} \mathbf{x}^T \mathbf{Op} \mathbf{x} + '
          r'\mathbf{b}^T \mathbf{x} + c$')
plt.legend()