@@ -102,8 +102,9 @@ def ProximalPoint(prox, x0, tau, niter=10, callback=None, show=False):
102102 return x
103103
104104
105- def ProximalGradient (proxf , proxg , x0 , tau = None , beta = 0.5 ,
106- epsg = 1. , niter = 10 , niterback = 100 ,
105+ def ProximalGradient (proxf , proxg , x0 , epsg = 1. ,
106+ tau = None , beta = 0.5 , eta = 1. ,
107+ niter = 10 , niterback = 100 ,
107108 acceleration = None ,
108109 callback = None , show = False ):
109110 r"""Proximal gradient (optionally accelerated)
@@ -127,17 +128,19 @@ def ProximalGradient(proxf, proxg, x0, tau=None, beta=0.5,
127128 Proximal operator of g function
128129 x0 : :obj:`numpy.ndarray`
129130 Initial vector
131+ epsg : :obj:`float` or :obj:`np.ndarray`, optional
132+ Scaling factor of g function
130133 tau : :obj:`float` or :obj:`numpy.ndarray`, optional
131134 Positive scalar weight, which should satisfy the following condition
132135 to guarantees convergence: :math:`\tau \in (0, 1/L]` where ``L`` is
133136 the Lipschitz constant of :math:`\nabla f`. When ``tau=None``,
134137 backtracking is used to adaptively estimate the best tau at each
135- iteration. Finally note that :math:`\tau` can be chosen to be a vector
138+ iteration. Finally, note that :math:`\tau` can be chosen to be a vector
136139 when dealing with problems with multiple right-hand-sides
137140 beta : :obj:`float`, optional
138141 Backtracking parameter (must be between 0 and 1)
139- epsg : :obj:`float` or :obj:`np.ndarray `, optional
140- Scaling factor of g function
142+ eta : :obj:`float`, optional
143+ Relaxation parameter (must be between 0 and 1, 0 excluded).
141144 niter : :obj:`int`, optional
142145 Number of iterations of iterative scheme
143146 niterback : :obj:`int`, optional
@@ -161,9 +164,8 @@ def ProximalGradient(proxf, proxg, x0, tau=None, beta=0.5,
161164
162165 .. math::
163166
164-
165- \mathbf{x}^{k+1} = \prox_{\tau^k \epsilon g}(\mathbf{y}^{k+1} -
166- \tau^k \nabla f(\mathbf{y}^{k+1})) \\
167+ \mathbf{x}^{k+1} = \mathbf{y}^k + \eta (\prox_{\tau^k \epsilon g}(\mathbf{y}^k -
168+ \tau^k \nabla f(\mathbf{y}^k)) - \mathbf{y}^k) \\
167169 \mathbf{y}^{k+1} = \mathbf{x}^k + \omega^k
168170 (\mathbf{x}^k - \mathbf{x}^{k-1})
169171
@@ -187,7 +189,7 @@ def ProximalGradient(proxf, proxg, x0, tau=None, beta=0.5,
187189 Different accelerations are provided:
188190
189191 - ``acceleration=None``: :math:`\omega^k = 0`;
190- - `acceleration=vandenberghe`` [1]_: :math:`\omega^k = k / (k + 3)` for `
192+ - `` acceleration=vandenberghe`` [1]_: :math:`\omega^k = k / (k + 3)` for `
191193 - ``acceleration=fista``: :math:`\omega^k = (t_{k-1}-1)/t_k` for where
192194 :math:`t_k = (1 + \sqrt{1+4t_{k-1}^{2}}) / 2` [2]_
193195
@@ -197,7 +199,7 @@ def ProximalGradient(proxf, proxg, x0, tau=None, beta=0.5,
197199 Imaging Sciences, vol. 2, pp. 183-202. 2009.
198200
199201 """
200- # check if epgs is a ve
202+ # check if epgs is a vector
201203 if np .asarray (epsg ).size == 1. :
202204 epsg_print = str (epsg )
203205 else :
@@ -237,10 +239,15 @@ def ProximalGradient(proxf, proxg, x0, tau=None, beta=0.5,
237239
238240 # proximal step
239241 if not backtracking :
240- x = proxg .prox (y - tau * proxf .grad (y ), epsg * tau )
242+ if eta == 1. :
243+ x = proxg .prox (y - tau * proxf .grad (y ), epsg * tau )
244+ else :
245+ x = x + eta * (proxg .prox (x - tau * proxf .grad (x ), epsg * tau ) - x )
241246 else :
242247 x , tau = _backtracking (y , tau , proxf , proxg , epsg ,
243248 beta = beta , niterback = niterback )
249+ if eta != 1. :
250+ x = x + eta * (proxg .prox (x - tau * proxf .grad (x ), epsg * tau ) - x )
244251
245252 # update internal parameters for bilinear operator
246253 if isinstance (proxf , BilinearOperator ):
@@ -297,8 +304,9 @@ def AcceleratedProximalGradient(proxf, proxg, x0, tau=None, beta=0.5,
297304 callback = callback , show = show )
298305
299306
300- def GeneralizedProximalGradient (proxfs , proxgs , x0 , tau = None ,
301- epsg = 1. , niter = 10 ,
307+ def GeneralizedProximalGradient (proxfs , proxgs , x0 , tau ,
308+ epsg = 1. , weights = None ,
309+ eta = 1. , niter = 10 ,
302310 acceleration = None ,
303311 callback = None , show = False ):
304312 r"""Generalized Proximal gradient
@@ -317,24 +325,27 @@ def GeneralizedProximalGradient(proxfs, proxgs, x0, tau=None,
317325
318326 Parameters
319327 ----------
320- proxfs : :obj:`List of pyproximal.ProxOperator`
328+ proxfs : :obj:`list of pyproximal.ProxOperator`
321329 Proximal operators of the :math:`f_i` functions (must have ``grad`` implemented)
322- proxgs : :obj:`List of pyproximal.ProxOperator`
330+ proxgs : :obj:`list of pyproximal.ProxOperator`
323331 Proximal operators of the :math:`g_j` functions
324332 x0 : :obj:`numpy.ndarray`
325333 Initial vector
326- tau : :obj:`float` or :obj:`numpy.ndarray`, optional
334+ tau : :obj:`float`
327335 Positive scalar weight, which should satisfy the following condition
328336 to guarantees convergence: :math:`\tau \in (0, 1/L]` where ``L`` is
329- the Lipschitz constant of :math:`\sum_{i=1}^n \nabla f_i`. When ``tau=None``,
330- backtracking is used to adaptively estimate the best tau at each
331- iteration.
337+ the Lipschitz constant of :math:`\sum_{i=1}^n \nabla f_i`.
332338 epsg : :obj:`float` or :obj:`np.ndarray`, optional
333339 Scaling factor(s) of ``g`` function(s)
340+ weights : :obj:`float`, optional
341+ Weighting factors of ``g`` functions. Must sum to 1.
342+ eta : :obj:`float`, optional
343+ Relaxation parameter (must be between 0 and 1, 0 excluded). Note that
344+ this will be only used when ``acceleration=None``.
334345 niter : :obj:`int`, optional
335346 Number of iterations of iterative scheme
336347 acceleration: :obj:`str`, optional
337- Acceleration (``vandenberghe`` or ``fista``)
348+ Acceleration (``None``, `` vandenberghe`` or ``fista``)
338349 callback : :obj:`callable`, optional
339350 Function with signature (``callback(x)``) to call after each iteration
340351 where ``x`` is the current model vector
@@ -353,16 +364,27 @@ def GeneralizedProximalGradient(proxfs, proxgs, x0, tau=None,
353364
354365 .. math::
355366 \text{for } j=1,\cdots,n, \\
356- ~~~~\mathbf z_j^{k+1} = \mathbf z_j^{k} + \epsilon_j
357- \left[prox_{\frac{\tau^k}{\omega_j } g_j}\left(2 \mathbf{x}^{k} - \mathbf{z}_j^{k}
367+ ~~~~\mathbf z_j^{k+1} = \mathbf z_j^{k} + \eta
368+ \left[prox_{\frac{\tau^k \epsilon_j}{w_j } g_j}\left(2 \mathbf{x}^{k} - \mathbf{z}_j^{k}
358369 - \tau^k \sum_{i=1}^n \nabla f_i(\mathbf{x}^{k})\right) - \mathbf{x}^{k} \right] \\
359- \mathbf{x}^{k+1} = \sum_{j=1}^n \omega_j f_j \\
360-
361- where :math:`\sum_{j=1}^n \omega_j=1`. In the current implementation :math:`\omega_j=1/n`.
370+ \mathbf{x}^{k+1} = \sum_{j=1}^n w_j \mathbf z_j^{k+1} \\
371+
372+ where :math:`\sum_{j=1}^n w_j=1`. In the current implementation, :math:`w_j=1/n` when
373+ not provided.
374+
362375 """
376+ # check if weights sum to 1
377+ if weights is None :
378+ weights = np .ones (len (proxgs )) / len (proxgs )
379+ if len (weights ) != len (proxgs ) or np .sum (weights ) != 1. :
380+ raise ValueError (f'omega={ weights } must be an array of size { len (proxgs )} '
381+ f'summing to 1' )
382+ print (weights )
383+
363384 # check if epgs is a vector
364385 if np .asarray (epsg ).size == 1. :
365386 epsg_print = str (epsg )
387+ epsg = epsg * np .ones (len (proxgs ))
366388 else :
367389 epsg_print = 'Multi'
368390
@@ -404,9 +426,9 @@ def GeneralizedProximalGradient(proxfs, proxgs, x0, tau=None,
404426 x = np .zeros_like (x )
405427 for i , proxg in enumerate (proxgs ):
406428 ztmp = 2 * y - zs [i ] - tau * grad
407- ztmp = proxg .prox (ztmp , epsg * tau )
408- zs [i ] += (ztmp - y )
409- x += zs [i ] / len ( proxgs )
429+ ztmp = proxg .prox (ztmp , tau * epsg [ i ] / weights [ i ] )
430+ zs [i ] += eta * (ztmp - y )
431+ x += weights [i ] * zs [ i ]
410432
411433 # update y
412434 if acceleration == 'vandenberghe' :
@@ -417,7 +439,6 @@ def GeneralizedProximalGradient(proxfs, proxgs, x0, tau=None,
417439 omega = ((told - 1. ) / t )
418440 else :
419441 omega = 0
420-
421442 y = x + omega * (x - xold )
422443
423444 # run callback
0 commit comments