pyproximal.optimization.primaldual.PrimalDual¶
- pyproximal.optimization.primaldual.PrimalDual(proxf: ProxOperator, proxg: ProxOperator, A: LinearOperator, x0: ndarray[tuple[Any, ...], dtype[_ScalarT]], tau: float | ndarray[tuple[Any, ...], dtype[_ScalarT]], mu: float | ndarray[tuple[Any, ...], dtype[_ScalarT]], y0: ndarray[tuple[Any, ...], dtype[_ScalarT]] | None = None, z: ndarray[tuple[Any, ...], dtype[_ScalarT]] | None = None, theta: float = 1.0, niter: int = 10, gfirst: bool = True, callback: Callable[[...], None] | None = None, callbacky: bool = False, returny: bool = False, show: bool = False) ndarray[tuple[Any, ...], dtype[_ScalarT]] | tuple[ndarray[tuple[Any, ...], dtype[_ScalarT]], ndarray[tuple[Any, ...], dtype[_ScalarT]]][source]¶
Primal-dual algorithm
Solves the following (possibly) nonlinear minimization problem using the general version of the first-order primal-dual algorithm of [1]:
\[\min_{\mathbf{x} \in X} g(\mathbf{Ax}) + f(\mathbf{x}) + \mathbf{z}^T \mathbf{x}\]where \(\mathbf{A}\) is a linear operator, \(f\) and \(g\) can be any convex functions that have a known proximal operator.
This functional is effectively minimized by solving its equivalent primal-dual problem (primal in \(f\), dual in \(g\)):
\[\min_{\mathbf{x} \in X} \max_{\mathbf{y} \in Y} \mathbf{y}^T(\mathbf{Ax}) + \mathbf{z}^T \mathbf{x} + f(\mathbf{x}) - g^*(\mathbf{y})\]where \(\mathbf{y}\) is the so-called dual variable.
- Parameters:
- proxf
pyproximal.ProxOperator Proximal operator of f function
- proxg
pyproximal.ProxOperator Proximal operator of g function
- A
pylops.LinearOperator Linear operator of g
- x0
numpy.ndarray Initial vector
- tau
floatornumpy.ndarray Stepsize of subgradient of \(f\). This can be constant or function of iterations (in the latter cases provided as np.ndarray)
- mu
floatornumpy.ndarray Stepsize of subgradient of \(g^*\). This can be constant or function of iterations (in the latter cases provided as np.ndarray)
- y0
numpy.ndarray Initial auxiliary vector. If
None, set to zero- z
numpy.ndarray, optional Additional vector
- theta
float Scalar between 0 and 1 that defines the update of the \(\bar{\mathbf{x}}\) variable - note that
theta=0is a special case that represents the semi-implicit classical Arrow-Hurwicz algorithm- niter
int, optional Number of iterations of iterative scheme
- gfirst
bool, optional Apply Proximal of operator
gfirst (True) or Proximal of operatorffirst (False)- callback
callable, optional Function with signature (
callback(x)) to call after each iteration wherexis the current model vector- callbacky
bool, optional Modify callback signature to (
callback(x, y)) whencallbacky=True- returny
bool, optional Return also
y- show
bool, optional Display iterations log
- proxf
- Returns:
- x
numpy.ndarray Inverted model
- y
numpy.ndarray, optional Inverted second model, only returned if
returny=True
- x
Notes
The Primal-dual algorithm can be expressed by the following recursion (
gfirst=True):\[\begin{split}\mathbf{y}^{k+1} = \prox_{\mu g^*}(\mathbf{y}^{k} + \mu \mathbf{A}\bar{\mathbf{x}}^{k})\\ \mathbf{x}^{k+1} = \prox_{\tau f}(\mathbf{x}^{k} - \tau (\mathbf{A}^H \mathbf{y}^{k+1} + \mathbf{z})) \\ \bar{\mathbf{x}}^{k+1} = \mathbf{x}^{k+1} + \theta (\mathbf{x}^{k+1} - \mathbf{x}^k)\end{split}\]where \(\tau \mu \lambda_{max}(\mathbf{A}^H\mathbf{A}) < 1\).
Alternatively for
gfirst=Falsethe scheme becomes:\[\begin{split}\mathbf{x}^{k+1} = \prox_{\tau f}(\mathbf{x}^{k} - \tau (\mathbf{A}^H \mathbf{y}^{k} + \mathbf{z})) \\ \bar{\mathbf{x}}^{k+1} = \mathbf{x}^{k+1} + \theta (\mathbf{x}^{k+1} - \mathbf{x}^k) \\ \mathbf{y}^{k+1} = \prox_{\mu g^*}(\mathbf{y}^{k} + \mu \mathbf{A}\bar{\mathbf{x}}^{k+1})\end{split}\][1]A., Chambolle, and T., Pock, “A first-order primal-dual algorithm for convex problems with applications to imaging”, Journal of Mathematical Imaging and Vision, 40, 8pp. 120-145. 2011.