slope 0.29.0
Loading...
Searching...
No Matches
sorted_l1_norm.cpp
1#include "sorted_l1_norm.h"
2#include "math.h"
3#include "utils.h"
4
5namespace slope {
6
7double
8SortedL1Norm::eval(const Eigen::VectorXd& beta,
9 const Eigen::ArrayXd& lambda) const
10{
11 assert(lambda.size() == beta.size() &&
12 "Coefficient and lambda sizes must agree");
13
14 Eigen::ArrayXd beta_abs = beta.array().abs();
15 sort(beta_abs, true);
16 return (beta_abs * lambda).sum();
17}
18
19Eigen::MatrixXd
20SortedL1Norm::prox(const Eigen::VectorXd& beta,
21 const Eigen::ArrayXd& lambda) const
22{
23 // TODO: Avoid copying beta
24 using namespace Eigen;
25
26 assert(lambda.size() == beta.size() &&
27 "Coefficient and lambda sizes must agree");
28
29 ArrayXd beta_sign = beta.array().sign();
30 VectorXd beta_copy = beta.array().abs();
31
32 auto ord = sortIndex(beta_copy, true);
33 permute(beta_copy, ord);
34
35 int p = beta_copy.size();
36
37 VectorXd s(p);
38 VectorXd w(p);
39 VectorXi idx_i(p);
40 VectorXi idx_j(p);
41
42 int k = 0;
43
44 for (int i = 0; i < p; i++) {
45 idx_i(k) = i;
46 idx_j(k) = i;
47 s(k) = beta_copy(i) - lambda(i);
48 w(k) = s(k);
49
50 while ((k > 0) && (w(k - 1) <= w(k))) {
51 k--;
52 idx_j(k) = i;
53 s(k) += s(k + 1);
54 w(k) = s(k) / (i - idx_i(k) + 1.0);
55 }
56 k++;
57 }
58
59 for (int j = 0; j < k; j++) {
60 double d = std::max(w(j), 0.0);
61 for (int i = idx_i(j); i <= idx_j(j); i++) {
62 beta_copy(i) = d;
63 }
64 }
65
66 // return order and sigsn
67 inversePermute(beta_copy, ord);
68 beta_copy.array() *= beta_sign;
69
70 return beta_copy;
71}
72
73double
74SortedL1Norm::dualNorm(const Eigen::VectorXd& gradient,
75 const Eigen::ArrayXd& lambda) const
76{
77 Eigen::ArrayXd abs_gradient = gradient.cwiseAbs();
78 sort(abs_gradient, true);
79
80 assert(lambda.size() == gradient.size() &&
81 "Gradient and lambda sizes must agree");
82
83 if (lambda(0) == 0) {
84 // TODO: this is a crude approach for the unregularized case.
85 // We should consider something more clever and avoid
86 // the division.
87 return (cumSum(abs_gradient) / 1e-6).maxCoeff();
88 }
89
90 return (cumSum(abs_gradient) / (cumSum(lambda))).maxCoeff();
91}
92
93} // namspace slope
double eval(const Eigen::VectorXd &beta, const Eigen::ArrayXd &lambda) const
Evaluates the Sorted L1 Norm.
double dualNorm(const Eigen::VectorXd &a, const Eigen::ArrayXd &lambda) const
Computes the dual norm of a vector.
Eigen::MatrixXd prox(const Eigen::VectorXd &beta, const Eigen::ArrayXd &lambda) const
Computes the proximal operator of the Sorted L1 Norm.
Mathematical support functions for the slope package.
Namespace containing SLOPE regression implementation.
Definition clusters.cpp:5
Eigen::ArrayXd cumSum(const T &x)
Definition math.h:46
std::vector< int > sortIndex(T &v, const bool descending=false)
Definition utils.h:89
void permute(T &values, const std::vector< int > &ind)
Definition utils.h:118
void sort(T &v, const bool descending=false)
Definition utils.h:37
void inversePermute(T &values, const std::vector< int > &ind)
Definition utils.h:152
The declaration of the SortedL1Norm class.
Various utility functions.