@@ -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,9 +199,10 @@ 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. :
202-         epsg_print  =  str (epsg )
204+         epsg  =  epsg  *  np .ones (niter )
205+         epsg_print  =  str (epsg [0 ])
203206    else :
204207        epsg_print  =  'Multi' 
205208
@@ -218,7 +221,7 @@ def ProximalGradient(proxf, proxg, x0, tau=None, beta=0.5,
218221              'niterback = %d\t acceleration = %s\n '  %  (type (proxf ), type (proxg ),
219222                                    'Adaptive'  if  tau  is  None  else  str (tau ), beta ,
220223                                    epsg_print , niter , niterback , acceleration ))
221-         head  =  '   Itn       x[0]          f           g       J=f+eps*g' 
224+         head  =  '   Itn       x[0]          f           g       J=f+eps*g       tau ' 
222225        print (head )
223226
224227    backtracking  =  False 
@@ -237,10 +240,15 @@ def ProximalGradient(proxf, proxg, x0, tau=None, beta=0.5,
237240
238241        # proximal step 
239242        if  not  backtracking :
240-             x  =  proxg .prox (y  -  tau  *  proxf .grad (y ), epsg  *  tau )
243+             if  eta  ==  1. :
244+                 x  =  proxg .prox (y  -  tau  *  proxf .grad (y ), epsg [iiter ] *  tau )
245+             else :
246+                 x  =  x  +  eta  *  (proxg .prox (x  -  tau  *  proxf .grad (x ), epsg [iiter ] *  tau ) -  x )
241247        else :
242-             x , tau  =  _backtracking (y , tau , proxf , proxg , epsg ,
248+             x , tau  =  _backtracking (y , tau , proxf , proxg , epsg [ iiter ] ,
243249                                   beta = beta , niterback = niterback )
250+             if  eta  !=  1. :
251+                 x  =  x  +  eta  *  (proxg .prox (x  -  tau  *  proxf .grad (x ), epsg [iiter ] *  tau ) -  x )
244252
245253        # update internal parameters for bilinear operator 
246254        if  isinstance (proxf , BilinearOperator ):
@@ -264,10 +272,11 @@ def ProximalGradient(proxf, proxg, x0, tau=None, beta=0.5,
264272        if  show :
265273            if  iiter  <  10  or  niter  -  iiter  <  10  or  iiter  %  (niter  //  10 ) ==  0 :
266274                pf , pg  =  proxf (x ), proxg (x )
267-                 msg  =  '%6g  %12.5e  %10.3e  %10.3e  %10.3e'  %  \
275+                 msg  =  '%6g  %12.5e  %10.3e  %10.3e  %10.3e  %10.3e '  %  \
268276                      (iiter  +  1 , np .real (to_numpy (x [0 ])) if  x .ndim  ==  1  else  np .real (to_numpy (x [0 , 0 ])),
269-                        pf , pg [0 ] if  epsg_print  ==  'Multi'  else  pg ,
270-                        pf  +  np .sum (epsg  *  pg ))
277+                        pf , pg ,
278+                        pf  +  np .sum (epsg [iiter ] *  pg ),
279+                        tau )
271280                print (msg )
272281    if  show :
273282        print ('\n Total time (s) = %.2f'  %  (time .time () -  tstart ))
@@ -296,8 +305,9 @@ def AcceleratedProximalGradient(proxf, proxg, x0, tau=None, beta=0.5,
296305                            callback = callback , show = show )
297306
298307
299- def  GeneralizedProximalGradient (proxfs , proxgs , x0 , tau = None ,
300-                                 epsg = 1. , niter = 10 ,
308+ def  GeneralizedProximalGradient (proxfs , proxgs , x0 , tau ,
309+                                 epsg = 1. , weights = None ,
310+                                 eta = 1. , niter = 10 ,
301311                                acceleration = None ,
302312                                callback = None , show = False ):
303313    r"""Generalized Proximal gradient 
@@ -316,24 +326,27 @@ def GeneralizedProximalGradient(proxfs, proxgs, x0, tau=None,
316326
317327    Parameters 
318328    ---------- 
319-     proxfs : :obj:`List  of pyproximal.ProxOperator` 
329+     proxfs : :obj:`list  of pyproximal.ProxOperator` 
320330        Proximal operators of the :math:`f_i` functions (must have ``grad`` implemented) 
321-     proxgs : :obj:`List  of pyproximal.ProxOperator` 
331+     proxgs : :obj:`list  of pyproximal.ProxOperator` 
322332        Proximal operators of the :math:`g_j` functions 
323333    x0 : :obj:`numpy.ndarray` 
324334        Initial vector 
325-     tau : :obj:`float` or :obj:`numpy.ndarray`, optional  
335+     tau : :obj:`float` 
326336        Positive scalar weight, which should satisfy the following condition 
327337        to guarantees convergence: :math:`\tau  \in (0, 1/L]` where ``L`` is 
328-         the Lipschitz constant of :math:`\sum_{i=1}^n \nabla f_i`. When ``tau=None``, 
329-         backtracking is used to adaptively estimate the best tau at each 
330-         iteration. 
338+         the Lipschitz constant of :math:`\sum_{i=1}^n \nabla f_i`. 
331339    epsg : :obj:`float` or :obj:`np.ndarray`, optional 
332340        Scaling factor(s) of ``g`` function(s) 
341+     weights : :obj:`float`, optional 
342+         Weighting factors of ``g`` functions. Must sum to 1. 
343+     eta : :obj:`float`, optional 
344+         Relaxation parameter (must be between 0 and 1, 0 excluded). Note that 
345+         this will be only used when ``acceleration=None``. 
333346    niter : :obj:`int`, optional 
334347        Number of iterations of iterative scheme 
335348    acceleration:  :obj:`str`, optional 
336-         Acceleration (``vandenberghe`` or ``fista``) 
349+         Acceleration (``None``, `` vandenberghe`` or ``fista``) 
337350    callback : :obj:`callable`, optional 
338351        Function with signature (``callback(x)``) to call after each iteration 
339352        where ``x`` is the current model vector 
@@ -352,16 +365,27 @@ def GeneralizedProximalGradient(proxfs, proxgs, x0, tau=None,
352365
353366    .. math:: 
354367        \text{for } j=1,\cdots,n, \\ 
355-         ~~~~\mathbf z_j^{k+1} = \mathbf z_j^{k} + \epsilon_j  
356-         \left[prox_{\frac{\tau^k}{\omega_j } g_j}\left(2 \mathbf{x}^{k} - \mathbf{z}_j^{k} 
368+         ~~~~\mathbf z_j^{k+1} = \mathbf z_j^{k} + \eta  
369+         \left[prox_{\frac{\tau^k \epsilon_j}{w_j } g_j}\left(2 \mathbf{x}^{k} - \mathbf{z}_j^{k} 
357370        - \tau^k \sum_{i=1}^n \nabla f_i(\mathbf{x}^{k})\right) - \mathbf{x}^{k} \right] \\ 
358-         \mathbf{x}^{k+1} = \sum_{j=1}^n \omega_j f_j \\ 
359-          
360-     where :math:`\sum_{j=1}^n \omega_j=1`. In the current implementation :math:`\omega_j=1/n`. 
371+         \mathbf{x}^{k+1} = \sum_{j=1}^n w_j \mathbf z_j^{k+1} \\ 
372+ 
373+     where :math:`\sum_{j=1}^n w_j=1`. In the current implementation, :math:`w_j=1/n` when 
374+     not provided. 
375+ 
361376    """ 
377+     # check if weights sum to 1 
378+     if  weights  is  None :
379+         weights  =  np .ones (len (proxgs )) /  len (proxgs )
380+     if  len (weights ) !=  len (proxgs ) or  np .sum (weights ) !=  1. :
381+         raise  ValueError (f'omega={ weights } { len (proxgs )}  
382+                          f'summing to 1' )
383+     print (weights )
384+ 
362385    # check if epgs is a vector 
363386    if  np .asarray (epsg ).size  ==  1. :
364387        epsg_print  =  str (epsg )
388+         epsg  =  epsg  *  np .ones (len (proxgs ))
365389    else :
366390        epsg_print  =  'Multi' 
367391
@@ -403,9 +427,9 @@ def GeneralizedProximalGradient(proxfs, proxgs, x0, tau=None,
403427        x  =  np .zeros_like (x )
404428        for  i , proxg  in  enumerate (proxgs ):
405429            ztmp  =  2  *  y  -  zs [i ] -  tau  *  grad 
406-             ztmp  =  proxg .prox (ztmp , tau  *  len ( proxgs ) )
407-             zs [i ] +=  epsg  *  (ztmp  -  y )
408-             x  +=  zs [i ] /   len ( proxgs ) 
430+             ztmp  =  proxg .prox (ztmp , tau  *  epsg [ i ]  /   weights [ i ] )
431+             zs [i ] +=  eta  *  (ztmp  -  y )
432+             x  +=  weights [i ] *   zs [ i ] 
409433
410434        # update y 
411435        if  acceleration  ==  'vandenberghe' :
@@ -416,7 +440,6 @@ def GeneralizedProximalGradient(proxfs, proxgs, x0, tau=None,
416440            omega  =  ((told  -  1. ) /  t )
417441        else :
418442            omega  =  0 
419-         
420443        y  =  x  +  omega  *  (x  -  xold )
421444
422445        # run callback 
@@ -558,7 +581,8 @@ def HQS(proxf, proxg, x0, tau, niter=10, z0=None, gfirst=True,
558581            if  iiter  <  10  or  niter  -  iiter  <  10  or  iiter  %  (niter  //  10 ) ==  0 :
559582                pf , pg  =  proxf (x ), proxg (x )
560583                msg  =  '%6g  %12.5e  %10.3e  %10.3e  %10.3e'  %  \
561-                       (iiter  +  1 , x [0 ], pf , pg , pf  +  pg )
584+                       (iiter  +  1 , np .real (to_numpy (x [0 ])), 
585+                        pf , pg , pf  +  pg )
562586                print (msg )
563587    if  show :
564588        print ('\n Total time (s) = %.2f'  %  (time .time () -  tstart ))
@@ -683,7 +707,8 @@ def ADMM(proxf, proxg, x0, tau, niter=10, gfirst=False,
683707            if  iiter  <  10  or  niter  -  iiter  <  10  or  iiter  %  (niter  //  10 ) ==  0 :
684708                pf , pg  =  proxf (x ), proxg (x )
685709                msg  =  '%6g  %12.5e  %10.3e  %10.3e  %10.3e'  %  \
686-                       (iiter  +  1 , x [0 ], pf , pg , pf  +  pg )
710+                       (iiter  +  1 , np .real (to_numpy (x [0 ])),
711+                        pf , pg , pf  +  pg )
687712                print (msg )
688713    if  show :
689714        print ('\n Total time (s) = %.2f'  %  (time .time () -  tstart ))
@@ -784,7 +809,8 @@ def ADMML2(proxg, Op, b, A, x0, tau, niter=10, callback=None, show=False, **kwar
784809            if  iiter  <  10  or  niter  -  iiter  <  10  or  iiter  %  (niter  //  10 ) ==  0 :
785810                pf , pg  =  0.5  *  np .linalg .norm (Op  @ x  -  b ) **  2 , proxg (Ax )
786811                msg  =  '%6g  %12.5e  %10.3e  %10.3e  %10.3e'  %  \
787-                       (iiter  +  1 , x [0 ], pf , pg , pf  +  pg )
812+                       (iiter  +  1 , np .real (to_numpy (x [0 ])),
813+                        pf , pg , pf  +  pg )
788814                print (msg )
789815    if  show :
790816        print ('\n Total time (s) = %.2f'  %  (time .time () -  tstart ))
@@ -889,7 +915,8 @@ def LinearizedADMM(proxf, proxg, A, x0, tau, mu, niter=10,
889915            if  iiter  <  10  or  niter  -  iiter  <  10  or  iiter  %  (niter  //  10 ) ==  0 :
890916                pf , pg  =  proxf (x ), proxg (Ax )
891917                msg  =  '%6g  %12.5e  %10.3e  %10.3e  %10.3e'  %  \
892-                       (iiter  +  1 , x [0 ], pf , pg , pf  +  pg )
918+                       (iiter  +  1 , np .real (to_numpy (x [0 ])),
919+                        pf , pg , pf  +  pg )
893920                print (msg )
894921    if  show :
895922        print ('\n Total time (s) = %.2f'  %  (time .time () -  tstart ))
@@ -1037,7 +1064,8 @@ def TwIST(proxg, A, b, x0, alpha=None, beta=None, eigs=None, niter=10,
10371064            if  iiter  <  10  or  niter  -  iiter  <  10  or  iiter  %  (niter  //  10 ) ==  0 :
10381065                pf , pg  =  proxf (x ), proxg (x )
10391066                msg  =  '%6g  %12.5e  %10.3e  %10.3e  %10.3e'  %  \
1040-                       (iiter  +  1 , np .real (to_numpy (x [0 ])), pf , pg , pf  +  pg )
1067+                       (iiter  +  1 , np .real (to_numpy (x [0 ])),
1068+                        pf , pg , pf  +  pg )
10411069                print (msg )
10421070    if  show :
10431071        print ('\n Total time (s) = %.2f'  %  (time .time () -  tstart ))
0 commit comments