示例#1
0
 def set_objective(self, X, y, lmbd):
     self.X, self.y, self.lmbd = X, y, lmbd
     n_features = self.X.shape[1]
     if self.restart_strategy == 'greedy':
         min_beta = 1.0
         s_greedy = 1.1
         p_lazy = 1.0
         q_lazy = 1.0
     else:
         min_beta = None
         s_greedy = None
         p_lazy = 1 / 30
         q_lazy = 1 / 10
     self.fb = ForwardBackward(
         x=np.zeros(n_features),  # this is the coefficient w
         grad=GradBasic(
             input_data=y,
             op=lambda w: self.X@w,
             trans_op=lambda res: self.X.T@res,
         ),
         prox=SparseThreshold(Identity(), lmbd),
         beta_param=1.0,
         min_beta=min_beta,
         metric_call_period=None,
         restart_strategy=self.restart_strategy,
         xi_restart=0.96,
         s_greedy=s_greedy,
         p_lazy=p_lazy,
         q_lazy=q_lazy,
         auto_iterate=False,
         progress=False,
         cost=None,
     )
示例#2
0
def fista(gradient_op,
          linear_op,
          prox_op,
          cost_op,
          lambda_init=1.0,
          max_nb_of_iter=300,
          x_init=None,
          metric_call_period=5,
          metrics={},
          verbose=0,
          **lambda_update_params):
    """ The FISTA sparse reconstruction

    Parameters
    ----------
    gradient_op: instance of class GradBase
        the gradient operator.
    linear_op: instance of LinearBase
        the linear operator: seek the sparsity, ie. a wavelet transform.
    prox_op: instance of ProximityParent
        the proximal operator.
    cost_op: instance of costObj
        the cost function used to check for convergence during the
        optimization.
    lambda_init: float, (default 1.0)
        initial value for the FISTA step.
    max_nb_of_iter: int (optional, default 300)
        the maximum number of iterations in the Condat-Vu proximal-dual
        splitting algorithm.
    x_init: np.ndarray (optional, default None)
        Inital guess for the image
    metric_call_period: int (default 5)
        the period on which the metrics are compute.
    metrics: dict (optional, default None)
        the list of desired convergence metrics: {'metric_name':
        [@metric, metric_parameter]}. See modopt for the metrics API.
    verbose: int (optional, default 0)
        the verbosity level.
    lambda_update_params: dict,
        Parameters for the lambda update in FISTA mode

    Returns
    -------
    x_final: ndarray
        the estimated FISTA solution.
    costs: list of float
        the cost function values.
    metrics: dict
        the requested metrics values during the optimization.
    """
    start = time.perf_counter()

    # Define the initial primal and dual solutions
    if x_init is None:
        x_init = np.squeeze(
            np.zeros(
                (gradient_op.linear_op.n_coils, *gradient_op.fourier_op.shape),
                dtype=np.complex))
    alpha_init = linear_op.op(x_init)

    # Welcome message
    if verbose > 0:
        print(" - mu: ", prox_op.weights)
        print(" - lipschitz constant: ", gradient_op.spec_rad)
        print(" - data: ", gradient_op.fourier_op.shape)
        if hasattr(linear_op, "nb_scale"):
            print(" - wavelet: ", linear_op, "-", linear_op.nb_scale)
        print(" - max iterations: ", max_nb_of_iter)
        print(" - image variable shape: ", gradient_op.fourier_op.shape)
        print(" - alpha variable shape: ", alpha_init.shape)
        print("-" * 40)

    beta_param = gradient_op.inv_spec_rad
    if lambda_update_params.get("restart_strategy") == "greedy":
        lambda_update_params["min_beta"] = gradient_op.inv_spec_rad
        # this value is the recommended one by J. Liang in his article
        # when introducing greedy FISTA.
        # ref: https://arxiv.org/pdf/1807.04005.pdf
        beta_param *= 1.3

    # Define the optimizer
    opt = ForwardBackward(x=alpha_init,
                          grad=gradient_op,
                          prox=prox_op,
                          cost=cost_op,
                          auto_iterate=False,
                          metric_call_period=metric_call_period,
                          metrics=metrics,
                          linear=linear_op,
                          lambda_param=lambda_init,
                          beta_param=beta_param,
                          **lambda_update_params)
    cost_op = opt._cost_func

    # Perform the reconstruction
    if verbose > 0:
        print("Starting optimization...")
    opt.iterate(max_iter=max_nb_of_iter)
    end = time.perf_counter()
    if verbose > 0:
        # cost_op.plot_cost()
        if hasattr(cost_op, "cost"):
            print(" - final iteration number: ", cost_op._iteration)
            print(" - final log10 cost value: ", np.log10(cost_op.cost))
        print(" - converged: ", opt.converge)
        print("Done.")
        print("Execution time: ", end - start, " seconds")
        print("-" * 40)
    x_final = linear_op.adj_op(opt.x_final)
    if hasattr(cost_op, "cost"):
        costs = cost_op._cost_list
    else:
        costs = None

    return x_final, costs, opt.metrics
