11#include <Eigen/SparseCore>
37 return (T(0) < val) - (val < T(0));
52 std::vector<double> cum_sum(x.size());
53 std::partial_sum(x.begin(), x.end(), cum_sum.begin(), std::plus<double>());
55 Eigen::Map<Eigen::ArrayXd> out(cum_sum.data(), cum_sum.size());
73 return 1.0 / (1.0 + std::exp(-x));
89 assert(x > 0 && x < 1 &&
"Input must be in (0, 1)");
91 return std::log(x) - std::log1p(-x);
105clamp(
const T& x,
const T& lo,
const T& hi)
107 return x < lo ? lo : x > hi ? hi : x;
128softmax(
const Eigen::MatrixXd& x);
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,
153 const bool intercept)
157 int m = beta0.size();
159 Eigen::MatrixXd eta = Eigen::MatrixXd::Zero(n, m);
162 bool large_problem = active_set.size() > 100 && n * active_set.size() > 1e7;
163#pragma omp parallel num_threads(Threads::get()) if (large_problem)
166 Eigen::MatrixXd eta_local = Eigen::MatrixXd::Zero(n, m);
169#pragma omp for nowait
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);
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);
182 eta_local.col(k) += x.col(j) * beta(ind);
183 eta_local.col(k).array() -= beta(ind) * x_centers(j);
187 eta_local.col(k) += x.col(j) * beta(ind) / x_scales(j);
191 eta_local.col(k) += x.col(j) * beta(ind);
205 eta.rowwise() += beta0.transpose();
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,
236 const int n = x.rows();
237 const int p = x.cols();
238 const int m = residual.cols();
240 assert(gradient.size() == p * m &&
241 "Gradient matrix has incorrect dimensions");
243 Eigen::MatrixXd weighted_residual(n, m);
244 Eigen::ArrayXd wr_sums(m);
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)
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();
256#pragma omp parallel for num_threads(Threads::get()) if (large_problem)
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);
262 switch (jit_normalization) {
265 (x.col(j).dot(weighted_residual.col(k)) - x_centers(j) * wr_sums(k)) /
270 (x.col(j).dot(weighted_residual.col(k)) - x_centers(j) * wr_sums(k)) /
275 x.col(j).dot(weighted_residual.col(k)) / (x_scales(j) * n);
278 gradient(ind) = x.col(j).dot(weighted_residual.col(k)) / n;
301 const Eigen::VectorXd& offset,
302 const std::vector<int>& active_set,
303 const Eigen::VectorXd& x_centers,
304 const Eigen::VectorXd& x_scales,
307 const int n = x.rows();
308 const int p = x.cols();
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);
314 switch (jit_normalization) {
317 offset(k) * (x.col(j).sum() / n - x_centers(j)) / x_scales(j);
320 gradient(ind) -= offset(k) * (x.col(j).sum() / n - x_centers(j));
323 gradient(ind) -= offset(k) * x.col(j).sum() / (n * x_scales(j));
326 gradient(ind) -= offset(k) * x.col(j).sum() / n;
341setUnion(
const std::vector<int>& a,
const std::vector<int>& b);
354setDiff(
const std::vector<int>& a,
const std::vector<int>& b);
371 return std::distance(x.begin(), std::max_element(x.begin(), x.end()));
389 return std::distance(x.begin(), std::min_element(x.begin(), x.end()));
405template<
typename T,
typename Comparator>
409 return std::distance(x.begin(), std::max_element(x.begin(), x.end(), comp));
427geomSpace(
const double start,
const double end,
const int n);
445 const int p = x.cols();
447 Eigen::VectorXd out(p);
449 for (
int j = 0; j < p; ++j) {
450 out(j) = x.col(j).cwiseAbs().sum();
467l2Norms(
const Eigen::SparseMatrix<double>& x);
480l2Norms(
const Eigen::MatrixXd& x);
494maxAbs(
const Eigen::SparseMatrix<double>& x);
509maxAbs(
const Eigen::MatrixXd& x);
523means(
const Eigen::SparseMatrix<double>& x);
537means(
const Eigen::MatrixXd& x);
552stdDevs(
const Eigen::SparseMatrix<double>& x);
567stdDevs(
const Eigen::MatrixXd& x);
580ranges(
const Eigen::SparseMatrix<double>& x);
596ranges(
const Eigen::MatrixXd& x);
609mins(
const Eigen::SparseMatrix<double>& x);
625mins(
const Eigen::MatrixXd& x);
629clusterGradient(Eigen::VectorXd& beta,
630 Eigen::VectorXd& residual,
633 const Eigen::VectorXd& w,
634 const Eigen::VectorXd& x_centers,
635 const Eigen::VectorXd& x_scales,
638 using namespace Eigen;
640 const int n = x.rows();
641 const int n_clusters = clusters.n_clusters();
643 Eigen::VectorXd gradient = Eigen::VectorXd::Zero(n_clusters);
645 for (
int j = 0; j < n_clusters; ++j) {
646 double c_old = clusters.coeff(j);
653 int cluster_size = clusters.cluster_size(j);
655 s.reserve(cluster_size);
657 for (
auto c_it = clusters.cbegin(j); c_it != clusters.cend(j); ++c_it) {
658 double s_k =
sign(beta(*c_it));
662 double hessian_j = 1;
663 double gradient_j = 0;
665 if (cluster_size == 1) {
666 int k = *clusters.cbegin(j);
668 x, k, w, residual, x_centers, x_scales, s[0], jit_normalization, n);
671 x, j, s, clusters, w, residual, x_centers, x_scales, jit_normalization);
674 gradient(j) = gradient_j;
The declaration of the Clusters class.
Enums to control predictor standardization behavior.
Namespace containing SLOPE regression implementation.
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.
Eigen::VectorXd maxAbs(const Eigen::SparseMatrix< double > &x)
Computes the maximum absolute value for each column of a matrix.
Eigen::VectorXd means(const Eigen::SparseMatrix< double > &x)
Computes the arithmetic mean for each column of a sparse matrix.
int whichMin(const T &x)
Returns the index of the minimum element in a container.
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)
Eigen::ArrayXd cumSum(const T &x)
JitNormalization
Enums to control predictor standardization behavior.
@ None
No JIT normalization.
Eigen::VectorXd logSumExp(const Eigen::MatrixXd &a)
Eigen::MatrixXd softmax(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 stdDevs(const Eigen::SparseMatrix< double > &x)
Computes the standard deviation for each column of a matrix.
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)
std::vector< int > setUnion(const std::vector< int > &a, const std::vector< int > &b)
Computes the union of two sorted integer vectors.
int whichBest(const T &x, const Comparator &comp)
Returns the index of the minimum element in a container.
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)
Eigen::VectorXd ranges(const Eigen::SparseMatrix< double > &x)
Computes the range (max - min) for each column of a matrix.
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 l2Norms(const Eigen::SparseMatrix< double > &x)
Computes the L2 (Euclidean) norms for each column of a sparse matrix.
Eigen::VectorXd mins(const Eigen::SparseMatrix< double > &x)
Computes the minimum value for each column of a sparse 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.
int whichMax(const T &x)
Returns the index of the maximum element in a container.
Thread management for parallel computations.