| 98 /// \prox_f(x) = \prox\_{f\_0}(x - y) + y, |
98 /// \prox_f(x) = \prox\_{f\_0}(x - y) + y, |
| 99 /// $$ |
99 /// $$ |
| 100 /// which is also used internally. |
100 /// which is also used internally. |
| 101 /// The third output indicates whether the output is “locked” to either $0$ (resp. $-y$ in |
101 /// The third output indicates whether the output is “locked” to either $0$ (resp. $-y$ in |
| 102 /// the reformulation), or $y$ ($0$ in the reformulation). |
102 /// the reformulation), or $y$ ($0$ in the reformulation). |
| 103 /// The fourth output indicates the next highest $λ$ where such locking would happen. |
103 /// The fourth output indicates $λ$ where such locking to y would happen. It may be negative, |
| |
104 /// in which case the prox is always locked to y. |
| 104 #[replace_float_literals(F::cast_from(literal))] |
105 #[replace_float_literals(F::cast_from(literal))] |
| 105 #[inline] |
106 #[inline] |
| 106 fn shifted_nonneg_soft_thresholding<F: Float>(x: F, y: F, λ: F) -> (F, F, bool, Option<F>) { |
107 fn shifted_nonneg_soft_thresholding<F: Float>(x: F, y: F, λ: F) -> (F, F, bool, F) { |
| |
108 // The OC is |
| |
109 // x ∈ w + λsign(w-y) + N_{≥ 0}(w) |
| |
110 // x-y ∈ w' + λsign(w') + N_{≥ -y}(w') |
| |
111 // if w' > -y, then soft-thresholding. So if soft-thresholding stays above -y. |
| |
112 // If w' = -y, and w'≠0, then x ≤ λsign(-y) |
| |
113 // If w' = -y and w'=0, then x ≤ λ. |
| |
114 // w_i=max{sign(x-y)*max(|x-y| - λ, 0), -y} + y = max{sign(x-y)*max(|x-y| - λ, 0)+y, 0} |
| |
115 let (w, locked, lock) = if x >= y { |
| |
116 // w_i=max{max(x-y - λ, 0)+y, 0}=max{max(x - λ, y), 0} = max{x-λ, max(y, 0)} |
| |
117 let l = 0.0.max(y); |
| |
118 // x - l = x + min(0.0, y) = min(x, x + y) |
| |
119 if x - λ >= l { |
| |
120 (x - λ, false, x - l) |
| |
121 } else { |
| |
122 (l, true, F::NEG_INFINITY) // λ is increasing, so NEG_INFINITY is ok. So is x-l < λ |
| |
123 } |
| |
124 } else { |
| |
125 // w_i=max{-max(-(x-y) - λ, 0)+y, 0}=max{min((x-y) + λ, 0)+y, 0}=max{min(x + λ, y), 0} |
| |
126 if x + λ <= y { |
| |
127 // = max(x+λ, 0) |
| |
128 if x >= -λ { |
| |
129 (x + λ, false, y - x) |
| |
130 } else { |
| |
131 (0.0, true, 0.0.min(y) - x) |
| |
132 } |
| |
133 } else { |
| |
134 (0.0.max(y), true, F::NEG_INFINITY) |
| |
135 } |
| |
136 }; |
| |
137 return (w, w - y, locked, lock); |
| |
138 |
| |
139 /* |
| 107 let z = x - y; // The shift to f_0 |
140 let z = x - y; // The shift to f_0 |
| 108 if -y >= 0.0 { |
141 if -y >= 0.0 { |
| 109 if x > λ { |
142 if x > λ { |
| 110 (x - λ, z - λ, false, Some(x)) |
143 (x - λ, z - λ, false, Some(x)) |
| 111 } else { |
144 } else { |
| 178 let mut w_locked = 0.0; |
211 let mut w_locked = 0.0; |
| 179 let mut n_unlocked = 0; // m |
212 let mut n_unlocked = 0; // m |
| 180 let mut x_prime = 0.0; |
213 let mut x_prime = 0.0; |
| 181 let mut max_shift = F::INFINITY; |
214 let mut max_shift = F::INFINITY; |
| 182 for (&x_i, &y_i) in izip!(x.iter(), y.iter()) { |
215 for (&x_i, &y_i) in izip!(x.iter(), y.iter()) { |
| 183 let (_, a_shifted, locked, next_lock) = shifted_nonneg_soft_thresholding(x_i, y_i, λ); |
216 let (_, w_i, locked, lock) = shifted_nonneg_soft_thresholding(x_i, y_i, λ); |
| 184 |
217 |
| 185 if let Some(t) = next_lock { |
218 // If not already locked (lock <= y), consider this coordinate in next level for λ. |
| 186 max_shift = min(max_shift, t); |
219 if lock > λ { |
| 187 assert!(max_shift > λ); |
220 max_shift = min(max_shift, lock); |
| 188 } |
221 } |
| |
222 |
| 189 if locked { |
223 if locked { |
| 190 w_locked += abs(a_shifted); |
224 w_locked += abs(w_i); |
| 191 } else { |
225 } else { |
| 192 n_unlocked += 1; |
226 n_unlocked += 1; |
| 193 x_prime += abs(x_i - y_i); |
227 x_prime += abs(x_i - y_i); |
| 194 } |
228 } |
| 195 } |
229 } |