@@ -406,7 +406,115 @@ def GeneralizedProximalGradient(proxfs, proxgs, x0, tau=None, beta=0.5,
406406 return x
407407
408408
409- def ADMM (proxf , proxg , x0 , tau , niter = 10 , callback = None , show = False ):
409+ def HQS (proxf , proxg , x0 , tau , niter = 10 , gfirst = True ,
410+ callback = None , callbackz = False , show = False ):
411+ r"""Half Quadratic splitting
412+
413+ Solves the following minimization problem using Half Quadratic splitting
414+ algorithm:
415+
416+ .. math::
417+
418+ \mathbf{x},\mathbf{z} = \argmin_{\mathbf{x},\mathbf{z}}
419+ f(\mathbf{x}) + g(\mathbf{z}) \\
420+ s.t. \; \mathbf{x}=\mathbf{z}
421+
422+ where :math:`f(\mathbf{x})` and :math:`g(\mathbf{z})` are any convex
423+ function that has a known proximal operator.
424+
425+ Parameters
426+ ----------
427+ proxf : :obj:`pyproximal.ProxOperator`
428+ Proximal operator of f function
429+ proxg : :obj:`pyproximal.ProxOperator`
430+ Proximal operator of g function
431+ x0 : :obj:`numpy.ndarray`
432+ Initial vector
433+ tau : :obj:`float`, optional
434+ Positive scalar weight, which should satisfy the following condition
435+ to guarantees convergence: :math:`\tau \in (0, 1/L]` where ``L`` is
436+ the Lipschitz constant of :math:`\nabla f`.
437+ niter : :obj:`int`, optional
438+ Number of iterations of iterative scheme
439+ gfirst : :obj:`bool`, optional
440+ Apply Proximal of operator ``g`` first (``True``) or Proximal of
441+ operator ``f`` first (``False``)
442+ callback : :obj:`callable`, optional
443+ Function with signature (``callback(x)``) to call after each iteration
444+ where ``x`` is the current model vector
445+ callbackz : :obj:`bool`, optional
446+ Modify callback signature to (``callback(x, z)``) when ``callbackz=True``
447+ show : :obj:`bool`, optional
448+ Display iterations log
449+
450+ Returns
451+ -------
452+ x : :obj:`numpy.ndarray`
453+ Inverted model
454+ z : :obj:`numpy.ndarray`
455+ Inverted second model
456+
457+ Notes
458+ -----
459+ The HQS algorithm can be expressed by the following recursion [1]_:
460+
461+ .. math::
462+
463+ \mathbf{z}^{k+1} = \prox_{\tau g}(\mathbf{x}^{k})
464+ \mathbf{x}^{k+1} = \prox_{\tau f}(\mathbf{z}^{k+1})\\
465+
466+ Note that ``x`` and ``z`` converge to each other, however if iterations are
467+ stopped too early ``x`` is guaranteed to belong to the domain of ``f``
468+ while ``z`` is guaranteed to belong to the domain of ``g``. Depending on
469+ the problem either of the two may be the best solution.
470+
471+ .. [1] D., Geman, and C., Yang, "Nonlinear image recovery with halfquadratic
472+ regularization", IEEE Transactions on Image Processing,
473+ 4, 7, pp. 932-946, 1995.
474+
475+ """
476+ if show :
477+ tstart = time .time ()
478+ print ('HQS\n '
479+ '---------------------------------------------------------\n '
480+ 'Proximal operator (f): %s\n '
481+ 'Proximal operator (g): %s\n '
482+ 'tau = %10e\t niter = %d\n ' % (type (proxf ), type (proxg ),
483+ tau , niter ))
484+ head = ' Itn x[0] f g J = f + g'
485+ print (head )
486+
487+ x = x0 .copy ()
488+ z = np .zeros_like (x )
489+ for iiter in range (niter ):
490+ if gfirst :
491+ z = proxg .prox (x , tau )
492+ x = proxf .prox (z , tau )
493+ else :
494+ x = proxf .prox (z , tau )
495+ z = proxg .prox (x , tau )
496+
497+ # run callback
498+ if callback is not None :
499+ if callbackz :
500+ callback (x , z )
501+ else :
502+ callback (x )
503+
504+ if show :
505+ if iiter < 10 or niter - iiter < 10 or iiter % (niter // 10 ) == 0 :
506+ pf , pg = proxf (x ), proxg (x )
507+ msg = '%6g %12.5e %10.3e %10.3e %10.3e' % \
508+ (iiter + 1 , x [0 ], pf , pg , pf + pg )
509+ print (msg )
510+ if show :
511+ print ('\n Total time (s) = %.2f' % (time .time () - tstart ))
512+ print ('---------------------------------------------------------\n ' )
513+ return x , z
514+
515+
516+ def ADMM (proxf , proxg , x0 , tau , niter = 10 , gfirst = False ,
517+ callback = None , callbackz = False , show = False ):
410518 r"""Alternating Direction Method of Multipliers
411519
412520 Solves the following minimization problem using Alternating Direction
@@ -451,9 +559,14 @@ def ADMM(proxf, proxg, x0, tau, niter=10, callback=None, show=False):
451559 the Lipschitz constant of :math:`\nabla f`.
452560 niter : :obj:`int`, optional
453561 Number of iterations of iterative scheme
562+ gfirst : :obj:`bool`, optional
563+ Apply Proximal of operator ``g`` first (``True``) or Proximal of
564+ operator ``f`` first (``False``)
454565 callback : :obj:`callable`, optional
455566 Function with signature (``callback(x)``) to call after each iteration
456567 where ``x`` is the current model vector
568+ callbackz : :obj:`bool`, optional
569+ Modify callback signature to (``callback(x, z)``) when ``callbackz=True``
457570 show : :obj:`bool`, optional
458571 Display iterations log
459572
@@ -479,7 +592,7 @@ def ADMM(proxf, proxg, x0, tau, niter=10, callback=None, show=False):
479592 \mathbf{z}^{k+1} = \prox_{\tau g}(\mathbf{x}^{k+1} + \mathbf{u}^{k})\\
480593 \mathbf{u}^{k+1} = \mathbf{u}^{k} + \mathbf{x}^{k+1} - \mathbf{z}^{k+1}
481594
482- Note that ``x`` and ``z`` converge to each other, but if iterations are
595+ Note that ``x`` and ``z`` converge to each other, however if iterations are
483596 stopped too early ``x`` is guaranteed to belong to the domain of ``f``
484597 while ``z`` is guaranteed to belong to the domain of ``g``. Depending on
485598 the problem either of the two may be the best solution.
@@ -499,14 +612,20 @@ def ADMM(proxf, proxg, x0, tau, niter=10, callback=None, show=False):
499612 x = x0 .copy ()
500613 u = z = np .zeros_like (x )
501614 for iiter in range (niter ):
502- x = proxf .prox (z - u , tau )
503- z = proxg .prox (x + u , tau )
615+ if gfirst :
616+ z = proxg .prox (x + u , tau )
617+ x = proxf .prox (z - u , tau )
618+ else :
619+ x = proxf .prox (z - u , tau )
620+ z = proxg .prox (x + u , tau )
504621 u = u + x - z
505622
506623 # run callback
507624 if callback is not None :
508- callback (x )
509-
625+ if callbackz :
626+ callback (x , z )
627+ else :
628+ callback (x )
510629 if show :
511630 if iiter < 10 or niter - iiter < 10 or iiter % (niter // 10 ) == 0 :
512631 pf , pg = proxf (x ), proxg (x )
0 commit comments