10 #include <type_traits> 14 #include <eigen3/Eigen/Dense> 20 #include "../Generic/generics.hpp" 21 #include "../Solvers/abstractsolver.hpp" 22 #include "../Solvers/solver.hpp" 23 #include "../Solvers/screeningsolver.hpp" 24 #include "../Solvers/SubGradientDescent/ISTA/ista.hpp" 25 #include "../Solvers/SubGradientDescent/FISTA/fista.hpp" 26 #include "../Solvers/CoordinateDescent/coordinate_descent.hpp" 30 enum class SolverType { ista, screen_ista, fista, screen_fista, cd, screen_cd };
32 template <
typename T >
50 void operator()(
const Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic >& x,
51 const Eigen::Matrix< T, Eigen::Dynamic, 1 >& y,
52 SolverType s_type = SolverType::ista );
56 Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic > ReturnBetas();
57 unsigned int ReturnOptimIndex();
58 Eigen::Matrix< T, Eigen::Dynamic, 1 > ReturnCoefficients();
59 Eigen::Matrix< int, Eigen::Dynamic, 1 > ReturnSupport();
63 Eigen::Matrix< T, Eigen::Dynamic, 1 > fos_fit;
65 unsigned int optim_index;
70 Eigen::Matrix< T, Eigen::Dynamic, 1 > X_weights(
const Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic >& X );
72 T Y_weight(
const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Y );
74 Eigen::Matrix< T, Eigen::Dynamic, 1 > RescaleCoefficients(
const Eigen::Matrix< T, Eigen::Dynamic, 1 >& raw_coefs,
75 const Eigen::Matrix< T, Eigen::Dynamic, 1 >& x_weights,
78 T compute_intercept(
const Eigen::Matrix< T, Eigen::Dynamic, 1 >& x,
79 const Eigen::Matrix< T, Eigen::Dynamic, 1 >& y,
80 const Eigen::Matrix< T, Eigen::Dynamic, 1 >& fit );
82 std::vector< T > GenerateLambdaGrid (
83 const Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic >& X,
84 const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Y,
87 bool ComputeStatsCond(T C,
88 unsigned int stats_it,
90 const std::vector<T> &lambdas,
91 const Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic >& Betas );
93 T duality_gap_target( T gamma, T C, T r_stats_it,
unsigned int n );
95 T primal_objective(
const Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic >& X,
96 const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Y,
97 const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Beta,
100 T dual_objective(
const Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic >& X,
101 const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Y,
102 const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Beta,
105 Eigen::Matrix< int, Eigen::Dynamic, 1 > ApplyScreening(
const Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic >& x,
106 const Eigen::Matrix< T, Eigen::Dynamic, 1 >& nu_tilde,
110 void choose_solver(
const Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic >& x,
111 const Eigen::Matrix< T, Eigen::Dynamic, 1 >& y,
112 const Eigen::Matrix< T, Eigen::Dynamic, 1 >& beta,
115 std::unique_ptr< internal::AbstractSolver<T> > solver;
117 Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic > Betas;
118 Eigen::Matrix< T, Eigen::Dynamic, 1 > x_std_devs;
123 const unsigned int M = 100;
126 unsigned int loop_index = 0;
128 unsigned int statsIt = 1;
135 template<
typename T >
146 static_assert(std::is_floating_point< T >::value,
"X_FOS can only be used with floating point types.");
149 template <
typename T >
152 template <
typename T >
157 template <
typename T >
162 template <
typename T >
167 template <
typename T >
169 return RescaleCoefficients(fos_fit, x_std_devs, y_std_dev );
172 template <
typename T >
175 T n_t =
static_cast<T
>( n );
176 T cut_off =
static_cast<T
>( 6 )*C*lambda/n_t;
177 DEBUG_PRINT(
"Cut-off for Support Computation: " << cut_off );
179 return GenerateSupport( fos_fit, cut_off );
184 template <
typename T >
186 const Eigen::Matrix< T, Eigen::Dynamic, 1 >& y,
187 const Eigen::Matrix< T, Eigen::Dynamic, 1 >& fit ) {
189 Eigen::Matrix< T, Eigen::Dynamic, 1 > scaled_beta = RescaleCoefficients( fit, x_std_devs, y_std_dev );
191 T intercept_part = 0.0;
193 for(
unsigned int i = 0; i < x.cols() ; i++ ) {
195 T X_i_bar = x.col( i ).mean();
196 intercept_part += scaled_beta( i )*X_i_bar;
200 return static_cast<T
>( y.mean() ) - static_cast<T>( intercept_part );
203 template <
typename T >
210 template <
typename T >
220 unsigned int stats_it,
222 const std::vector <T>& lambdas,
223 const Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic >& Betas ) {
225 bool stats_cond =
true;
227 for (
unsigned int i = 1; i <= stats_it; i++ ) {
229 Eigen::Matrix< T, Eigen::Dynamic, 1 > beta_k = Betas.col( i - 1 );
230 T rk = lambdas.at( i - 1 );
232 Eigen::Matrix< T, Eigen::Dynamic, 1 > beta_diff = Betas.col( stats_it - 1 ) - beta_k;
233 T abs_max_betas = beta_diff.template lpNorm< Eigen::Infinity >();
235 T n_t =
static_cast<T
>( n );
236 T check_parameter = n_t*abs_max_betas / ( r_stats_it + rk );
238 stats_cond &= ( check_parameter <= C );
245 template <
typename T >
251 const Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic >& X,
252 const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Y,
255 T rMax = 2.0*( X.transpose() * Y ).
template lpNorm< Eigen::Infinity >();
262 template <
typename T >
264 const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Y, \
265 const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Beta, \
268 Eigen::Matrix< T, Eigen::Dynamic, 1 > error = Y - X*Beta;
269 T f_beta = error.squaredNorm() + r_stats_it*Beta.template lpNorm < 1 >();
275 template <
typename T >
277 const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Y, \
278 const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Beta, \
282 T s_chunk = r_stats_it / ( 2.0*X.transpose()*( X*Beta - Y ) ).template lpNorm< Eigen::Infinity >();
283 T s_chunk_prime = ( -
static_cast<T
>( Y.transpose()*( X*Beta - Y ) ) )/( Y - X*Beta ).squaredNorm();
284 T s = std::min( std::max( - s_chunk, s_chunk_prime ), s_chunk );
287 Eigen::Matrix< T, Eigen::Dynamic, 1 > nu_tilde = 2.0*s/r_stats_it*( X*Beta - Y );
289 T d_nu =
square( r_stats_it )/4.0*( nu_tilde + 2.0/r_stats_it*Y ).squaredNorm() - Y.squaredNorm();
294 template <
typename T >
297 T n_f =
static_cast<T
>( n );
302 template <
typename T >
303 Eigen::Matrix< T, Eigen::Dynamic, 1 >
X_FOS< T >::X_weights(
const Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic >& X ) {
305 Eigen::Matrix< T, Eigen::Dynamic, 1 > weights( X.cols() );
307 for(
unsigned int i = 0; i < X.cols() ; i ++ ) {
308 Eigen::Matrix< T, Eigen::Dynamic, 1 > X_i = X.col( i );
309 weights( i ) = StdDev( X_i );
315 template <
typename T >
320 template <
typename T >
322 const Eigen::Matrix< T, Eigen::Dynamic, 1 >& raw_coefs,
323 const Eigen::Matrix< T, Eigen::Dynamic, 1 >& x_weights,
326 Eigen::Matrix< T, Eigen::Dynamic, 1 > scaled_coefs( raw_coefs.size() );
328 for(
unsigned int i = 0; i < raw_coefs.size() ; i++ ) {
330 T weight = ( x_weights(i) == 0.0 )?( 0.0 ):( y_weight / x_weights(i) );
331 scaled_coefs( i ) = weight*raw_coefs( i );
339 template <
typename T >
340 Eigen::Matrix< int, Eigen::Dynamic, 1 >
X_FOS< T >::ApplyScreening(
const Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic >& x,
341 const Eigen::Matrix< T, Eigen::Dynamic, 1 >& nu_tilde,
345 Eigen::Matrix< int, Eigen::Dynamic, 1 > A( x.cols() );
346 unsigned int counter = 0;
348 for(
unsigned int j = 0; j < x.cols(); j ++ ) {
350 Eigen::Matrix< T, Eigen::Dynamic, 1 > X_j = x.col( j );
352 T radius = std::abs( static_cast<T>( X_j.transpose() * nu_tilde ) ) + std::sqrt( 2.0 /
square( lambda ) * duality_gap )*X_j.norm();
353 A[j] = ( radius > 1.0 );
355 if ( radius > 1.0 ) {
361 DEBUG_PRINT(
"Number of active variables: " << counter );
367 template <
typename T >
369 const Eigen::Matrix< T, Eigen::Dynamic, 1 >& y,
370 const Eigen::Matrix< T, Eigen::Dynamic, 1 >& beta,
371 SolverType s_type ) {
376 case SolverType::ista:
379 case SolverType::screen_ista:
382 case SolverType::fista:
385 case SolverType::screen_fista:
391 case SolverType::screen_cd:
398 template <
typename T >
400 const Eigen::Matrix< T, Eigen::Dynamic, 1 >& y,
401 SolverType s_type ) {
403 Eigen::Matrix< T, Eigen::Dynamic, 1 > old_Betas;
405 bool statsCont =
true;
407 x_std_devs = X_weights( x );
408 y_std_dev = Y_weight( y );
410 Eigen::Matrix< T , Eigen::Dynamic, Eigen::Dynamic > X =
Normalize( x );
411 Eigen::Matrix< T , Eigen::Dynamic, 1 > Y =
Normalize( y );
416 std::vector<T> lambda_grid = GenerateLambdaGrid( X, Y, M );
418 Betas = Eigen::Matrix< T , Eigen::Dynamic, Eigen::Dynamic >::Zero( X.cols(), M );
420 choose_solver( X, Y, Betas.col( 0 ), s_type );
423 while( statsCont && ( statsIt < M ) ) {
429 old_Betas = Betas.col( statsIt - 2 );
430 T rStatsIt = lambda_grid.at( statsIt - 1 );
432 T gap_target = duality_gap_target( gamma, C, rStatsIt, n );
435 Betas.col( statsIt - 1 ) = solver->operator()( X, Y, old_Betas, rStatsIt, gap_target );
437 statsCont = ComputeStatsCond( C, statsIt, rStatsIt, lambda_grid, Betas );
440 fos_fit = Betas.col( statsIt - 2 );
441 lambda = lambda_grid.at( statsIt - 2 );
442 optim_index = statsIt;
448 Eigen::Matrix< T, Eigen::Dynamic, 1 > scaled_beta = RescaleCoefficients( fos_fit, x_std_devs, y_std_dev );
450 T intercept_part = 0.0;
451 for(
unsigned int i = 0; i < x.cols() ; i++ ) {
452 T X_i_bar = x.col( i ).mean();
453 intercept_part += scaled_beta( i )*X_i_bar;
456 intercept = y.mean() - intercept_part;
Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic > Normalize(const Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic > &mat)
Set the mean of a matrix to 0 and the standard deviation to 1.
std::vector< T > LogScaleVector(T lower_bound, T upper_bound, unsigned int num_elements)
Generate a vector of logarithmically equally spaced points.
#define DEBUG_PRINT(x,...)
T square(T &val)
Compute the square of a value.
Run the Fast Iterative Shrinking and Thresholding Algorthim.
Run the Iterative Shrinking and Thresholding Algorthim.
void operator()(const Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic > &x, const Eigen::Matrix< T, Eigen::Dynamic, 1 > &y, SolverType s_type=SolverType::ista)
Run the main X_FOS algorithm.
X_FOS()
Initialize a new algorithm, and instantiate member attributes X and Y.