<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def da_spdhg(x, f, g, A, tau, sigma_tilde, niter, mu, **kwargs):
 r"""Computes a saddle point with a PDHG and dual acceleration. It therefore requires the functionals f*_i to be mu[i] strongly convex. Parameters x : primal variable This variable is both input and output of the method. f : functions Functionals Y[i] -> IR_infty that all have a convex conjugate with a proximal operator, i.e. f[i].convex_conj.proximal(sigma[i]) : Y[i] -> Y[i]. g : function Functional X -> IR_infty that has a proximal operator, i.e. g.proximal(tau) : X -> X. A : functions Operators A[i] : X -> Y[i] that possess adjoints: A[i].adjoint tau : scalar Initial step size for primal variable. sigma_tilde : scalar Related to initial step size for dual variable. niter : int Number of iterations mu: list List of strong convexity constants of f*, i.e. mu[i] is the strong convexity constant of f*[i]. Other Parameters y: dual variable Dual variable is part of a product space z: variable Adjoint of dual variable, z = A^* y. prob: list List of probabilities that an index i is selected each iteration. By default this is uniform serial sampling, p_i = 1/n. fun_select : function default this is serial sampling, fun_select(k) selects an index extra: list List of local extrapolation paramters for every index i. By default extra_i = 1 / p_i. callback : callable, optional Function called with the current iterate after each iteration. References [CERS2017] A. Chambolle, M. J. Ehrhardt, P. Richtarik and C.-B. Schoenlieb, *Stochastic Primal-Dual Hybrid Gradient Algorithm with Arbitrary Sampling and Imaging Applications*. ArXiv: http://arxiv.org/abs/1706.04957 (2017). """

    # Callback object
    callback = kwargs.pop('callback', None)
    if callback is not None and not callable(callback):
        raise TypeError('`callback` {} is not callable'
                        ''.format(callback))

    # Probabilities
    prob = kwargs.pop('prob', None)
    if prob is None:
        prob = [1 / len(A)] * len(A)

    # Selection function
    fun_select = kwargs.pop('fun_select', None)
    if fun_select is None:
        def fun_select(x):
            return [int(np.random.choice(len(A), 1, p=prob))]

    # Dual variable
    y = kwargs.pop('y', None)
    if y is None:
        y = A.range.zero()

    # Adjoint of dual variable
    z = kwargs.pop('z', None)
    if z is None and y.norm() == 0:
        z = A.domain.zero()

    # Extrapolation
    extra = kwargs.pop('extra', None)
    if extra is None:
        extra = [1 / p for p in prob]

    # Initialize variables
    z_relax = z.copy()
    dz = A.domain.element()
    y_old = A.range.element()

    # Save proximal operators
    prox_dual = [fi.convex_conj.proximal for fi in f]
    prox_primal = g.proximal

    # run the iterations
    for k in range(niter):

        # select block
        selected = fun_select(k)

        # update extrapolation parameter theta
        theta = float(1 / np.sqrt(1 + 2 * sigma_tilde))

        # update primal variable
        # tmp = x - tau * z_relax; z_relax used as tmp variable
        z_relax.lincomb(1, x, -tau, z_relax)
        # x = prox(tmp)
        prox_primal(tau)(z_relax, out=x)

        # update dual variable and z, z_relax
        z_relax.assign(z)
        for i in selected:

            # compute the step sizes sigma_i based on sigma_tilde
            sigma_i = sigma_tilde / (
                mu[i] * (prob[i] - 2 * (1 - prob[i]) * sigma_tilde))

            # save old yi
            y_old[i].assign(y[i])

            # tmp = Ai(x)
            A[i](x, out=y[i])

            # tmp = y_old + sigma_i * Ai(x)
            y[i].lincomb(1, y_old[i], sigma_i, y[i])

            # yi++ = fi*.prox_sigmai(yi)
            prox_dual[i](sigma_i)(y[i], out=y[i])

            # update adjoint of dual variable
            y_old[i].lincomb(-1, y_old[i], 1, y[i])
            A[i].adjoint(y_old[i], out=dz)
            z += dz

            # compute extrapolation
            z_relax.lincomb(1, z_relax, 1 + theta * extra[i], dz)

        # update the step sizes tau and sigma_tilde for acceleration
        sigma_tilde *= theta
        tau /= theta

        if callback is not None:
            callback([x, y])