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;
154linearPredictor(
const T& 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();
235template<
typename T,
typename IndexAt>
237updateGradientImpl(Eigen::VectorXd& gradient,
239 const Eigen::MatrixXd& residual,
240 const int active_size,
241 const IndexAt& index_at,
242 const Eigen::VectorXd& x_centers,
243 const Eigen::VectorXd& x_scales,
244 const Eigen::VectorXd& w,
247 const int n = x.rows();
248 const int p = x.cols();
249 const int m = residual.cols();
251 assert(gradient.size() == p * m &&
252 "Gradient matrix has incorrect dimensions");
254 Eigen::MatrixXd weighted_residual(n, m);
255 Eigen::ArrayXd wr_sums(m);
259 active_size > 100 &&
static_cast<long long>(n) * active_size > 1e5;
260#pragma omp parallel for num_threads(Threads::get()) if (large_problem)
262 for (
int k = 0; k < m; ++k) {
263 weighted_residual.col(k) = residual.col(k).cwiseProduct(w);
264 wr_sums(k) = weighted_residual.col(k).sum();
268#pragma omp parallel for num_threads(Threads::get()) if (large_problem)
270 for (
int i = 0; i < active_size; ++i) {
271 int ind = index_at(i);
272 auto [k, j] = std::div(ind, p);
274 switch (jit_normalization) {
277 (x.col(j).dot(weighted_residual.col(k)) - x_centers(j) * wr_sums(k)) /
282 (x.col(j).dot(weighted_residual.col(k)) - x_centers(j) * wr_sums(k)) /
287 x.col(j).dot(weighted_residual.col(k)) / (x_scales(j) * n);
290 gradient(ind) = x.col(j).dot(weighted_residual.col(k)) / n;
313 const Eigen::MatrixXd& residual,
314 const std::vector<int>& active_set,
315 const Eigen::VectorXd& x_centers,
316 const Eigen::VectorXd& x_scales,
317 const Eigen::VectorXd& w,
320 detail::updateGradientImpl(
324 static_cast<int>(active_set.size()),
325 [&active_set](
int i) { return active_set[i]; },
341 const Eigen::MatrixXd& residual,
342 const Eigen::VectorXd& x_centers,
343 const Eigen::VectorXd& x_scales,
344 const Eigen::VectorXd& w,
347 detail::updateGradientImpl(
351 static_cast<int>(gradient.size()),
352 [](
int i) { return i; },
374template<
typename T,
typename IndexAt>
376offsetGradientImpl(Eigen::VectorXd& gradient,
378 const Eigen::VectorXd& offset,
379 const int active_size,
380 const IndexAt& index_at,
381 const Eigen::VectorXd& x_centers,
382 const Eigen::VectorXd& x_scales,
385 const int n = x.rows();
386 const int p = x.cols();
388 for (
int i = 0; i < active_size; ++i) {
389 int ind = index_at(i);
390 auto [k, j] = std::div(ind, p);
392 switch (jit_normalization) {
395 offset(k) * (x.col(j).sum() / n - x_centers(j)) / x_scales(j);
398 gradient(ind) -= offset(k) * (x.col(j).sum() / n - x_centers(j));
401 gradient(ind) -= offset(k) * x.col(j).sum() / (n * x_scales(j));
404 gradient(ind) -= offset(k) * x.col(j).sum() / n;
426 const Eigen::VectorXd& offset,
427 const std::vector<int>& active_set,
428 const Eigen::VectorXd& x_centers,
429 const Eigen::VectorXd& x_scales,
432 detail::offsetGradientImpl(
436 static_cast<int>(active_set.size()),
437 [&active_set](
int i) { return active_set[i]; },
452 const Eigen::VectorXd& offset,
453 const Eigen::VectorXd& x_centers,
454 const Eigen::VectorXd& x_scales,
457 detail::offsetGradientImpl(
461 static_cast<int>(gradient.size()),
462 [](
int i) { return i; },
477setUnion(
const std::vector<int>& a,
const std::vector<int>& b);
490setDiff(
const std::vector<int>& a,
const std::vector<int>& b);
507 return std::distance(x.begin(), std::max_element(x.begin(), x.end()));
525 return std::distance(x.begin(), std::min_element(x.begin(), x.end()));
541template<
typename T,
typename Comparator>
548 return std::distance(x.begin(), std::max_element(x.begin(), x.end(), comp));
566geomSpace(
const double start,
const double end,
const int n);
584 const int p = x.cols();
586 Eigen::VectorXd out(p);
588 for (
int j = 0; j < p; ++j) {
589 out(j) = x.col(j).cwiseAbs().sum();
609 const int p = x.cols();
611 Eigen::VectorXd out(p);
613 for (
int j = 0; j < p; ++j) {
614 out(j) = x.col(j).norm();
634 return x.colwise().norm();
650maxAbs(
const Eigen::SparseMatrixBase<T>& x)
652 const int p = x.cols();
654 Eigen::VectorXd out(p);
656 for (
int j = 0; j < p; ++j) {
657 double x_j_maxabs = 0.0;
659 for (
typename T::InnerIterator it(x.derived(), j); it; ++it) {
660 x_j_maxabs = std::max(x_j_maxabs, std::abs(it.value()));
685 return x.cwiseAbs().colwise().maxCoeff();
701means(
const Eigen::SparseMatrixBase<T>& x)
703 const int n = x.rows();
704 const int p = x.cols();
706 Eigen::VectorXd out(p);
708 for (
int j = 0; j < p; ++j) {
709 out(j) = x.col(j).sum() / n;
730 return x.colwise().mean();
749 const int n = x.rows();
750 const int p = x.cols();
752 Eigen::VectorXd x_means =
means(x);
753 Eigen::VectorXd out(p);
755 for (
int j = 0; j < p; ++j) {
756 double sum_sq_diff = 0.0;
757 const double mean = x_means(j);
760 for (
typename T::InnerIterator it(x.derived(), j); it; ++it) {
761 double diff = it.value() - mean;
762 sum_sq_diff += diff * diff;
768 sum_sq_diff += (n - nz_count) * mean * mean;
772 out(j) = std::sqrt(sum_sq_diff / n);
797 Eigen::VectorXd x_means =
means(x);
798 Eigen::VectorXd out(p);
800 for (
int j = 0; j < p; ++j) {
801 out(j) = (x.col(j).array() - x_means(j)).matrix().norm();
804 out.array() /= std::sqrt(n);
821ranges(
const Eigen::SparseMatrixBase<T>& x)
823 const int p = x.cols();
825 Eigen::VectorXd out(p);
827 for (
int j = 0; j < p; ++j) {
828 double x_j_max = 0.0;
829 double x_j_min = 0.0;
831 for (
typename T::InnerIterator it(x.derived(), j); it; ++it) {
832 x_j_max = std::max(x_j_max, it.value());
833 x_j_min = std::min(x_j_min, it.value());
836 out(j) = x_j_max - x_j_min;
859 return x.colwise().maxCoeff() - x.colwise().minCoeff();
874mins(
const Eigen::SparseMatrixBase<T>& x)
876 const int p = x.cols();
878 Eigen::VectorXd out(p);
880 for (
int j = 0; j < p; ++j) {
881 double x_j_min = 0.0;
883 for (
typename T::InnerIterator it(x.derived(), j); it; ++it) {
884 x_j_min = std::min(x_j_min, it.value());
908mins(
const Eigen::MatrixBase<T>& x)
910 return x.colwise().minCoeff();
935 Eigen::MatrixXd& residual,
938 const Eigen::MatrixXd& w,
939 const Eigen::VectorXd& x_centers,
940 const Eigen::VectorXd& x_scales,
943 using namespace Eigen;
945 const int n = x.rows();
946 const int p = x.cols();
947 const int n_clusters = clusters.
size();
949 Eigen::VectorXd gradient = Eigen::VectorXd::Zero(n_clusters);
951 for (
int j = 0; j < n_clusters; ++j) {
952 double c_old = clusters.
coeff(j);
961 s.reserve(cluster_size);
963 for (
auto c_it = clusters.
cbegin(j); c_it != clusters.
cend(j); ++c_it) {
965 double s_k =
sign(beta(ind));
972 if (cluster_size == 1) {
973 int k = *clusters.
cbegin(j);
975 x, k, w, residual, x_centers, x_scales, s[0], jit_normalization, n);
978 x, j, s, clusters, w, residual, x_centers, x_scales, jit_normalization);
Representation of the nonzero 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 stored nonzero 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.
std::pair< double, double > computeGradientAndHessian(const Eigen::MatrixBase< 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, const Eigen::VectorXd &weight_sums)
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.
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::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)
Computes the gradient for selected coefficients.
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)
Offsets the gradient for selected coefficients.
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.