1 #ifndef COORDINATEDESCENTWITHSCREEN_HPP     2 #define COORDINATEDESCENTWITHSCREEN_HPP    12 #include <type_traits>    15 #include <eigen3/Eigen/Dense>    21 #include "../../Generic/debug.hpp"    22 #include "../../Generic/generics.hpp"    23 #include "../../Screening/screening_rules.hpp"    24 #include "../solver.hpp"    28 template < 
typename T >
    33                                  const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Y,
    34                                  const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Beta_0 );
    37     Eigen::Matrix< T, Eigen::Dynamic, 1 > 
operator()(
const Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic >& X,
    38             const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Y,
    39             const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Beta_0,
    41             const T duality_gap_target );
    43     Eigen::Matrix< T, Eigen::Dynamic, 1 > 
operator()(
    44         const Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic >& X,
    45         const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Y,
    46         const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Beta_0,
    48         const unsigned int num_iterations );
    51     std::vector<T> inverse_norms;
    55 template < 
typename T >
    57     const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> &X,
    58     const Eigen::Matrix<T, Eigen::Dynamic, 1> &Y,
    59     const Eigen::Matrix<T, Eigen::Dynamic, 1> &Beta_0 ) {
    63     inverse_norms.reserve( Beta_0.size() );
    65     for( 
int i = 0; i < Beta_0.size() ; i++ ) {
    67         T X_i_norm = X.col( i ).squaredNorm();
    69         T inverse_norm = ( X_i_norm == 0 )?( 0.0 ):( 
static_cast<T
>(1)/X_i_norm );
    70         inverse_norms.push_back( inverse_norm );
    75 template < 
typename T >
    78 template < 
typename T >
    80     const Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic >& X,
    81     const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Y,
    82     const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Beta_0,
    84     const unsigned int num_iterations ) {
    86     const T lambda_half = lambda / 2.0;
    88     Eigen::Matrix< T, Eigen::Dynamic, 1 > Beta = Beta_0;
    89     Eigen::Matrix< T, Eigen::Dynamic, 1 > Residual = Y - X*Beta_0;
    91     Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic > X_A = X;
    92     Eigen::Matrix< T, Eigen::Dynamic, 1 > Beta_A = Beta;
    95     std::vector< unsigned int > active_set, inactive_set;
    98     std::vector< unsigned int > universe ( X.cols() );
    99     std::iota ( std::begin(universe), std::end(universe) , 0 );
   101     T duality_gap_2 = 
static_cast<T
>( 0 );
   103     for( 
unsigned int j = 0; j < num_iterations ; j ++ ) {
   105         Eigen::Matrix< T, Eigen::Dynamic, 1 > nu = DualPoint( X_A, Y, Beta_A, lambda_half );
   106         duality_gap_2 = DualityGap2( X_A, Y, Beta_A, nu, lambda_half );
   110             T radius = std::sqrt( 2.0 * duality_gap_2 / 
square( lambda ) );
   111             active_set = SafeActiveSet( X, nu, radius );
   113             X_A = slice( X, active_set );
   114             Beta_A = slice( Beta, active_set );
   116             std::set_difference( universe.begin(),
   120                                  std::inserter(inactive_set, inactive_set.begin()) );
   123         for( 
const auto& active_index : active_set ) {
   125             Eigen::Matrix< T, Eigen::Dynamic, 1 > X_j = X.col( active_index );
   127             if( Beta( active_index ) != static_cast<T>(0) ) {
   128                 Residual = Residual + X_j*Beta( active_index );
   131             T inverse_norm_j = inverse_norms[ active_index ];
   133             T threshold = lambda_half * inverse_norm_j;
   134             T elem = inverse_norm_j*X_j.transpose()*Residual;
   136             Beta( active_index ) = soft_threshold<T>( elem, threshold );
   138             if( Beta( active_index ) != 
static_cast<T
>(0) ) {
   139                 Residual = Residual - X_j*Beta( active_index );
   144         for( 
const auto& inactive_index : inactive_set ) {
   145             Beta( inactive_index ) = 0.0;
   148         DEBUG_PRINT( 
"Norm Squared of updated Beta: " << Beta.squaredNorm() );
   155 template < 
typename T >
   157     const Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic >& X,
   158     const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Y,
   159     const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Beta_0,
   161     const T duality_gap_target ) {
   163     const T lambda_half = lambda / 2.0;
   164     const T dgt_half = duality_gap_target / 2.0;
   166     Eigen::Matrix< T, Eigen::Dynamic, 1 > Beta = Beta_0;
   167     Eigen::Matrix< T, Eigen::Dynamic, 1 > Residual = Y - X*Beta_0;
   169     Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic > X_A = X;
   170     Eigen::Matrix< T, Eigen::Dynamic, 1 > Beta_A = Beta;
   173     std::vector< unsigned int > active_set, inactive_set;
   176     std::vector< unsigned int > universe ( X.cols() );
   177     std::iota ( std::begin(universe), std::end(universe) , 0 );
   179     T duality_gap_2 = 
static_cast<T
>( 0 );
   181     unsigned int counter = 0;
   185         Eigen::Matrix< T, Eigen::Dynamic, 1 > nu = DualPoint( X_A, Y, Beta_A, lambda_half );
   186         duality_gap_2 = DualityGap2( X_A, Y, Beta_A, nu, lambda_half );
   188         if( counter % 10 == 0 ) {
   190             T radius = std::sqrt( 2.0 * duality_gap_2 / 
square( lambda ) );
   191             active_set = SafeActiveSet( X, nu, radius );
   193             X_A = slice( X, active_set );
   194             Beta_A = slice( Beta, active_set );
   196             std::set_difference( universe.begin(),
   200                                  std::inserter(inactive_set, inactive_set.begin()) );
   203         for( 
const auto& active_index : active_set ) {
   205             Eigen::Matrix< T, Eigen::Dynamic, 1 > X_j = X.col( active_index );
   207             if( Beta( active_index ) != static_cast<T>(0) ) {
   208                 Residual = Residual + X_j*Beta( active_index );
   211             T inverse_norm_j = inverse_norms[ active_index ];
   213             T threshold = lambda_half * inverse_norm_j;
   214             T elem = inverse_norm_j*X_j.transpose()*Residual;
   216             Beta( active_index ) = soft_threshold<T>( elem, threshold );
   218             if( Beta( active_index ) != 
static_cast<T
>(0) ) {
   219                 Residual = Residual - X_j*Beta( active_index );
   224         for( 
const auto& inactive_index : inactive_set ) {
   225             Beta( inactive_index ) = 0.0;
   228         DEBUG_PRINT( 
"Current Duality Gap: " << duality_gap_2 << 
" Current Target: " << dgt_half );
   229         DEBUG_PRINT( 
"Norm Squared of updated Beta: " << Beta.squaredNorm() );
   233     } 
while ( duality_gap_2 > dgt_half );
   240 #endif // COORDINATEDESCENTWITHSCREEN_HPP 
Eigen::Matrix< T, Eigen::Dynamic, 1 > operator()(const Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic > &X, const Eigen::Matrix< T, Eigen::Dynamic, 1 > &Y, const Eigen::Matrix< T, Eigen::Dynamic, 1 > &Beta_0, const T lambda, const T duality_gap_target)
Run the Sub-Gradient Descent algorithm until the duality gap is below the threshold specified by dual...
Abstract base class for solvers that do not make use of GAP SAFE screening rules. ...
#define DEBUG_PRINT(x,...)
T square(T &val)
Compute the square of a value.