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