示例#3
0
def sparse_rec_fista(gradient_op,
                     linear_op,
                     prox_op,
                     cost_op,
                     mu=1e-6,
                     nb_scales=4,
                     lambda_init=1.0,
                     max_nb_of_iter=300,
                     atol=1e-4,
                     metric_call_period=5,
                     metrics=None,
                     verbose=0):
    """ The FISTA sparse reconstruction without reweightings.

    .. note:: At the moment, tested only with 2D data.

    Parameters
    ----------
    gradient_op: instance of class GradBase
        the gradient operator.
    linear_op: instance of LinearBase
        the linear operator: seek the sparsity, ie. a wavelet transform.
    prox_op: instance of ProximityParent
        the proximal operator.
    cost_op: instance of costObj
        the cost function used to check for convergence during the
        optimization.
    mu: float, (default 1e-6)
       coefficient of regularization.
    nb_scales: int, default 4
        the number of scales in the wavelet decomposition.
    lambda_init: float, (default 1.0)
        initial value for the FISTA step.
    max_nb_of_iter: int (optional, default 300)
        the maximum number of iterations in the Condat-Vu proximal-dual
        splitting algorithm.
    atol: float (optional, default 1e-4)
        tolerance threshold for convergence.
    metric_call_period: int (default 5)
        the period on which the metrics are compute.
    metrics: dict (optional, default None)
        the list of desired convergence metrics: {'metric_name':
        [@metric, metric_parameter]}. See modopt for the metrics API.
    verbose: int (optional, default 0)
        the verbosity level.

    Returns
    -------
    x_final: ndarray
        the estimated FISTA solution.
    transform: a WaveletTransformBase derived instance
        the wavelet transformation instance.
    costs: list of float
        the cost function values.
    metrics: dict
        the requested metrics values during the optimization.
    """
    # Check inputs
    start = time.clock()
    if not linear_op.transform.__is_decimated__:
        warnings.warn("Undecimated wavelets shouldn't be used with FISTA: "
                      "non optimal solution.")

    # Define the initial primal and dual solutions
    x_init = np.zeros(gradient_op.fourier_op.shape, dtype=np.complex)
    alpha = linear_op.op(x_init)
    alpha[...] = 0.0

    # Welcome message
    if verbose > 0:
        print(fista_logo())
        print(" - mu: ", mu)
        print(" - lipschitz constant: ", gradient_op.spec_rad)
        print(" - data: ", gradient_op.fourier_op.shape)
        if hasattr(linear_op, "nb_scale"):
            print(" - wavelet: ", linear_op, "-", linear_op.nb_scale)
        print(" - max iterations: ", max_nb_of_iter)
        print(" - image variable shape: ", x_init.shape)
        print(" - alpha variable shape: ", alpha.shape)
        print("-" * 40)

    # Define the proximity dual operator
    weights = copy.deepcopy(alpha)
    weights[...] = mu
    prox_op.weights = weights

    # Define the optimizer
    opt = ForwardBackward(x=alpha,
                          grad=gradient_op,
                          prox=prox_op,
                          cost=cost_op,
                          auto_iterate=False,
                          metric_call_period=metric_call_period,
                          metrics=metrics or {},
                          linear=linear_op,
                          beta_param=gradient_op.inv_spec_rad)
    cost_op = opt._cost_func

    # Perform the reconstruction
    if verbose > 0:
        print("Starting optimization...")
    opt.iterate(max_iter=max_nb_of_iter)
    end = time.clock()
    if verbose > 0:
        # cost_op.plot_cost()
        if hasattr(cost_op, "cost"):
            print(" - final iteration number: ", cost_op._iteration)
            print(" - final log10 cost value: ", np.log10(cost_op.cost))
        print(" - converged: ", opt.converge)
        print("Done.")
        print("Execution time: ", end - start, " seconds")
        print("-" * 40)
    x_final = linear_op.adj_op(opt.x_final)
    if hasattr(cost_op, "cost"):
        costs = cost_op._cost_list
    else:
        costs = None

    return x_final, linear_op.transform, costs, opt.metrics
