SOPT
Sparse OPTimisation
proximal.h
Go to the documentation of this file.
1 #ifndef SOPT_PROXIMAL_H
2 #define SOPT_PROXIMAL_H
3 
4 #include "sopt/config.h"
5 #include <type_traits>
6 #include <Eigen/Core>
7 #include "sopt/maths.h"
9 #ifdef SOPT_MPI
10 #include "sopt/mpi/communicator.h"
11 #include "sopt/mpi/utilities.h"
12 #endif
13 
15 namespace sopt::proximal {
16 
19  public:
20 #ifdef SOPT_MPI
21  EuclidianNorm(mpi::Communicator const &comm = mpi::Communicator()) : comm_(comm){};
22  mpi::Communicator communicator() const { return comm_; }
23  EuclidianNorm &communicator(mpi::Communicator const &comm) {
24  comm_ = comm;
25  return *this;
26  }
27 #endif
28  template <typename T0>
30  typename real_type<typename T0::Scalar>::type const &t,
31  Eigen::MatrixBase<T0> const &x) const {
32  using Scalar = typename T0::Scalar;
33 #ifdef SOPT_MPI
34  auto const norm = mpi::l2_norm(x, comm_);
35 #else
36  auto const norm = x.norm();
37 #endif
38  if (norm > t)
39  out = (Scalar(1) - t / norm) * x;
40  else
41  out.fill(0);
42  }
44  template <typename T0>
46  Eigen::MatrixBase<T0> const &x) const {
47  return {*this, t, x};
48  }
49 #ifdef SOPT_MPI
50  private:
51  mpi::Communicator comm_;
52 #endif
53 };
54 
56 template <typename T0>
58  Eigen::MatrixBase<T0> const &x) -> decltype(EuclidianNorm(), t, x) {
59  return EuclidianNorm()(t, x);
60 }
61 
63 template <typename T0, typename T1>
64 void l1_norm(Eigen::DenseBase<T0> &out, typename real_type<typename T0::Scalar>::type gamma,
65  Eigen::DenseBase<T1> const &x) {
66  out = sopt::soft_threshhold<T0>(x, gamma);
67 }
69 template <typename T0, typename T1, typename T2>
70 void l1_norm(Eigen::DenseBase<T0> &out, Eigen::DenseBase<T2> const &gamma,
71  Eigen::DenseBase<T1> const &x) {
72  out = sopt::soft_threshhold<T0, T2>(x, gamma);
73 }
74 
77 template <typename S>
78 void l1_norm(Vector<S> &out, typename real_type<S>::type gamma, Vector<S> const &x) {
79  l1_norm<Vector<S>, Vector<S>>(out, gamma, x);
80 }
81 
83 template <typename T0, typename T1>
84 void l2_norm(Eigen::DenseBase<T0> &out, typename real_type<typename T0::Scalar>::type gamma,
85  Eigen::DenseBase<T1> const &x) {
86  out = x.derived() * 1. / (1. + gamma);
87 }
88 
89 template <typename T0, typename T1, typename T2>
90 void l2_norm(Eigen::DenseBase<T0> &out, Eigen::DenseBase<T2> const &gamma,
91  Eigen::DenseBase<T1> const &x) {
92  out = x.derived().array() * 1. / (1. + gamma.derived().array()).array();
93 }
94 
96 template <typename T0, typename T1>
97 void tv_norm(Eigen::DenseBase<T0> &out, typename real_type<typename T0::Scalar>::type gamma,
98  Eigen::DenseBase<T1> const &x) {
99  typename Eigen::Index const size = x.size() / 2;
100  typename T1::PlainObject const &u = x.segment(0, size);
101  typename T1::PlainObject const &v = x.segment(size, size);
102  out = T0::Zero(size * 2);
103  for (typename Eigen::Index i(0); i < size; i++) {
104  const t_real norm = std::sqrt(std::abs(u(i) * u(i) + v(i) * v(i)));
105  if (norm > gamma) {
106  out(i) = (1 - gamma / norm) * u(i);
107  out(size + i) = (1 - gamma / norm) * v(i);
108  } else {
109  out(i) = 0;
110  out(size + i) = 0;
111  }
112  }
113 }
114 template <typename T0, typename T1, typename T2>
115 void tv_norm(Eigen::DenseBase<T0> &out, Eigen::DenseBase<T2> const &gamma,
116  Eigen::DenseBase<T1> const &x) {
117  typename Eigen::Index const size = x.size() / 2;
118  typename T1::PlainObject const &u = x.segment(0, size);
119  typename T1::PlainObject const &v = x.segment(size, size);
120  out = T0::Zero(size * 2);
121  for (typename Eigen::Index i(0); i < size; i++) {
122  const t_real norm = std::sqrt(std::abs(u(i) * u(i) + v(i) * v(i)));
123  if (norm > gamma(i)) {
124  out(i) = (1 - gamma(i) / norm) * u(i);
125  out(size + i) = (1 - gamma(i) / norm) * v(i);
126  } else {
127  out(i) = 0;
128  out(size + i) = 0;
129  }
130  }
131 }
132 
134 template <typename T0, typename T1>
135 void id(Eigen::DenseBase<T0> &out, typename real_type<typename T0::Scalar>::type gamma,
136  Eigen::DenseBase<T1> const &x) {
137  out = x;
138 }
139 
143 template <typename T>
144 auto l1_norm(typename real_type<typename T::Scalar>::type gamma, Eigen::DenseBase<T> const &x)
145  -> decltype(sopt::soft_threshhold(x, gamma)) {
146  return sopt::soft_threshhold(x, gamma);
147 }
148 
150 template <typename T>
151 void positive_quadrant(Vector<T> &out, typename real_type<T>::type, Vector<T> const &x) {
152  out = sopt::positive_quadrant(x);
153 };
154 
156 template <typename T>
157 class L2Norm {
158  public:
159  using Real = typename real_type<T>::type;
161  L2Norm() {}
162 
164  void operator()(Vector<T> &out, const Real gamma, Vector<T> const &x) const {
165  proximal::l2_norm(out, gamma, x);
166  }
168  template <typename T0>
169  EnveloppeExpression<L2Norm, T0> operator()(Real const &, Eigen::MatrixBase<T0> const &x) const {
170  return {*this, x};
171  }
172 
174  template <typename T0>
175  EnveloppeExpression<L2Norm, T0> operator()(Eigen::MatrixBase<T0> const &x) const {
176  return {*this, x};
177  }
178 };
179 
181 template <typename T>
182 class L2Ball {
183  public:
184  using Real = typename real_type<T>::type;
186 #ifdef SOPT_MPI
187  L2Ball(Real epsilon, mpi::Communicator const &comm = mpi::Communicator())
188  : epsilon_(epsilon), comm_(comm){};
189 #else
190  L2Ball(Real epsilon) : epsilon_(epsilon) {}
191 #endif
192 
194  void operator()(Vector<T> &out, typename real_type<T>::type, Vector<T> const &x) const {
195  return operator()(out, x);
196  }
198  void operator()(Vector<T> &out, Vector<T> const &x) const {
199 #ifdef SOPT_MPI
200  auto const norm = mpi::l2_norm(x, comm_);
201 #else
202  auto const norm = x.stableNorm();
203 #endif
204  if (norm > epsilon())
205  out = x * (epsilon() / norm);
206  else
207  out = x;
208  }
210  template <typename T0>
211  EnveloppeExpression<L2Ball, T0> operator()(Real const &, Eigen::MatrixBase<T0> const &x) const {
212  return {*this, x};
213  }
214 
216  template <typename T0>
217  EnveloppeExpression<L2Ball, T0> operator()(Eigen::MatrixBase<T0> const &x) const {
218  return {*this, x};
219  }
220 
222  Real epsilon() const { return epsilon_; }
225  epsilon_ = eps;
226  return *this;
227  }
228 
229 #ifdef SOPT_MPI
230  mpi::Communicator const &communicator() const { return comm_; }
231  L2Ball &communicator(mpi::Communicator const &comm) {
232  comm_ = comm;
233  return *this;
234  }
235 #endif
236 
237  private:
239  Real epsilon_;
240 #ifdef SOPT_MPI
241  mpi::Communicator comm_;
242 #endif
243 };
244 
245 template <typename T>
246 class WeightedL2Ball : public L2Ball<T> {
247  public:
248  using Real = typename L2Ball<T>::Real;
250 #ifdef SOPT_MPI
252  template <typename T0>
253  WeightedL2Ball(Real epsilon, Eigen::DenseBase<T0> const &w,
254  mpi::Communicator const &comm = mpi::Communicator())
255  : L2Ball<T>(epsilon, comm), weights_(w) {}
257  WeightedL2Ball(Real epsilon, mpi::Communicator const &comm = mpi::Communicator())
258  : WeightedL2Ball(epsilon, t_Vector::Ones(1), comm) {}
259  mpi::Communicator communicator() const { return L2Ball<T>::communicator(); }
260  WeightedL2Ball<T> &communicator(mpi::Communicator const &c) {
261  L2Ball<T>::communicator(c);
262  return *this;
263  }
264 #else
266  template <typename T0>
267  WeightedL2Ball(Real epsilon, Eigen::DenseBase<T0> const &w) : L2Ball<T>(epsilon), weights_(w) {}
270 #endif
271 
273  void operator()(Vector<T> &out, typename real_type<T>::type, Vector<T> const &x) const {
274  return operator()(out, x);
275  }
277  void operator()(Vector<T> &out, Vector<T> const &x) const {
278 #ifdef SOPT_MPI
279  auto const norm = mpi::l2_norm(x.array(), weights().array(), communicator());
280 #else
281  auto const norm = weights().size() == 1 ? x.stableNorm() * std::abs(weights()(0))
282  : (x.array() * weights().array()).matrix().stableNorm();
283 #endif
284  if (norm > epsilon())
285  out = x * (epsilon() / norm);
286  else
287  out = x;
288  }
290  template <typename T0>
292  Eigen::MatrixBase<T0> const &x) const {
293  return {*this, x};
294  }
296  template <typename T0>
297  EnveloppeExpression<WeightedL2Ball, T0> operator()(Eigen::MatrixBase<T0> const &x) const {
298  return {*this, x};
299  }
300 
302  t_Vector const &weights() const { return weights_; }
304  template <typename T0>
305  WeightedL2Ball<T> &weights(Eigen::MatrixBase<T0> const &w) {
306  if ((w.array() < 0e0).any()) SOPT_THROW("Weights cannot be negative");
307  if (w.stableNorm() < 1e-12) SOPT_THROW("Weights cannot be null");
308  weights_ = w;
309  return *this;
310  }
312  Real epsilon() const { return L2Ball<T>::epsilon(); }
315  L2Ball<T>::epsilon(eps);
316  return *this;
317  }
318 
319  private:
320  t_Vector weights_;
321 };
322 
324 template <typename FUNCTION, typename VECTOR>
325 class Translation {
326  public:
328  template <typename T_VECTOR>
329  Translation(FUNCTION const &func, T_VECTOR const &trans) : func(func), trans(trans) {}
331  template <typename OUTPUT, typename T0>
332  typename std::enable_if<std::is_reference<OUTPUT>::value, void>::type operator()(
333  OUTPUT out, typename real_type<typename T0::Scalar>::type const &t,
334  Eigen::MatrixBase<T0> const &x) const {
335  func(out, t, x + trans);
336  out -= trans;
337  }
339  template <typename T0>
341  typename real_type<typename T0::Scalar>::type const &t,
342  Eigen::MatrixBase<T0> const &x) const {
343  func(out, t, x + trans);
344  out -= trans;
345  }
347  template <typename T0>
349  typename T0::Scalar const &t, Eigen::MatrixBase<T0> const &x) const {
350  return {*this, t, x};
351  }
352 
353  private:
355  FUNCTION const func;
357  VECTOR const trans;
358 };
359 
361 template <typename FUNCTION, typename VECTOR>
362 Translation<FUNCTION, VECTOR> translate(FUNCTION const &func, VECTOR const &translation) {
363  return Translation<FUNCTION, VECTOR>(func, translation);
364 }
365 } // namespace sopt::proximal
366 
367 #endif
sopt::Vector< Scalar > t_Vector
sopt::t_real Scalar
Computes inner-most element type.
Definition: real_type.h:42
Proximal of euclidian norm.
Definition: proximal.h:18
void operator()(Vector< typename T0::Scalar > &out, typename real_type< typename T0::Scalar >::type const &t, Eigen::MatrixBase< T0 > const &x) const
Definition: proximal.h:29
ProximalExpression< EuclidianNorm, T0 > operator()(typename T0::Scalar const &t, Eigen::MatrixBase< T0 > const &x) const
Lazy version.
Definition: proximal.h:45
Proximal for indicator function of L2 ball.
Definition: proximal.h:182
Real epsilon() const
Size of the ball.
Definition: proximal.h:222
void operator()(Vector< T > &out, typename real_type< T >::type, Vector< T > const &x) const
Calls proximal function.
Definition: proximal.h:194
L2Ball(Real epsilon)
Constructs an L2 ball proximal of size epsilon.
Definition: proximal.h:190
EnveloppeExpression< L2Ball, T0 > operator()(Real const &, Eigen::MatrixBase< T0 > const &x) const
Lazy version.
Definition: proximal.h:211
L2Ball< T > & epsilon(Real eps)
Size of the ball.
Definition: proximal.h:224
typename real_type< T >::type Real
Definition: proximal.h:184
EnveloppeExpression< L2Ball, T0 > operator()(Eigen::MatrixBase< T0 > const &x) const
Lazy version.
Definition: proximal.h:217
void operator()(Vector< T > &out, Vector< T > const &x) const
Calls proximal function.
Definition: proximal.h:198
Proximal for the L2 norm.
Definition: proximal.h:157
EnveloppeExpression< L2Norm, T0 > operator()(Real const &, Eigen::MatrixBase< T0 > const &x) const
Lazy version.
Definition: proximal.h:169
void operator()(Vector< T > &out, const Real gamma, Vector< T > const &x) const
Calls proximal function.
Definition: proximal.h:164
typename real_type< T >::type Real
Definition: proximal.h:159
EnveloppeExpression< L2Norm, T0 > operator()(Eigen::MatrixBase< T0 > const &x) const
Lazy version.
Definition: proximal.h:175
L2Norm()
Constructs an L2 ball proximal of size gamma.
Definition: proximal.h:161
Translation over proximal function.
Definition: proximal.h:325
std::enable_if< std::is_reference< OUTPUT >::value, void >::type operator()(OUTPUT out, typename real_type< typename T0::Scalar >::type const &t, Eigen::MatrixBase< T0 > const &x) const
Computes proximal of translated function.
Definition: proximal.h:332
Translation(FUNCTION const &func, T_VECTOR const &trans)
Creates proximal of translated function.
Definition: proximal.h:329
ProximalExpression< Translation< FUNCTION, VECTOR > const &, T0 > operator()(typename T0::Scalar const &t, Eigen::MatrixBase< T0 > const &x) const
Lazy version.
Definition: proximal.h:348
void operator()(Vector< typename T0::Scalar > &out, typename real_type< typename T0::Scalar >::type const &t, Eigen::MatrixBase< T0 > const &x) const
Computes proximal of translated function.
Definition: proximal.h:340
WeightedL2Ball< T > & weights(Eigen::MatrixBase< T0 > const &w)
Weights associated with each dimension.
Definition: proximal.h:305
void operator()(Vector< T > &out, typename real_type< T >::type, Vector< T > const &x) const
Calls proximal function.
Definition: proximal.h:273
t_Vector const & weights() const
Weights associated with each dimension.
Definition: proximal.h:302
EnveloppeExpression< WeightedL2Ball, T0 > operator()(Eigen::MatrixBase< T0 > const &x) const
Lazy version.
Definition: proximal.h:297
WeightedL2Ball(Real epsilon, Eigen::DenseBase< T0 > const &w)
Constructs an L2 ball proximal of size epsilon with given weights.
Definition: proximal.h:267
WeightedL2Ball(Real epsilon)
Constructs an L2 ball proximal of size epsilon.
Definition: proximal.h:269
void operator()(Vector< T > &out, Vector< T > const &x) const
Calls proximal function.
Definition: proximal.h:277
WeightedL2Ball< T > & epsilon(Real const &eps)
Size of the ball.
Definition: proximal.h:314
EnveloppeExpression< WeightedL2Ball, T0 > operator()(Real const &, Eigen::MatrixBase< T0 > const &x) const
Lazy version.
Definition: proximal.h:291
Real epsilon() const
Size of the ball.
Definition: proximal.h:312
typename L2Ball< T >::Real Real
Definition: proximal.h:248
Expression referencing a lazy function call to envelope proximal.
Expression referencing a lazy proximal function call.
#define SOPT_THROW(MSG)
Definition: exception.h:46
Holds some standard proximals.
Definition: l1_proximal.h:17
void l2_norm(Eigen::DenseBase< T0 > &out, typename real_type< typename T0::Scalar >::type gamma, Eigen::DenseBase< T1 > const &x)
Proximal of the l2 norm (note this is different from the l2 ball indicator function)
Definition: proximal.h:84
Translation< FUNCTION, VECTOR > translate(FUNCTION const &func, VECTOR const &translation)
Translates given proximal by given vector.
Definition: proximal.h:362
void id(Eigen::DenseBase< T0 > &out, typename real_type< typename T0::Scalar >::type gamma, Eigen::DenseBase< T1 > const &x)
Proximal of a function that is always zero, the identity.
Definition: proximal.h:135
void positive_quadrant(Vector< T > &out, typename real_type< T >::type, Vector< T > const &x)
Proximal for projection on the positive quadrant.
Definition: proximal.h:151
void tv_norm(Eigen::DenseBase< T0 > &out, typename real_type< typename T0::Scalar >::type gamma, Eigen::DenseBase< T1 > const &x)
Proximal of the l1,2 norm that is used in the TV norm.
Definition: proximal.h:97
auto euclidian_norm(typename real_type< typename T0::Scalar >::type const &t, Eigen::MatrixBase< T0 > const &x) -> decltype(EuclidianNorm(), t, x)
Proximal of the euclidian norm.
Definition: proximal.h:57
void l1_norm(Eigen::DenseBase< T0 > &out, typename real_type< typename T0::Scalar >::type gamma, Eigen::DenseBase< T1 > const &x)
Proximal of the l1 norm.
Definition: proximal.h:64
void l2_norm(Eigen::DenseBase< T0 > &out, Eigen::DenseBase< T2 > const &gamma, Eigen::DenseBase< T1 > const &x)
Definition: proximal.h:90
Eigen::CwiseUnaryOp< const details::ProjectPositiveQuadrant< typename T::Scalar >, const T > positive_quadrant(Eigen::DenseBase< T > const &input)
Expression to create projection onto positive quadrant.
Definition: maths.h:60
std::enable_if< std::is_arithmetic< SCALAR >::value or is_complex< SCALAR >::value, SCALAR >::type soft_threshhold(SCALAR const &x, typename real_type< SCALAR >::type const &threshhold)
abs(x) < threshhold ? 0: x - sgn(x) * threshhold
Definition: maths.h:29
double t_real
Root of the type hierarchy for real numbers.
Definition: types.h:17
Eigen::Matrix< T, Eigen::Dynamic, 1 > Vector
A vector of a given type.
Definition: types.h:24