slope 0.31.0
Loading...
Searching...
No Matches
math.h
Go to the documentation of this file.
1
6#pragma once
7
8#include "clusters.h"
9#include "jit_normalization.h"
10#include <Eigen/Core>
11#include <Eigen/SparseCore>
12#include <numeric>
13#include <vector>
14
15#ifdef _OPENMP
16#include "threads.h"
17#endif
18
19namespace slope {
20
33template<typename T>
34int
35sign(T val)
36{
37 return (T(0) < val) - (val < T(0));
38}
39
48template<typename T>
49Eigen::ArrayXd
50cumSum(const T& x)
51{
52 std::vector<double> cum_sum(x.size());
53 std::partial_sum(x.begin(), x.end(), cum_sum.begin(), std::plus<double>());
54
55 Eigen::Map<Eigen::ArrayXd> out(cum_sum.data(), cum_sum.size());
56
57 return out;
58}
59
69template<typename T>
70T
71sigmoid(const T& x)
72{
73 return 1.0 / (1.0 + std::exp(-x));
74}
75
85template<typename T>
86T
87logit(const T& x)
88{
89 assert(x > 0 && x < 1 && "Input must be in (0, 1)");
90
91 return std::log(x) - std::log1p(-x);
92}
93
103template<typename T>
104T
105clamp(const T& x, const T& lo, const T& hi)
106{
107 return x < lo ? lo : x > hi ? hi : x;
108}
109
116Eigen::VectorXd
117logSumExp(const Eigen::MatrixXd& a);
118
127Eigen::MatrixXd
128softmax(const Eigen::MatrixXd& x);
129
144template<typename T>
145Eigen::MatrixXd
147 const std::vector<int>& active_set,
148 const Eigen::VectorXd& beta0,
149 const Eigen::VectorXd& beta,
150 const Eigen::VectorXd& x_centers,
151 const Eigen::VectorXd& x_scales,
152 const JitNormalization jit_normalization,
153 const bool intercept)
154{
155 int n = x.rows();
156 int p = x.cols();
157 int m = beta0.size();
158
159 Eigen::MatrixXd eta = Eigen::MatrixXd::Zero(n, m);
160
161#ifdef _OPENMP
162 bool large_problem = active_set.size() > 100 && n * active_set.size() > 1e7;
163#pragma omp parallel num_threads(Threads::get()) if (large_problem)
164#endif
165 {
166 Eigen::MatrixXd eta_local = Eigen::MatrixXd::Zero(n, m);
167
168#ifdef _OPENMP
169#pragma omp for nowait
170#endif
171 for (int i = 0; i < static_cast<int>(active_set.size()); ++i) {
172 int ind = active_set[i];
173 auto [k, j] = std::div(ind, p);
174
175 switch (jit_normalization) {
177 eta_local.col(k) += x.col(j) * beta(ind) / x_scales(j);
178 eta_local.col(k).array() -= beta(ind) * x_centers(j) / x_scales(j);
179 break;
180
182 eta_local.col(k) += x.col(j) * beta(ind);
183 eta_local.col(k).array() -= beta(ind) * x_centers(j);
184 break;
185
187 eta_local.col(k) += x.col(j) * beta(ind) / x_scales(j);
188 break;
189
191 eta_local.col(k) += x.col(j) * beta(ind);
192 break;
193 }
194 }
195
196#ifdef _OPENMP
197#pragma omp critical
198#endif
199 {
200 eta += eta_local;
201 }
202 }
203
204 if (intercept) {
205 eta.rowwise() += beta0.transpose();
206 }
207
208 return eta;
209}
210
225template<typename T>
226void
227updateGradient(Eigen::VectorXd& gradient,
228 const T& x,
229 const Eigen::MatrixXd& residual,
230 const std::vector<int>& active_set,
231 const Eigen::VectorXd& x_centers,
232 const Eigen::VectorXd& x_scales,
233 const Eigen::VectorXd& w,
234 const JitNormalization jit_normalization)
235{
236 const int n = x.rows();
237 const int p = x.cols();
238 const int m = residual.cols();
239
240 assert(gradient.size() == p * m &&
241 "Gradient matrix has incorrect dimensions");
242
243 Eigen::MatrixXd weighted_residual(n, m);
244 Eigen::ArrayXd wr_sums(m);
245
246#ifdef _OPENMP
247 bool large_problem = active_set.size() > 100 && n * active_set.size() > 1e5;
248#pragma omp parallel for num_threads(Threads::get()) if (large_problem)
249#endif
250 for (int k = 0; k < m; ++k) {
251 weighted_residual.col(k) = residual.col(k).cwiseProduct(w);
252 wr_sums(k) = weighted_residual.col(k).sum();
253 }
254
255#ifdef _OPENMP
256#pragma omp parallel for num_threads(Threads::get()) if (large_problem)
257#endif
258 for (int i = 0; i < static_cast<int>(active_set.size()); ++i) {
259 int ind = active_set[i];
260 auto [k, j] = std::div(ind, p);
261
262 switch (jit_normalization) {
264 gradient(ind) =
265 (x.col(j).dot(weighted_residual.col(k)) - x_centers(j) * wr_sums(k)) /
266 (x_scales(j) * n);
267 break;
269 gradient(ind) =
270 (x.col(j).dot(weighted_residual.col(k)) - x_centers(j) * wr_sums(k)) /
271 n;
272 break;
274 gradient(ind) =
275 x.col(j).dot(weighted_residual.col(k)) / (x_scales(j) * n);
276 break;
278 gradient(ind) = x.col(j).dot(weighted_residual.col(k)) / n;
279 break;
280 }
281 }
282}
283
297template<typename T>
298void
299offsetGradient(Eigen::VectorXd& gradient,
300 const T& x,
301 const Eigen::VectorXd& offset,
302 const std::vector<int>& active_set,
303 const Eigen::VectorXd& x_centers,
304 const Eigen::VectorXd& x_scales,
305 const JitNormalization jit_normalization)
306{
307 const int n = x.rows();
308 const int p = x.cols();
309
310 for (size_t i = 0; i < active_set.size(); ++i) {
311 int ind = active_set[i];
312 auto [k, j] = std::div(ind, p);
313
314 switch (jit_normalization) {
316 gradient(ind) -=
317 offset(k) * (x.col(j).sum() / n - x_centers(j)) / x_scales(j);
318 break;
320 gradient(ind) -= offset(k) * (x.col(j).sum() / n - x_centers(j));
321 break;
323 gradient(ind) -= offset(k) * x.col(j).sum() / (n * x_scales(j));
324 break;
326 gradient(ind) -= offset(k) * x.col(j).sum() / n;
327 break;
328 }
329 }
330}
331
340std::vector<int>
341setUnion(const std::vector<int>& a, const std::vector<int>& b);
342
353std::vector<int>
354setDiff(const std::vector<int>& a, const std::vector<int>& b);
355
367template<typename T>
368int
369whichMax(const T& x)
370{
371 return std::distance(x.begin(), std::max_element(x.begin(), x.end()));
372}
373
385template<typename T>
386int
387whichMin(const T& x)
388{
389 return std::distance(x.begin(), std::min_element(x.begin(), x.end()));
390}
391
405template<typename T, typename Comparator>
406int
407whichBest(const T& x, const Comparator& comp)
408{
409 return std::distance(x.begin(), std::max_element(x.begin(), x.end(), comp));
410}
411
426Eigen::ArrayXd
427geomSpace(const double start, const double end, const int n);
428
441template<typename T>
442Eigen::VectorXd
443l1Norms(const T& x)
444{
445 const int p = x.cols();
446
447 Eigen::VectorXd out(p);
448
449 for (int j = 0; j < p; ++j) {
450 out(j) = x.col(j).cwiseAbs().sum();
451 }
452
453 return out;
454}
455
466Eigen::VectorXd
467l2Norms(const Eigen::SparseMatrix<double>& x);
468
479Eigen::VectorXd
480l2Norms(const Eigen::MatrixXd& x);
481
493Eigen::VectorXd
494maxAbs(const Eigen::SparseMatrix<double>& x);
495
508Eigen::VectorXd
509maxAbs(const Eigen::MatrixXd& x);
510
522Eigen::VectorXd
523means(const Eigen::SparseMatrix<double>& x);
524
536Eigen::VectorXd
537means(const Eigen::MatrixXd& x);
538
551Eigen::VectorXd
552stdDevs(const Eigen::SparseMatrix<double>& x);
553
566Eigen::VectorXd
567stdDevs(const Eigen::MatrixXd& x);
568
579Eigen::VectorXd
580ranges(const Eigen::SparseMatrix<double>& x);
581
595Eigen::VectorXd
596ranges(const Eigen::MatrixXd& x);
597
608Eigen::VectorXd
609mins(const Eigen::SparseMatrix<double>& x);
610
624Eigen::VectorXd
625mins(const Eigen::MatrixXd& x);
626
627template<typename T>
628Eigen::VectorXd
629clusterGradient(Eigen::VectorXd& beta,
630 Eigen::VectorXd& residual,
631 Clusters& clusters,
632 const T& x,
633 const Eigen::VectorXd& w,
634 const Eigen::VectorXd& x_centers,
635 const Eigen::VectorXd& x_scales,
636 const JitNormalization jit_normalization)
637{
638 using namespace Eigen;
639
640 const int n = x.rows();
641 const int n_clusters = clusters.n_clusters();
642
643 Eigen::VectorXd gradient = Eigen::VectorXd::Zero(n_clusters);
644
645 for (int j = 0; j < n_clusters; ++j) {
646 double c_old = clusters.coeff(j);
647
648 if (c_old == 0) {
649 gradient(j) = 0;
650 continue;
651 }
652
653 int cluster_size = clusters.cluster_size(j);
654 std::vector<int> s;
655 s.reserve(cluster_size);
656
657 for (auto c_it = clusters.cbegin(j); c_it != clusters.cend(j); ++c_it) {
658 double s_k = sign(beta(*c_it));
659 s.emplace_back(s_k);
660 }
661
662 double hessian_j = 1;
663 double gradient_j = 0;
664
665 if (cluster_size == 1) {
666 int k = *clusters.cbegin(j);
667 std::tie(gradient_j, hessian_j) = computeGradientAndHessian(
668 x, k, w, residual, x_centers, x_scales, s[0], jit_normalization, n);
669 } else {
670 std::tie(hessian_j, gradient_j) = computeClusterGradientAndHessian(
671 x, j, s, clusters, w, residual, x_centers, x_scales, jit_normalization);
672 }
673
674 gradient(j) = gradient_j;
675 }
676
677 return gradient;
678}
679
680} // namespace slope
The declaration of the Clusters class.
Enums to control predictor standardization behavior.
Namespace containing SLOPE regression implementation.
Definition clusters.cpp:5
T clamp(const T &x, const T &lo, const T &hi)
Definition math.h:105
Eigen::VectorXd l1Norms(const T &x)
Computes the L1 (Manhattan) norms for each column of a matrix.
Definition math.h:443
int sign(T val)
Returns the sign of a given value.
Definition math.h:35
Eigen::VectorXd maxAbs(const Eigen::SparseMatrix< double > &x)
Computes the maximum absolute value for each column of a matrix.
Definition math.cpp:126
Eigen::VectorXd means(const Eigen::SparseMatrix< double > &x)
Computes the arithmetic mean for each column of a sparse matrix.
Definition math.cpp:76
int whichMin(const T &x)
Returns the index of the minimum element in a container.
Definition math.h:387
std::pair< double, double > computeClusterGradientAndHessian(const Eigen::MatrixXd &x, const int j, const std::vector< int > &s, const Clusters &clusters, const Eigen::VectorXd &w, const Eigen::VectorXd &residual, const Eigen::VectorXd &x_centers, const Eigen::VectorXd &x_scales, const JitNormalization jit_normalization)
Definition hybrid_cd.cpp:6
Eigen::ArrayXd cumSum(const T &x)
Definition math.h:50
T sigmoid(const T &x)
Definition math.h:71
JitNormalization
Enums to control predictor standardization behavior.
@ None
No JIT normalization.
Eigen::VectorXd logSumExp(const Eigen::MatrixXd &a)
Definition math.cpp:7
Eigen::MatrixXd softmax(const Eigen::MatrixXd &a)
Definition math.cpp:17
std::vector< int > setDiff(const std::vector< int > &a, const std::vector< int > &b)
Computes the set difference of two sorted integer vectors.
Definition math.cpp:36
Eigen::VectorXd stdDevs(const Eigen::SparseMatrix< double > &x)
Computes the standard deviation for each column of a matrix.
Definition math.cpp:180
Eigen::MatrixXd linearPredictor(const T &x, const std::vector< int > &active_set, const Eigen::VectorXd &beta0, const Eigen::VectorXd &beta, const Eigen::VectorXd &x_centers, const Eigen::VectorXd &x_scales, const JitNormalization jit_normalization, const bool intercept)
Definition math.h:146
std::vector< int > setUnion(const std::vector< int > &a, const std::vector< int > &b)
Computes the union of two sorted integer vectors.
Definition math.cpp:26
int whichBest(const T &x, const Comparator &comp)
Returns the index of the minimum element in a container.
Definition math.h:407
std::pair< double, double > computeGradientAndHessian(const T &x, const int k, const Eigen::VectorXd &w, const Eigen::VectorXd &residual, const Eigen::VectorXd &x_centers, const Eigen::VectorXd &x_scales, const double s, const JitNormalization jit_normalization, const int n)
Definition hybrid_cd.h:42
Eigen::VectorXd ranges(const Eigen::SparseMatrix< double > &x)
Computes the range (max - min) for each column of a matrix.
Definition math.cpp:97
void updateGradient(Eigen::VectorXd &gradient, const T &x, const Eigen::MatrixXd &residual, const std::vector< int > &active_set, const Eigen::VectorXd &x_centers, const Eigen::VectorXd &x_scales, const Eigen::VectorXd &w, const JitNormalization jit_normalization)
Definition math.h:227
void offsetGradient(Eigen::VectorXd &gradient, const T &x, const Eigen::VectorXd &offset, const std::vector< int > &active_set, const Eigen::VectorXd &x_centers, const Eigen::VectorXd &x_scales, const JitNormalization jit_normalization)
Definition math.h:299
T logit(const T &x)
Definition math.h:87
Eigen::VectorXd l2Norms(const Eigen::SparseMatrix< double > &x)
Computes the L2 (Euclidean) norms for each column of a sparse matrix.
Definition math.cpp:56
Eigen::VectorXd mins(const Eigen::SparseMatrix< double > &x)
Computes the minimum value for each column of a sparse matrix.
Definition math.cpp:153
Eigen::ArrayXd geomSpace(const double start, const double end, const int n)
Creates an array of n numbers in geometric progression from start to end.
Definition math.cpp:46
int whichMax(const T &x)
Returns the index of the maximum element in a container.
Definition math.h:369
Thread management for parallel computations.