示例#4
0
class Solver(BaseSolver):
    name = 'ModOpt-FISTA'
    stop_strategy = 'iteration'
    install_cmd = 'conda'
    requirements = [
        'pip:git+https://github.com/CEA-COSMIC/ModOpt.git',
    ]
    parameters = {
        'restart_strategy': ['greedy', 'adaptive-1'],
    }
    references = [
        'S. Farrens, A. Grigis, L. El Gueddari, Z. Ramzi, G. R. Chaithya, '
        'S. Starck, B. Sarthou, H. Cherkaoui, P. Ciuciu and J.-L. Starck, '
        '"PySAP: Python Sparse Data Analysis Package for multidisciplinary '
        'image processing", Astronomy and Computing, vol. 32, '
        ' pp. 100402 (2020)'
    ]
    support_sparse = False

    def set_objective(self, X, y, lmbd):
        self.X, self.y, self.lmbd = X, y, lmbd
        n_features = self.X.shape[1]
        if self.restart_strategy == 'greedy':
            min_beta = 1.0
            s_greedy = 1.1
            p_lazy = 1.0
            q_lazy = 1.0
        else:
            min_beta = None
            s_greedy = None
            p_lazy = 1 / 30
            q_lazy = 1 / 10
        self.fb = ForwardBackward(
            x=np.zeros(n_features),  # this is the coefficient w
            grad=GradBasic(
                input_data=y,
                op=lambda w: self.X@w,
                trans_op=lambda res: self.X.T@res,
            ),
            prox=SparseThreshold(Identity(), lmbd),
            beta_param=1.0,
            min_beta=min_beta,
            metric_call_period=None,
            restart_strategy=self.restart_strategy,
            xi_restart=0.96,
            s_greedy=s_greedy,
            p_lazy=p_lazy,
            q_lazy=q_lazy,
            auto_iterate=False,
            progress=False,
            cost=None,
        )

    def run(self, n_iter):
        L = np.linalg.norm(self.X, ord=2) ** 2
        if self.restart_strategy == 'greedy':
            beta_param = 1.3 * (1/L)
        else:
            beta_param = 1 / L
        self.fb.beta_param = beta_param
        self.fb._beta = self.fb.step_size or beta_param
        self.fb.iterate(max_iter=n_iter)

    def get_result(self):
        return self.fb.x_final
