Source code for odl.solvers.nonsmooth.difference_convex

# Copyright 2014-2019 The ODL contributors
#
# This file is part of ODL.
#
# This Source Code Form is subject to the terms of the Mozilla Public License,
# v. 2.0. If a copy of the MPL was not distributed with this file, You can
# obtain one at https://mozilla.org/MPL/2.0/.

"""Solvers for the optimization of the difference of convex functions.

Collection of DCA (d.c. algorithms) and related methods which make use of
structured optimization if the objective function can be written as a
difference of two convex functions.
"""

from __future__ import print_function, division, absolute_import

__all__ = ('dca', 'prox_dca', 'doubleprox_dc')


[docs] def dca(x, f, g, niter, callback=None): r"""Subgradient DCA of Tao and An. This algorithm solves a problem of the form :: min_x f(x) - g(x), where ``f`` and ``g`` are proper, convex and lower semicontinuous functions. Parameters ---------- x : `LinearSpaceElement` Initial point, updated in-place. f : `Functional` Convex functional. Needs to implement ``f.convex_conj.gradient``. g : `Functional` Convex functional. Needs to implement ``g.gradient``. niter : int Number of iterations. callback : callable, optional Function called with the current iterate after each iteration. Notes ----- The algorithm is described in Section 3 and in particular in Theorem 3 of `[TA1997] <http://journals.math.ac.vn/acta/pdf/9701289.pdf>`_. The problem .. math:: \min f(x) - g(x) has the first-order optimality condition :math:`0 \in \partial f(x) - \partial g(x)`, i.e., aims at finding an :math:`x` so that there exists a common element .. math:: y \in \partial f(x) \cap \partial g(x). The element :math:`y` can be seen as a solution of the Toland dual problem .. math:: \min g^*(y) - f^*(y) and the iteration is given by .. math:: y_n \in \partial g(x_n), \qquad x_{n+1} \in \partial f^*(y_n), for :math:`n\geq 0`. Here, a subgradient is found by evaluating the gradient method of the respective functionals. References ---------- [TA1997] Tao, P D, and An, L T H. *Convex analysis approach to d.c. programming: Theory, algorithms and applications*. Acta Mathematica Vietnamica, 22.1 (1997), pp 289--355. See also -------- prox_dca : Solver with a proximal step for ``f`` and a subgradient step for ``g``. doubleprox_dc : Solver with proximal steps for all the nonsmooth convex functionals and a gradient step for a smooth functional. """ space = f.domain if g.domain != space: raise ValueError('`f.domain` and `g.domain` need to be equal, but ' '{} != {}'.format(space, g.domain)) f_convex_conj = f.convex_conj for _ in range(niter): f_convex_conj.gradient(g.gradient(x), out=x) if callback is not None: callback(x)
[docs] def prox_dca(x, f, g, niter, gamma, callback=None): r"""Proximal DCA of Sun, Sampaio and Candido. This algorithm solves a problem of the form :: min_x f(x) - g(x) where ``f`` and ``g`` are two proper, convex and lower semicontinuous functions. Parameters ---------- x : `LinearSpaceElement` Initial point, updated in-place. f : `Functional` Convex functional. Needs to implement ``f.proximal``. g : `Functional` Convex functional. Needs to implement ``g.gradient``. niter : int Number of iterations. gamma : positive float Stepsize in the primal updates. callback : callable, optional Function called with the current iterate after each iteration. Notes ----- The algorithm was proposed as Algorithm 2.3 in `[SSC2003] <http://www.global-sci.org/jcm/readabs.php?vol=21&no=4&page=451&year=2003&ppage=462>`_. It solves the problem .. math :: \min f(x) - g(x) by using subgradients of :math:`g` and proximal points of :math:`f`. The iteration is given by .. math :: y_n \in \partial g(x_n), \qquad x_{n+1} = \mathrm{Prox}_{\gamma f}(x_n + \gamma y_n). In contrast to `dca`, `prox_dca` uses proximal steps with respect to the convex part ``f``. Both algorithms use subgradients of the concave part ``g``. References ---------- [SSC2003] Sun, W, Sampaio R J B, and Candido M A B. *Proximal point algorithm for minimization of DC function*. Journal of Computational Mathematics, 21.4 (2003), pp 451--462. See also -------- dca : Solver with subgradinet steps for all the functionals. doubleprox_dc : Solver with proximal steps for all the nonsmooth convex functionals and a gradient step for a smooth functional. """ space = f.domain if g.domain != space: raise ValueError('`f.domain` and `g.domain` need to be equal, but ' '{} != {}'.format(space, g.domain)) for _ in range(niter): f.proximal(gamma)(x.lincomb(1, x, gamma, g.gradient(x)), out=x) if callback is not None: callback(x)
[docs] def doubleprox_dc(x, y, f, phi, g, K, niter, gamma, mu, callback=None): r"""Double-proxmial gradient d.c. algorithm of Banert and Bot. This algorithm solves a problem of the form :: min_x f(x) + phi(x) - g(Kx). Parameters ---------- x : `LinearSpaceElement` Initial primal guess, updated in-place. y : `LinearSpaceElement` Initial dual guess, updated in-place. f : `Functional` Convex functional. Needs to implement ``g.proximal``. phi : `Functional` Convex functional. Needs to implement ``phi.gradient``. Convergence can be guaranteed if the gradient is Lipschitz continuous. g : `Functional` Convex functional. Needs to implement ``h.convex_conj.proximal``. K : `Operator` Linear operator. Needs to implement ``K.adjoint`` niter : int Number of iterations. gamma : positive float Stepsize in the primal updates. mu : positive float Stepsize in the dual updates. callback : callable, optional Function called with the current iterate after each iteration. Notes ----- This algorithm is proposed in `[BB2016] <https://arxiv.org/abs/1610.06538>`_ and solves the d.c. problem .. math :: \min_x f(x) + \varphi(x) - g(Kx) together with its Toland dual .. math :: \min_y g^*(y) - (f + \varphi)^*(K^* y). The iterations are given by .. math :: x_{n+1} &= \mathrm{Prox}_{\gamma f} (x_n + \gamma (K^* y_n - \nabla \varphi(x_n))), \\ y_{n+1} &= \mathrm{Prox}_{\mu g^*} (y_n + \mu K x_{n+1}). To guarantee convergence, the parameter :math:`\gamma` must satisfy :math:`0 < \gamma < 2/L` where :math:`L` is the Lipschitz constant of :math:`\nabla \varphi`. References ---------- [BB2016] Banert, S, and Bot, R I. *A general double-proximal gradient algorithm for d.c. programming*. arXiv:1610.06538 [math.OC] (2016). See also -------- dca : Solver with subgradient steps for all the functionals. prox_dca : Solver with a proximal step for ``f`` and a subgradient step for ``g``. """ primal_space = f.domain dual_space = g.domain if phi.domain != primal_space: raise ValueError('`f.domain` and `phi.domain` need to be equal, but ' '{} != {}'.format(primal_space, phi.domain)) if K.domain != primal_space: raise ValueError('`f.domain` and `K.domain` need to be equal, but ' '{} != {}'.format(primal_space, K.domain)) if K.range != dual_space: raise ValueError('`g.domain` and `K.range` need to be equal, but ' '{} != {}'.format(dual_space, K.range)) g_convex_conj = g.convex_conj for _ in range(niter): f.proximal(gamma)(x.lincomb(1, x, gamma, K.adjoint(y) - phi.gradient(x)), out=x) g_convex_conj.proximal(mu)(y.lincomb(1, y, mu, K(x)), out=y) if callback is not None: callback(x)
[docs] def doubleprox_dc_simple(x, y, f, phi, g, K, niter, gamma, mu): """Non-optimized version of ``doubleprox_dc``. This function is intended for debugging. It makes a lot of copies and performs no error checking. """ for _ in range(niter): f.proximal(gamma)(x + gamma * K.adjoint(y) - gamma * phi.gradient(x), out=x) g.convex_conj.proximal(mu)(y + mu * K(x), out=y)