@@ -96,6 +96,76 @@ def prox(self, x, tau):
9696 r = np .vstack ((np .zeros_like (c ), (b [idx ] + c ) / (2 * self .gamma )))
9797 val = tau * self .elementwise (r ) + (r - np .abs (x [idx ])) ** 2 / 2
9898 idx_minima = np .argmin (val , axis = 0 )
99- out [idx ] = r [idx_minima , range (r .shape [1 ])]
99+ out [idx ] = r [idx_minima , list ( range (r .shape [1 ]) )]
100100 out *= np .sign (x )
101101 return out
102+
103+
104+ class Log1 (ProxOperator ):
105+ r"""Logarithmic penalty 2.
106+
107+ The logarithmic penalty (Log) is defined as
108+
109+ .. math::
110+
111+ \mathrm{Log}_{\sigma,\delta}(\mathbf{x}) = \sigma \sum_i \log(|x_i| + \delta)
112+
113+ where :math:`{\sigma>0}`, :math:`{\gamma>0}`.
114+
115+ Parameters
116+ ----------
117+ sigma : :obj:`float`
118+ Multiplicative coefficient of Log norm.
119+ delta : :obj:`float`, optional
120+ Regularization parameter. Default is 1e-10.
121+
122+ Notes
123+ -----
124+ The logarithmic penalty gives rise to a log-thresholding that is
125+ a smooth alternative falling in between the hard and soft thresholding.
126+
127+ The proximal operator is defined as [1]_:
128+
129+ .. math::
130+
131+ \prox_{\tau \sigma log}(\mathbf{x}) =
132+ \begin{cases}
133+ 0.5 (x_i + \delta - \sqrt{(x_i-\delta)^2-2\tau \sigma}), & x_i < -x_0 \\
134+ 0, & -x_0 \leq x_i \leq x_0 \\
135+ 0.5 (x_i - \delta + \sqrt{(x_i+\delta)^2-2\tau \sigma}), & x_i > x_0\\
136+ \end{cases}
137+
138+ where :math:`x_0=\sqrt{2 \tau \sigma} - \delta`.
139+
140+ .. [1] Malioutov, D., and Aravkin, A. "Iterative log thresholding",
141+ Arxiv, 2013.
142+
143+ """
144+
145+ def __init__ (self , sigma , delta = 1e-10 ):
146+ super ().__init__ (None , False )
147+ if delta < 0 :
148+ raise ValueError ('Variable "delta" must be positive.' )
149+ self .sigma = sigma
150+ self .delta = delta
151+
152+ def __call__ (self , x ):
153+ return np .sum (self .elementwise (x ))
154+
155+ def elementwise (self , x ):
156+ return np .log (np .abs (x ) + self .delta )
157+
158+ @_check_tau
159+ def prox (self , x , tau ):
160+ tau1 = self .sigma * tau
161+ thresh = np .sqrt (2 * tau1 ) - self .delta
162+ x1 = np .zeros_like (x , dtype = x .dtype )
163+ if np .iscomplexobj (x ):
164+ x1 [np .abs (x ) > thresh ] = 0.5 * np .exp (1j * np .angle (x [np .abs (x ) > thresh ])) * \
165+ (np .abs (x [np .abs (x ) > thresh ]) - self .delta +
166+ np .sqrt (np .abs (x [np .abs (x ) > thresh ] + self .delta ) ** 2 - 2 * tau1 ))
167+ else :
168+ x1 [x > thresh ] = 0.5 * (x [x > thresh ] - self .delta + np .sqrt (np .abs (x [x > thresh ] + self .delta ) ** 2 - 2 * tau1 ))
169+ x1 [x < - thresh ] = 0.5 * (x [x < - thresh ] + self .delta - np .sqrt (np .abs (x [x < - thresh ] - self .delta ) ** 2 - 2 * tau1 ))
170+ return x1
171+
0 commit comments