11#include <Eigen/SparseCore>
33 return (T(0) < val) - (val < T(0));
48 std::vector<double> cum_sum(x.size());
49 std::partial_sum(x.begin(), x.end(), cum_sum.begin(), std::plus<double>());
51 Eigen::Map<Eigen::ArrayXd> out(cum_sum.data(), cum_sum.size());
69 return 1.0 / (1.0 + std::exp(-x));
85 assert(x > 0 && x < 1 &&
"Input must be in (0, 1)");
87 return std::log(x) - std::log1p(-x);
101clamp(
const T& x,
const T& lo,
const T& hi)
103 return x < lo ? lo : x > hi ? hi : x;
124softmax(
const Eigen::MatrixXd& x);
143 const std::vector<int>& active_set,
144 const Eigen::VectorXd& beta0,
145 const Eigen::VectorXd& beta,
146 const Eigen::VectorXd& x_centers,
147 const Eigen::VectorXd& x_scales,
149 const bool intercept)
153 int m = beta0.size();
155 Eigen::MatrixXd eta = Eigen::MatrixXd::Zero(n, m);
158 bool large_problem = active_set.size() > 100 && n * active_set.size() > 1e7;
159#pragma omp parallel num_threads(Threads::get()) if (large_problem)
162 Eigen::MatrixXd eta_local = Eigen::MatrixXd::Zero(n, m);
165#pragma omp for nowait
167 for (
size_t i = 0; i < active_set.size(); ++i) {
168 int ind = active_set[i];
169 auto [k, j] = std::div(ind, p);
171 switch (jit_normalization) {
173 eta_local.col(k) += x.col(j) * beta(ind) / x_scales(j);
174 eta_local.col(k).array() -= beta(ind) * x_centers(j) / x_scales(j);
178 eta_local.col(k) += x.col(j) * beta(ind);
179 eta_local.col(k).array() -= beta(ind) * x_centers(j);
183 eta_local.col(k) += x.col(j) * beta(ind) / x_scales(j);
187 eta_local.col(k) += x.col(j) * beta(ind);
201 eta.rowwise() += beta0.transpose();
225 const Eigen::MatrixXd& residual,
226 const std::vector<int>& active_set,
227 const Eigen::VectorXd& x_centers,
228 const Eigen::VectorXd& x_scales,
229 const Eigen::VectorXd& w,
232 const int n = x.rows();
233 const int p = x.cols();
234 const int m = residual.cols();
236 assert(gradient.size() == p * m &&
237 "Gradient matrix has incorrect dimensions");
239 Eigen::MatrixXd weighted_residual(n, m);
240 Eigen::ArrayXd wr_sums(m);
243 bool large_problem = active_set.size() > 100 && n * active_set.size() > 1e5;
244#pragma omp parallel for num_threads(Threads::get()) if (large_problem)
246 for (
int k = 0; k < m; ++k) {
247 weighted_residual.col(k) = residual.col(k).cwiseProduct(w);
248 wr_sums(k) = weighted_residual.col(k).sum();
252#pragma omp parallel for num_threads(Threads::get()) if (large_problem)
254 for (
size_t i = 0; i < active_set.size(); ++i) {
255 int ind = active_set[i];
256 auto [k, j] = std::div(ind, p);
258 switch (jit_normalization) {
261 (x.col(j).dot(weighted_residual.col(k)) - x_centers(j) * wr_sums(k)) /
266 (x.col(j).dot(weighted_residual.col(k)) - x_centers(j) * wr_sums(k)) /
271 x.col(j).dot(weighted_residual.col(k)) / (x_scales(j) * n);
274 gradient(ind) = x.col(j).dot(weighted_residual.col(k)) / n;
297 const Eigen::VectorXd& offset,
298 const std::vector<int>& active_set,
299 const Eigen::VectorXd& x_centers,
300 const Eigen::VectorXd& x_scales,
303 const int n = x.rows();
304 const int p = x.cols();
306 for (
size_t i = 0; i < active_set.size(); ++i) {
307 int ind = active_set[i];
308 auto [k, j] = std::div(ind, p);
310 switch (jit_normalization) {
313 offset(k) * (x.col(j).sum() / n - x_centers(j)) / x_scales(j);
316 gradient(ind) -= offset(k) * (x.col(j).sum() / n - x_centers(j));
319 gradient(ind) -= offset(k) * x.col(j).sum() / (n * x_scales(j));
322 gradient(ind) -= offset(k) * x.col(j).sum() / n;
337setUnion(
const std::vector<int>& a,
const std::vector<int>& b);
350setDiff(
const std::vector<int>& a,
const std::vector<int>& b);
367 return std::distance(x.begin(), std::max_element(x.begin(), x.end()));
385 return std::distance(x.begin(), std::min_element(x.begin(), x.end()));
401template<
typename T,
typename Comparator>
405 return std::distance(x.begin(), std::max_element(x.begin(), x.end(), comp));
423geomSpace(
const double start,
const double end,
const int n);
441 const int p = x.cols();
443 Eigen::VectorXd out(p);
445 for (
int j = 0; j < p; ++j) {
446 out(j) = x.col(j).cwiseAbs().sum();
463l2Norms(
const Eigen::SparseMatrix<double>& x);
476l2Norms(
const Eigen::MatrixXd& x);
490maxAbs(
const Eigen::SparseMatrix<double>& x);
505maxAbs(
const Eigen::MatrixXd& x);
519means(
const Eigen::SparseMatrix<double>& x);
533means(
const Eigen::MatrixXd& x);
548stdDevs(
const Eigen::SparseMatrix<double>& x);
563stdDevs(
const Eigen::MatrixXd& x);
576ranges(
const Eigen::SparseMatrix<double>& x);
592ranges(
const Eigen::MatrixXd& x);
605mins(
const Eigen::SparseMatrix<double>& x);
621mins(
const Eigen::MatrixXd& x);
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.
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.
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.