13#include <Eigen/SparseCore>
40 return (T(0) < val) - (val < T(0));
54cumSum(
const T& x,
const bool leading_zero =
false)
56 const size_t start = leading_zero ? 1 : 0;
57 Eigen::ArrayXd out(x.size() + start);
63 std::partial_sum(x.begin(), x.end(), out.begin() + start);
81 return 1.0 / (1.0 + std::exp(-x));
97 assert(x > 0 && x < 1 &&
"Input must be in (0, 1)");
99 return std::log(x) - std::log1p(-x);
113clamp(
const T& x,
const T& lo,
const T& hi)
115 return x < lo ? lo : x > hi ? hi : x;
155 const std::vector<int>& active_set,
156 const Eigen::VectorXd& beta0,
157 const Eigen::VectorXd& beta,
158 const Eigen::VectorXd& x_centers,
159 const Eigen::VectorXd& x_scales,
161 const bool intercept)
165 int m = beta0.size();
167 Eigen::MatrixXd eta = Eigen::MatrixXd::Zero(n, m);
170 bool large_problem = active_set.size() > 100 && n * active_set.size() > 1e7;
171#pragma omp parallel num_threads(Threads::get()) if (large_problem)
174 Eigen::MatrixXd eta_local = Eigen::MatrixXd::Zero(n, m);
177#pragma omp for nowait
179 for (
int i = 0; i < static_cast<int>(active_set.size()); ++i) {
180 int ind = active_set[i];
181 auto [k, j] = std::div(ind, p);
183 switch (jit_normalization) {
185 eta_local.col(k) += x.col(j) * beta(ind) / x_scales(j);
186 eta_local.col(k).array() -= beta(ind) * x_centers(j) / x_scales(j);
190 eta_local.col(k) += x.col(j) * beta(ind);
191 eta_local.col(k).array() -= beta(ind) * x_centers(j);
195 eta_local.col(k) += x.col(j) * beta(ind) / x_scales(j);
199 eta_local.col(k) += x.col(j) * beta(ind);
213 eta.rowwise() += beta0.transpose();
237 const Eigen::MatrixXd& residual,
238 const std::vector<int>& active_set,
239 const Eigen::VectorXd& x_centers,
240 const Eigen::VectorXd& x_scales,
241 const Eigen::VectorXd& w,
244 const int n = x.rows();
245 const int p = x.cols();
246 const int m = residual.cols();
248 assert(gradient.size() == p * m &&
249 "Gradient matrix has incorrect dimensions");
251 Eigen::MatrixXd weighted_residual(n, m);
252 Eigen::ArrayXd wr_sums(m);
255 bool large_problem = active_set.size() > 100 && n * active_set.size() > 1e5;
256#pragma omp parallel for num_threads(Threads::get()) if (large_problem)
258 for (
int k = 0; k < m; ++k) {
259 weighted_residual.col(k) = residual.col(k).cwiseProduct(w);
260 wr_sums(k) = weighted_residual.col(k).sum();
264#pragma omp parallel for num_threads(Threads::get()) if (large_problem)
266 for (
int i = 0; i < static_cast<int>(active_set.size()); ++i) {
267 int ind = active_set[i];
268 auto [k, j] = std::div(ind, p);
270 switch (jit_normalization) {
273 (x.col(j).dot(weighted_residual.col(k)) - x_centers(j) * wr_sums(k)) /
278 (x.col(j).dot(weighted_residual.col(k)) - x_centers(j) * wr_sums(k)) /
283 x.col(j).dot(weighted_residual.col(k)) / (x_scales(j) * n);
286 gradient(ind) = x.col(j).dot(weighted_residual.col(k)) / n;
309 const Eigen::VectorXd& offset,
310 const std::vector<int>& active_set,
311 const Eigen::VectorXd& x_centers,
312 const Eigen::VectorXd& x_scales,
315 const int n = x.rows();
316 const int p = x.cols();
318 for (
size_t i = 0; i < active_set.size(); ++i) {
319 int ind = active_set[i];
320 auto [k, j] = std::div(ind, p);
322 switch (jit_normalization) {
325 offset(k) * (x.col(j).sum() / n - x_centers(j)) / x_scales(j);
328 gradient(ind) -= offset(k) * (x.col(j).sum() / n - x_centers(j));
331 gradient(ind) -= offset(k) * x.col(j).sum() / (n * x_scales(j));
334 gradient(ind) -= offset(k) * x.col(j).sum() / n;
349setUnion(
const std::vector<int>& a,
const std::vector<int>& b);
362setDiff(
const std::vector<int>& a,
const std::vector<int>& b);
379 return std::distance(x.begin(), std::max_element(x.begin(), x.end()));
397 return std::distance(x.begin(), std::min_element(x.begin(), x.end()));
413template<
typename T,
typename Comparator>
420 return std::distance(x.begin(), std::max_element(x.begin(), x.end(), comp));
438geomSpace(
const double start,
const double end,
const int n);
456 const int p = x.cols();
458 Eigen::VectorXd out(p);
460 for (
int j = 0; j < p; ++j) {
461 out(j) = x.col(j).cwiseAbs().sum();
481 const int p = x.cols();
483 Eigen::VectorXd out(p);
485 for (
int j = 0; j < p; ++j) {
486 out(j) = x.col(j).norm();
506 return x.colwise().norm();
522maxAbs(
const Eigen::SparseMatrixBase<T>& x)
524 const int p = x.cols();
526 Eigen::VectorXd out(p);
528 for (
int j = 0; j < p; ++j) {
529 double x_j_maxabs = 0.0;
531 for (
typename T::InnerIterator it(x.derived(), j); it; ++it) {
532 x_j_maxabs = std::max(x_j_maxabs, std::abs(it.value()));
557 return x.cwiseAbs().colwise().maxCoeff();
573means(
const Eigen::SparseMatrixBase<T>& x)
575 const int n = x.rows();
576 const int p = x.cols();
578 Eigen::VectorXd out(p);
580 for (
int j = 0; j < p; ++j) {
581 out(j) = x.col(j).sum() / n;
602 return x.colwise().mean();
621 const int n = x.rows();
622 const int p = x.cols();
624 Eigen::VectorXd x_means =
means(x);
625 Eigen::VectorXd out(p);
627 for (
int j = 0; j < p; ++j) {
628 double sum_sq_diff = 0.0;
629 const double mean = x_means(j);
632 for (
typename T::InnerIterator it(x.derived(), j); it; ++it) {
633 double diff = it.value() - mean;
634 sum_sq_diff += diff * diff;
640 sum_sq_diff += (n - nz_count) * mean * mean;
644 out(j) = std::sqrt(sum_sq_diff / n);
669 Eigen::VectorXd x_means =
means(x);
670 Eigen::VectorXd out(p);
672 for (
int j = 0; j < p; ++j) {
673 out(j) = (x.col(j).array() - x_means(j)).matrix().norm();
676 out.array() /= std::sqrt(n);
693ranges(
const Eigen::SparseMatrixBase<T>& x)
695 const int p = x.cols();
697 Eigen::VectorXd out(p);
699 for (
int j = 0; j < p; ++j) {
700 double x_j_max = 0.0;
701 double x_j_min = 0.0;
703 for (
typename T::InnerIterator it(x.derived(), j); it; ++it) {
704 x_j_max = std::max(x_j_max, it.value());
705 x_j_min = std::min(x_j_min, it.value());
708 out(j) = x_j_max - x_j_min;
731 return x.colwise().maxCoeff() - x.colwise().minCoeff();
746mins(
const Eigen::SparseMatrixBase<T>& x)
748 const int p = x.cols();
750 Eigen::VectorXd out(p);
752 for (
int j = 0; j < p; ++j) {
753 double x_j_min = 0.0;
755 for (
typename T::InnerIterator it(x.derived(), j); it; ++it) {
756 x_j_min = std::min(x_j_min, it.value());
780mins(
const Eigen::MatrixBase<T>& x)
782 return x.colwise().minCoeff();
806 Eigen::MatrixXd& residual,
809 const Eigen::MatrixXd& w,
810 const Eigen::VectorXd& x_centers,
811 const Eigen::VectorXd& x_scales,
814 using namespace Eigen;
816 const int n = x.rows();
817 const int p = x.cols();
818 const int n_clusters = clusters.
size();
820 Eigen::VectorXd gradient = Eigen::VectorXd::Zero(n_clusters);
822 for (
int j = 0; j < n_clusters; ++j) {
823 double c_old = clusters.
coeff(j);
832 s.reserve(cluster_size);
834 for (
auto c_it = clusters.
cbegin(j); c_it != clusters.
cend(j); ++c_it) {
836 double s_k =
sign(beta(ind));
843 if (cluster_size == 1) {
844 int k = *clusters.
cbegin(j);
846 x, k, w, residual, x_centers, x_scales, s[0], jit_normalization, n);
849 x, j, s, clusters, w, residual, x_centers, x_scales, jit_normalization);
Representation of the clusters in SLOPE.
double coeff(const int i) const
Returns the coefficient of the cluster with the given index.
std::size_t size()
Returns the number of clusters.
int cluster_size(const int i) const
Returns the size of the cluster with the given index.
std::vector< int >::const_iterator cend(const int i) const
Returns a constant iterator pointing to the end of the cluster with the given index.
std::vector< int >::const_iterator cbegin(const int i) const
Returns a constant iterator pointing to the beginning of the cluster with the given index.
The declaration of the Clusters class.
Eigen compatibility layer for version differences.
Enums to control predictor standardization behavior.
Namespace containing SLOPE regression implementation.
Eigen::VectorXd means(const Eigen::SparseMatrixBase< T > &x)
Computes the arithmetic mean for each column of a sparse matrix.
T clamp(const T &x, const T &lo, const T &hi)
Eigen::VectorXd l1Norms(const T &x)
Computes the L1 (Manhattan) norms for each column of a matrix.
int sign(T val)
Returns the sign of a given value.
int whichMin(const T &x)
Returns the index of the minimum element in a container.
std::pair< double, double > computeGradientAndHessian(const T &x, const int ind, const Eigen::MatrixXd &w, const Eigen::MatrixXd &residual, const Eigen::VectorXd &x_centers, const Eigen::VectorXd &x_scales, const double s, const JitNormalization jit_normalization, const int n)
JitNormalization
Enums to control predictor standardization behavior.
@ None
No JIT normalization.
Eigen::VectorXd logSumExp(const Eigen::MatrixXd &a)
std::vector< int > setDiff(const std::vector< int > &a, const std::vector< int > &b)
Computes the set difference of two sorted integer vectors.
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)
Eigen::VectorXd ranges(const Eigen::SparseMatrixBase< T > &x)
Computes the range (max - min) for each column of a matrix.
Eigen::MatrixXd softmax(const Eigen::MatrixXd &x)
std::vector< int > setUnion(const std::vector< int > &a, const std::vector< int > &b)
Computes the union of two sorted integer vectors.
Eigen::VectorXd mins(const Eigen::SparseMatrixBase< T > &x)
Computes the minimum value for each column of a sparse matrix.
Eigen::ArrayXd cumSum(const T &x, const bool leading_zero=false)
int whichBest(const T &x, const Comparator &comp)
Returns the index of the minimum element in a container.
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)
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)
Eigen::VectorXd stdDevs(const Eigen::SparseMatrixBase< T > &x)
Computes the standard deviation for each column of a matrix.
Eigen::VectorXd l2Norms(const Eigen::SparseMatrixBase< T > &x)
Computes the L2 (Euclidean) norms for each column of a sparse matrix.
Eigen::VectorXd clusterGradient(Eigen::VectorXd &beta, Eigen::MatrixXd &residual, Clusters &clusters, const T &x, const Eigen::MatrixXd &w, const Eigen::VectorXd &x_centers, const Eigen::VectorXd &x_scales, const JitNormalization jit_normalization)
Eigen::VectorXd maxAbs(const Eigen::SparseMatrixBase< T > &x)
Computes the maximum absolute value for each column of a matrix.
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.
std::pair< double, double > computeClusterGradientAndHessian(const Eigen::MatrixBase< T > &x, const int c_ind, const std::vector< int > &s, const Clusters &clusters, const Eigen::MatrixXd &w, const Eigen::MatrixXd &residual, const Eigen::VectorXd &x_centers, const Eigen::VectorXd &x_scales, const JitNormalization jit_normalization)
int whichMax(const T &x)
Returns the index of the maximum element in a container.
Eigen::Index nonZeros(const Eigen::SparseMatrixBase< Derived > &x)
Thread management for parallel computations.
Various utility functions.