示例#5
0
def sparse_rec_fista(gradient_op,
                     linear_op,
                     mu,
                     lambda_init=1.0,
                     max_nb_of_iter=300,
                     atol=1e-4,
                     verbose=0,
                     get_cost=False):
    """ The FISTA sparse reconstruction without reweightings.

    .. note:: At the moment, supports only 2D data.

    Parameters
    ----------
    gradient_op: Instance of class GradBase
        The gradient operator of the differentiable part
    linear_op: Instance of LinearBase
        The linear operator is the tranform in wich we seek the sparsity.
    samples: np.ndarray
        the mask samples in the Fourier domain.
    mu: float
       coefficient of regularization.
    nb_scales: int, default 4
        the number of scales in the wavelet decomposition.
    lambda_init: float, (default 1.0)
        initial value for the FISTA step.
    max_nb_of_iter: int (optional, default 300)
        the maximum number of iterations in the Condat-Vu proximal-dual
        splitting algorithm.
    atol: float (optional, default 1e-4)
        tolerance threshold for convergence.
    verbose: int (optional, default 0)
        the verbosity level.
    get_cost: bool (default False)
        computes the cost of the objective function

    Returns
    -------
    x_final: ndarray
        the estimated FISTA solution.
    transform: a WaveletTransformBase derived instance
        the wavelet transformation instance.
    """
    # Check inputs
    start = time.clock()

    # Define the initial primal and dual solutions
    x_init = np.zeros(gradient_op.fourier_op.shape, dtype=np.complex)
    alpha = linear_op.op(x_init)
    alpha[...] = 0.0

    # Welcome message
    if verbose > 0:
        print(fista_logo())
        print(" - mu: ", mu)
        print(" - lipschitz constant: ", gradient_op.spec_rad)
        print(" - data: ", gradient_op.obs_data.shape)
        print(" - max iterations: ", max_nb_of_iter)
        print(" - image variable shape: ", x_init.shape)
        print(" - alpha variable shape: ", alpha.shape)
        print("-" * 40)

    # Define the proximity dual operator
    weights = copy.deepcopy(alpha)
    weights[...] = mu
    prox_op = Threshold(weights)

    # Define the optimizer
    cost_op = None
    opt = ForwardBackward(x=alpha,
                          grad=gradient_op,
                          prox=prox_op,
                          cost=cost_op,
                          auto_iterate=False)

    # Perform the reconstruction

    if verbose > 0:
        print("Starting optimization...")

    if get_cost:
        cost = np.zeros(max_nb_of_iter)

    for i in range(max_nb_of_iter):
        opt._update()
        if get_cost:
            cost[i] = gradient_op.get_cost(opt._x_new) + \
                      prox_op.get_cost(opt._x_new)
        if opt.converge:
            print(' - Converged!')
            if get_cost:
                cost = cost[0:i]
            break

    opt.x_final = opt._x_new
    end = time.clock()
    if verbose > 0:
        # cost_op.plot_cost()
        # print(" - final iteration number: ", cost_op._iteration)
        # print(" - final log10 cost value: ", np.log10(cost_op.cost))
        print(" - converged: ", opt.converge)
        print("Done.")
        print("Execution time: ", end - start, " seconds")
        print("-" * 40)
    x_final = linear_op.adj_op(opt.x_final)

    if get_cost:
        return x_final, linear_op.transform, cost
    else:
        return x_final, linear_op.transform
示例#6
0
def fista_online(kspace_generator,
                 gradient_op,
                 linear_op,
                 prox_op,
                 cost_op,
                 lambda_init=1.0,
                 x_init=None,
                 nb_run=1,
                 metric_call_period=5,
                 metrics=None,
                 estimate_call_period=None,
                 verbose=0,
                 **lambda_update_params):
    """The FISTA sparse reconstruction

    Parameters
    ----------
    kspace_generator: instance of class KspaceGenerator
        the observed data (ie kspace) generated for each iteration of the algorithm
    gradient_op: instance of class GradBase
        the gradient operator.
    linear_op: instance of LinearBase
        the linear operator: seek the sparsity, ie. a wavelet transform.
    prox_op: instance of ProximityParent
        the proximal operator.
    cost_op: instance of costObj
        the cost function used to check for convergence during the
        optimization.
    lambda_init: float, (default 1.0)
        initial value for the FISTA step.
    x_init: np.ndarray (optional, default None)
        Inital guess for the image
    metric_call_period: int (default 5)
        the period on which the metrics are compute.
    metrics: dict (optional, default None)
        the list of desired convergence metrics: {'metric_name':
        [@metric, metric_parameter]}. See modopt for the metrics API.
    verbose: int (optional, default 0)
        the verbosity level.
    lambda_update_params: dict,
        Parameters for the lambda update in FISTA mode

    Returns
    -------
    x_final: ndarray
        the estimated FISTA solution.
    costs: list of float
        the cost function values.
    metrics: dict
        the requested metrics values during the optimization.
    """
    if metrics is None:
        metrics = dict()
    start = time.perf_counter()

    # Define the initial primal and dual solutions
    if x_init is None:
        x_init = np.squeeze(
            np.zeros(
                (gradient_op.fourier_op.n_coils,
                 *gradient_op.fourier_op.shape),
                dtype=np.complex,
            ))
    alpha_init = linear_op.op(x_init)

    # Welcome message
    if verbose > 0:
        print(" - mu: ", prox_op.weights)
        print(" - lipschitz constant: ", gradient_op.spec_rad)
        print(" - data: ", gradient_op.fourier_op.shape)
        if hasattr(linear_op, "nb_scale"):
            print(" - wavelet: ", linear_op, "-", linear_op.nb_scale)
        print(" - image variable shape: ", gradient_op.fourier_op.shape)
        print(" - alpha variable shape: ", alpha_init.shape)
        print("-" * 40)

    beta_param = gradient_op.inv_spec_rad
    if lambda_update_params.get("restart_strategy") == "greedy":
        lambda_update_params["min_beta"] = gradient_op.inv_spec_rad
        # this value is the recommended one by J. Liang in his article
        # when introducing greedy FISTA.
        # ref: https://arxiv.org/pdf/1807.04005.pdf
        beta_param *= 1.3

    # Define the optimizer
    opt = ForwardBackward(x=alpha_init,
                          grad=gradient_op,
                          prox=prox_op,
                          cost=cost_op,
                          auto_iterate=False,
                          metric_call_period=metric_call_period,
                          metrics=metrics,
                          linear=linear_op,
                          lambda_param=lambda_init,
                          beta_param=beta_param,
                          **lambda_update_params)
    cost_op = opt._cost_func

    return online_algorithm(opt,
                            kspace_generator,
                            estimate_call_period=estimate_call_period,
                            nb_run=nb_run)
