slope 0.29.0
Loading...
Searching...
No Matches
screening.cpp
Go to the documentation of this file.
1
6#include "screening.h"
7#include "kkt_check.h"
8#include "slope/math.h"
9#include "utils.h"
10#include <Eigen/Core>
11#include <stdexcept>
12
13namespace slope {
14
15typedef Eigen::Array<bool, Eigen::Dynamic, 1> ArrayXb;
16typedef Eigen::Array<bool, Eigen::Dynamic, Eigen::Dynamic> ArrayXXb;
17
18std::vector<int>
19activeSet(const Eigen::VectorXd& beta)
20{
21 ArrayXb active = beta.array() != 0.0;
22
23 return which(active);
24}
25
26std::vector<int>
27strongSet(const Eigen::VectorXd& gradient_prev,
28 const Eigen::ArrayXd& lambda,
29 const Eigen::ArrayXd& lambda_prev)
30{
31 using Eigen::VectorXd;
32 using Eigen::VectorXi;
33
34 int pm = gradient_prev.size();
35
36 assert(lambda_prev.size() == lambda.size() &&
37 "lambda_prev and lambda must have the same length");
38 assert((lambda <= lambda_prev).all() &&
39 "New lambda values must be smaller than or equal to previous values");
40
41 const VectorXd abs_grad = gradient_prev.reshaped().cwiseAbs();
42 std::vector<int> ord = sortIndex(abs_grad, true);
43
44 assert(abs_grad.size() == lambda.size());
45
46 const VectorXd tmp =
47 abs_grad(ord).array().eval() + lambda_prev - 2.0 * lambda;
48
49 int i = 0;
50 int k = 0;
51
52 double s = 0;
53
54 while (i + k < pm) {
55 s += tmp(k + i);
56
57 if (s >= 0) {
58 k = k + i + 1;
59 i = 0;
60 s = 0;
61 } else {
62 i++;
63 }
64 }
65
66 ArrayXb active_set = ArrayXb::Zero(pm);
67 active_set.head(k).setOnes();
68
69 // restore order
70 inversePermute(active_set, ord);
71
72 return which(active_set);
73}
74
75// NoScreening implementation
76std::vector<int>
77NoScreening::initialize(const std::vector<int>& full_set, int)
78{
79 return full_set;
80}
81
82std::vector<int>
83NoScreening::screen(Eigen::VectorXd&,
84 const Eigen::ArrayXd&,
85 const Eigen::ArrayXd&,
86 const Eigen::VectorXd&,
87 const std::vector<int>& full_set)
88{
89 // No screening - use all variables
90 return full_set;
91}
92
93bool
95 const Eigen::VectorXd&,
96 const Eigen::ArrayXd&,
97 std::vector<int>&,
98 const Eigen::MatrixXd&,
99 const Eigen::MatrixXd&,
100 const Eigen::VectorXd&,
101 const Eigen::VectorXd&,
103 const std::vector<int>&)
104{
105 return true;
106}
107
108bool
110 const Eigen::VectorXd&,
111 const Eigen::ArrayXd&,
112 std::vector<int>&,
113 const Eigen::SparseMatrix<double>&,
114 const Eigen::MatrixXd&,
115 const Eigen::VectorXd&,
116 const Eigen::VectorXd&,
118 const std::vector<int>&)
119{
120 return true;
121}
122
123std::string
125{
126 return "none";
127}
128
129// StrongScreening implementation
130std::vector<int>
131StrongScreening::initialize(const std::vector<int>&, int alpha_max_ind)
132{
133 return { alpha_max_ind };
134}
135
136std::vector<int>
137StrongScreening::screen(Eigen::VectorXd& gradient,
138 const Eigen::ArrayXd& lambda_curr,
139 const Eigen::ArrayXd& lambda_prev,
140 const Eigen::VectorXd& beta,
141 const std::vector<int>&)
142{
143 std::vector<int> active_set = activeSet(beta);
144 strong_set = strongSet(gradient, lambda_curr, lambda_prev);
145 strong_set = setUnion(strong_set, active_set);
146
147 // Return working set based on active set and maximum gradient
148 return setUnion(active_set, { whichMax(gradient.cwiseAbs()) });
149}
150
151template<typename MatrixType>
152bool
153StrongScreening::checkKktViolationsImpl(Eigen::VectorXd& gradient,
154 const Eigen::VectorXd& beta,
155 const Eigen::ArrayXd& lambda_curr,
156 std::vector<int>& working_set,
157 const MatrixType& x,
158 const Eigen::MatrixXd& residual,
159 const Eigen::VectorXd& x_centers,
160 const Eigen::VectorXd& x_scales,
161 JitNormalization jit_normalization,
162 const std::vector<int>& full_set)
163{
164 // First check for violations in the strong set
165 updateGradient(gradient,
166 x,
167 residual,
169 x_centers,
170 x_scales,
171 Eigen::VectorXd::Ones(x.rows()),
172 jit_normalization);
173
174 auto violations =
175 setDiff(kktCheck(gradient, beta, lambda_curr, strong_set), working_set);
176
177 if (violations.empty()) {
178 // Now check for violations in the full set
179 updateGradient(gradient,
180 x,
181 residual,
182 full_set,
183 x_centers,
184 x_scales,
185 Eigen::VectorXd::Ones(x.rows()),
186 jit_normalization);
187
188 violations =
189 setDiff(kktCheck(gradient, beta, lambda_curr, full_set), working_set);
190
191 if (violations.empty()) {
192 return true; // No violations found
193 }
194 }
195
196 // If we found violations, update the working set
197 working_set = setUnion(working_set, violations);
198 return false; // Violations found
199}
200
201bool
202StrongScreening::checkKktViolations(Eigen::VectorXd& gradient,
203 const Eigen::VectorXd& beta,
204 const Eigen::ArrayXd& lambda_curr,
205 std::vector<int>& working_set,
206 const Eigen::MatrixXd& x,
207 const Eigen::MatrixXd& residual,
208 const Eigen::VectorXd& x_centers,
209 const Eigen::VectorXd& x_scales,
210 JitNormalization jit_normalization,
211 const std::vector<int>& full_set)
212{
213 return checkKktViolationsImpl(gradient,
214 beta,
215 lambda_curr,
216 working_set,
217 x,
218 residual,
219 x_centers,
220 x_scales,
221 jit_normalization,
222 full_set);
223}
224
225bool
226StrongScreening::checkKktViolations(Eigen::VectorXd& gradient,
227 const Eigen::VectorXd& beta,
228 const Eigen::ArrayXd& lambda_curr,
229 std::vector<int>& working_set,
230 const Eigen::SparseMatrix<double>& x,
231 const Eigen::MatrixXd& residual,
232 const Eigen::VectorXd& x_centers,
233 const Eigen::VectorXd& x_scales,
234 JitNormalization jit_normalization,
235 const std::vector<int>& full_set)
236{
237 return checkKktViolationsImpl(gradient,
238 beta,
239 lambda_curr,
240 working_set,
241 x,
242 residual,
243 x_centers,
244 x_scales,
245 jit_normalization,
246 full_set);
247}
248
249std::string
251{
252 return "strong";
253}
254
255// Factory function to create appropriate screening rule
256std::unique_ptr<ScreeningRule>
257createScreeningRule(const std::string& screening_type)
258{
259 if (screening_type == "none") {
260 return std::make_unique<NoScreening>();
261 } else if (screening_type == "strong") {
262 return std::make_unique<StrongScreening>();
263 } else {
264 throw std::invalid_argument("Unknown screening type: " + screening_type);
265 }
266}
267
268} // namespace slope
std::vector< int > initialize(const std::vector< int > &full_set, int alpha_max_ind) override
Initialize the screening rule at the start of the path algorithm.
Definition screening.cpp:77
std::vector< int > screen(Eigen::VectorXd &gradient, const Eigen::ArrayXd &lambda_curr, const Eigen::ArrayXd &lambda_prev, const Eigen::VectorXd &beta, const std::vector< int > &full_set) override
Screen for the next path step.
Definition screening.cpp:83
std::string toString() const override
Get string representation of the screening rule.
bool checkKktViolations(Eigen::VectorXd &gradient, const Eigen::VectorXd &beta, const Eigen::ArrayXd &lambda_curr, std::vector< int > &working_set, const Eigen::MatrixXd &x, const Eigen::MatrixXd &residual, const Eigen::VectorXd &x_centers, const Eigen::VectorXd &x_scales, JitNormalization jit_normalization, const std::vector< int > &full_set) override
Check for KKT violations and update working set if necessary.
Definition screening.cpp:94
std::vector< int > strong_set
Strong set of variables.
Definition screening.h:142
std::vector< int > screen(Eigen::VectorXd &gradient, const Eigen::ArrayXd &lambda_curr, const Eigen::ArrayXd &lambda_prev, const Eigen::VectorXd &beta, const std::vector< int > &full_set) override
Screen for the next path step.
std::vector< int > initialize(const std::vector< int > &full_set, int alpha_max_ind) override
Initialize the screening rule at the start of the path algorithm.
std::string toString() const override
Get string representation of the screening rule.
bool checkKktViolations(Eigen::VectorXd &gradient, const Eigen::VectorXd &beta, const Eigen::ArrayXd &lambda_curr, std::vector< int > &working_set, const Eigen::MatrixXd &x, const Eigen::MatrixXd &residual, const Eigen::VectorXd &x_centers, const Eigen::VectorXd &x_scales, JitNormalization jit_normalization, const std::vector< int > &full_set) override
Check for KKT violations and update working set if necessary.
Karush-Kuhn-Tucker (KKT) optimality condition checking for SLOPE regression.
Mathematical support functions for the slope package.
Namespace containing SLOPE regression implementation.
Definition clusters.cpp:5
Eigen::Array< bool, Eigen::Dynamic, 1 > ArrayXb
Dynamic-size column vector of boolean values Wrapper around Eigen::Array<bool, Eigen::Dynamic,...
Definition kkt_check.h:18
std::vector< int > kktCheck(const Eigen::VectorXd &gradient, const Eigen::VectorXd &beta, const Eigen::ArrayXd &lambda, const std::vector< int > &indices)
Checks KKT conditions for SLOPE optimization.
Definition kkt_check.cpp:9
std::vector< int > which(const T &x)
Definition utils.h:60
std::unique_ptr< ScreeningRule > createScreeningRule(const std::string &screening_type)
Creates a screening rule based on the provided type.
JitNormalization
Enums to control predictor standardization behavior.
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::Array< bool, Eigen::Dynamic, Eigen::Dynamic > ArrayXXb
Dynamic-size matrix of boolean values Wrapper around Eigen::Array<bool, Eigen::Dynamic,...
Definition kkt_check.h:25
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
std::vector< int > strongSet(const Eigen::VectorXd &gradient_prev, const Eigen::ArrayXd &lambda, const Eigen::ArrayXd &lambda_prev)
Determines the strong set using sequential strong rules.
Definition screening.cpp:27
std::vector< int > sortIndex(T &v, const bool descending=false)
Definition utils.h:89
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:223
std::vector< int > activeSet(const Eigen::VectorXd &beta)
Identifies previously active variables.
Definition screening.cpp:19
int whichMax(const T &x)
Returns the index of the maximum element in a container.
Definition math.h:365
void inversePermute(T &values, const std::vector< int > &ind)
Definition utils.h:152
Screening rules for SLOPE regression optimization.
Various utility functions.