示例#7
0
def sparse_rec_fista(data, wavelet_name, samples, mu, nb_scales=4,
                     lambda_init=1.0, max_nb_of_iter=300, atol=1e-4,
                     non_cartesian=False, uniform_data_shape=None, verbose=0):
    """ The FISTA sparse reconstruction without reweightings.

    .. note:: At the moment, supports only 2D data.

    Parameters
    ----------
    data: ndarray
        the data to reconstruct (observation are expected in the Fourier
        space).
    wavelet_name: str
        the wavelet name to be used during the decomposition.
    samples: np.ndarray
        the mask samples in the Fourier domain.
    mu: float
       coefficient of regularization.
    nb_scales: int, default 4
        the number of scales in the wavelet decomposition.
    lambda_init: float, (default 1.0)
        initial value for the FISTA step.
    max_nb_of_iter: int (optional, default 300)
        the maximum number of iterations in the Condat-Vu proximal-dual
        splitting algorithm.
    atol: float (optional, default 1e-4)
        tolerance threshold for convergence.
    non_cartesian: bool (optional, default False)
        if set, use the nfftw rather than the fftw. Expect an 1D input dataset.
    uniform_data_shape: uplet (optional, default None)
        the shape of the matrix containing the uniform data. Only required
        for non-cartesian reconstructions.
    verbose: int (optional, default 0)
        the verbosity level.

    Returns
    -------
    x_final: ndarray
        the estimated FISTA solution.
    transform: a WaveletTransformBase derived instance
        the wavelet transformation instance.
    """
    # Check inputs
    start = time.clock()
    if non_cartesian and data.ndim != 1:
        raise ValueError("Expect 1D data with the non-cartesian option.")
    elif non_cartesian and uniform_data_shape is None:
        raise ValueError("Need to set the 'uniform_data_shape' parameter with "
                         "the non-cartesian option.")
    elif not non_cartesian and data.ndim != 2:
        raise ValueError("At the moment, this functuion only supports 2D "
                         "data.")

    # Define the gradient/linear/fourier operators
    linear_op = Wavelet2(
        nb_scale=nb_scales,
        wavelet_name=wavelet_name)
    if non_cartesian:
        fourier_op = NFFT2(
            samples=samples,
            shape=uniform_data_shape)
    else:
        fourier_op = FFT2(
            samples=samples,
            shape=data.shape)
    gradient_op = GradSynthesis2(
        data=data,
        linear_op=linear_op,
        fourier_op=fourier_op)

    # Define the initial primal and dual solutions
    x_init = np.zeros(fourier_op.shape, dtype=np.complex)
    alpha = linear_op.op(x_init)
    alpha[...] = 0.0

    # Welcome message
    if verbose > 0:
        print(fista_logo())
        print(" - mu: ", mu)
        print(" - lipschitz constant: ", gradient_op.spec_rad)
        print(" - data: ", data.shape)
        print(" - wavelet: ", wavelet_name, "-", nb_scales)
        print(" - max iterations: ", max_nb_of_iter)
        print(" - image variable shape: ", x_init.shape)
        print(" - alpha variable shape: ", alpha.shape)
        print("-" * 40)

    # Define the proximity dual operator
    weights = copy.deepcopy(alpha)
    weights[...] = mu
    prox_op = SparseThreshold(linear_op, weights, thresh_type="soft")

    # Define the optimizer
    cost_op = None
    opt = ForwardBackward(
        x=alpha,
        grad=gradient_op,
        prox=prox_op,
        cost=cost_op,
        auto_iterate=False)

    # Perform the reconstruction
    end = time.clock()
    if verbose > 0:
        print("Starting optimization...")
    opt.iterate(max_iter=max_nb_of_iter)
    if verbose > 0:
        # cost_op.plot_cost()
        # print(" - final iteration number: ", cost_op._iteration)
        # print(" - final log10 cost value: ", np.log10(cost_op.cost))
        print(" - converged: ", opt.converge)
        print("Done.")
        print("Execution time: ", end - start, " seconds")
        print("-" * 40)
    x_final = linear_op.adj_op(opt.x_final)

    return x_final, linear_op.transform
示例#8
0
def fista(gradient_op,
          linear_op,
          prox_op,
          cost_op,
          kspace_generator=None,
          estimate_call_period=None,
          lambda_init=1.0,
          max_nb_of_iter=300,
          x_init=None,
          metric_call_period=5,
          metrics={},
          verbose=0,
          **lambda_update_params):
    """FISTA sparse reconstruction.

    Parameters
    ----------
    gradient_op: instance of class GradBase
        the gradient operator.
    linear_op: instance of LinearBase
        the linear operator: seek the sparsity, ie. a wavelet transform.
    prox_op: instance of ProximityParent
        the proximal operator.
    cost_op: instance of costObj
        the cost function used to check for convergence during the
        optimization.
    kspace_generator: instance of class BaseKspaceGenerator, default None
        If not None, run the algorithm in an online way, where the data is
        updated between iterations.
    estimate_call_period: int, default None
        In an online configuration (kspace_generator is defined),
        retrieve partial results at this interval.
    lambda_init: float, (default 1.0)
        initial value for the FISTA step.
    max_nb_of_iter: int (optional, default 300)
        the maximum number of iterations in the Condat-Vu proximal-dual
        splitting algorithm.
    x_init: np.ndarray (optional, default None)
        Inital guess for the image
    metric_call_period: int (default 5)
        the period on which the metrics are compute.
    metrics: dict (optional, default None)
        the list of desired convergence metrics: {'metric_name':
        [@metric, metric_parameter]}. See modopt for the metrics API.
    verbose: int (optional, default 0)
        the verbosity level.
    lambda_update_params: dict,
        Parameters for the lambda update in FISTA mode

    Returns
    -------
    x_final: ndarray
        the estimated FISTA solution.
    costs: list of float
        the cost function values.
    metrics: dict
        the requested metrics values during the optimization.
    """
    # Define the initial primal and dual solutions
    if x_init is None:
        x_init = np.squeeze(
            np.zeros(
                (gradient_op.linear_op.n_coils, *gradient_op.fourier_op.shape),
                dtype=np.complex))
    alpha_init = linear_op.op(x_init)

    # Welcome message
    if verbose > 0:
        print(" - mu: ", prox_op.weights)
        print(" - lipschitz constant: ", gradient_op.spec_rad)
        print(" - data: ", gradient_op.fourier_op.shape)
        if hasattr(linear_op, "nb_scale"):
            print(" - wavelet: ", linear_op, "-", linear_op.nb_scale)
        print(" - max iterations: ", max_nb_of_iter)
        print(" - image variable shape: ", gradient_op.fourier_op.shape)
        print(" - alpha variable shape: ", alpha_init.shape)
        print("-" * 40)

    beta_param = gradient_op.inv_spec_rad
    if lambda_update_params.get("restart_strategy") == "greedy":
        lambda_update_params["min_beta"] = gradient_op.inv_spec_rad
        # this value is the recommended one by J. Liang in his article
        # when introducing greedy FISTA.
        # ref: https://arxiv.org/pdf/1807.04005.pdf
        beta_param *= 1.3

    # Define the optimizer
    opt = ForwardBackward(x=alpha_init,
                          grad=gradient_op,
                          prox=prox_op,
                          cost=cost_op,
                          auto_iterate=False,
                          metric_call_period=metric_call_period,
                          metrics=metrics,
                          linear=linear_op,
                          lambda_param=lambda_init,
                          beta_param=beta_param,
                          **lambda_update_params)
    if kspace_generator is not None:
        return run_online_algorithm(opt, kspace_generator,
                                    estimate_call_period, verbose)
    return run_algorithm(opt, max_nb_of_iter, verbose)