HDIM  1.0.0
Packages for High Dimensional Linear Regression
screeningsolver.hpp
1 #ifndef SCREENINGSOLVER_HPP
2 #define SCREENINGSOLVER_HPP
3 
4 // C System-Headers
5 //
6 // C++ System headers
7 #include <numeric>
8 // Eigen Headers
9 #include <eigen3/Eigen/Dense>
10 #include <eigen3/Eigen/Core>
11 // Boost Headers
12 //
13 // SPAMS Headers
14 //
15 // OpenMP Headers
16 //
17 // Project Specific Headers
18 #include "../Generic/generics.hpp"
19 #include "../Generic/debug.hpp"
20 #include "../Screening/screening_rules.hpp"
21 #include "abstractsolver.hpp"
22 
23 namespace hdim {
24 
25 namespace internal {
26 
27 template < typename T >
28 
32 class ScreeningSolver : public AbstractSolver < T > {
33 
34  public:
35 
37  virtual ~ScreeningSolver() = 0;
38 
39  virtual Eigen::Matrix< T, Eigen::Dynamic, 1 > operator()(
40  const Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic >& X,
41  const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Y,
42  const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Beta_0,
43  T lambda,
44  unsigned int num_iterations );
45 
46  virtual Eigen::Matrix< T, Eigen::Dynamic, 1 > operator()(
47  const Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic >& X,
48  const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Y,
49  const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Beta_0,
50  T lambda,
51  T duality_gap_target );
52 
53  protected:
54 
55  virtual Eigen::Matrix< T, Eigen::Dynamic, 1 > update_rule(
56  const Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic >& X,
57  const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Y,
58  const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Beta_0,
59  T lambda ) = 0;
60 
61 };
62 
63 template < typename T >
65  DEBUG_PRINT( "Using Screening Rules" );
66 }
67 
68 template < typename T >
70 
71 // Iterative
72 template < typename T >
73 Eigen::Matrix< T, Eigen::Dynamic, 1 > ScreeningSolver<T>::operator()(
74  const Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic >& X,
75  const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Y,
76  const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Beta_0,
77  T lambda,
78  T duality_gap_target ) {
79 
80  const T lambda_half = lambda / 2.0;
81 
82  Eigen::Matrix< T, Eigen::Dynamic, 1 > Beta = Beta_0;
83 
84  Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic > X_A = X;
85  Eigen::Matrix< T, Eigen::Dynamic, 1 > Beta_A = Beta;
86 
87  std::vector< unsigned int > active_set, inactive_set;
88 
89  // Initialize vector of values [ 0, 1, ..., p - 1, p ]
90  std::vector< unsigned int > universe ( X.cols() );
91  std::iota ( std::begin(universe), std::end(universe) , 0 );
92 
93  T duality_gap_2 = static_cast<T>( 0 );
94 
95  bool optim_continue = true;
96  unsigned int counter = 0;
97 
98  while( optim_continue ) {
99 
100  Eigen::Matrix< T, Eigen::Dynamic, 1 > nu = DualPoint( X_A, Y, Beta_A, lambda_half );
101  duality_gap_2 = DualityGap2( X_A, Y, Beta_A, nu, lambda_half );
102 
103  if( duality_gap_2 <= duality_gap_target ) {
104  optim_continue = false;
105  }
106 
107  if( counter % 10 == 0 ) {
108 
109  T radius = std::sqrt( 2.0 * duality_gap_2 / square( lambda ) );
110  active_set = SafeActiveSet( X, nu, radius );
111 
112  X_A = slice( X, active_set );
113  Beta_A = slice( Beta, active_set );
114 
115  std::set_difference( universe.begin(),
116  universe.end(),
117  active_set.begin(),
118  active_set.end(),
119  std::inserter(inactive_set, inactive_set.begin()) );
120  }
121 
122  Beta_A = update_rule( X_A, Y, Beta_A, lambda );
123 
124  for( unsigned int x = 0; x < active_set.size() ; x++ ) {
125 
126  unsigned int active_index = active_set[ x ];
127  Beta( active_index ) = Beta_A[ x ];
128 
129  }
130 
131  for( const auto& inactive_index : inactive_set ) {
132  Beta( inactive_index ) = 0.0;
133  }
134 
135  counter ++;
136  DEBUG_PRINT( "Duality Gap:" << duality_gap_2 );
137 
138  }
139 
140  return Beta;
141 
142 }
143 
144 // Duality Gap Convergence Criteria
145 template < typename T >
146 Eigen::Matrix< T, Eigen::Dynamic, 1 > ScreeningSolver<T>::operator()(
147  const Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic >& X,
148  const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Y,
149  const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Beta_0,
150  T lambda,
151  unsigned int num_iterations ) {
152 
153  const T lambda_half = lambda / 2.0;
154 
155  Eigen::Matrix< T, Eigen::Dynamic, 1 > Beta = Beta_0;
156 
157  Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic > X_A = X;
158  Eigen::Matrix< T, Eigen::Dynamic, 1 > Beta_A = Beta;
159 
160 
161  std::vector< unsigned int > active_set, inactive_set;
162 
163  // Initialize vector of values [ 0, 1, ..., p - 1, p ]
164  std::vector< unsigned int > universe ( X.cols() );
165  std::iota ( std::begin(universe), std::end(universe) , 0 );
166 
167  T duality_gap_2 = static_cast<T>( 0 );
168 
169  for( unsigned int i = 0; i < num_iterations ; i++ ) {
170 
171  Eigen::Matrix< T, Eigen::Dynamic, 1 > nu = DualPoint( X_A, Y, Beta_A, lambda_half );
172  duality_gap_2 = DualityGap2( X_A, Y, Beta_A, nu, lambda_half );
173 
174  if( i % 10 == 0 ) {
175 
176  T radius = std::sqrt( 2.0 * duality_gap_2 / square( lambda ) );
177  active_set = SafeActiveSet( X, nu, radius );
178 
179  X_A = slice( X, active_set );
180  Beta_A = slice( Beta, active_set );
181 
182  std::set_difference( universe.begin(),
183  universe.end(),
184  active_set.begin(),
185  active_set.end(),
186  std::inserter(inactive_set, inactive_set.begin()) );
187  }
188 
189  Beta_A = update_rule( X_A, Y, Beta_A, lambda );
190 
191  for( unsigned int x = 0; x < active_set.size() ; x++ ) {
192 
193  unsigned int active_index = active_set[ x ];
194  Beta( active_index ) = Beta_A[ x ];
195 
196  }
197 
198  for( const auto& inactive_index : inactive_set ) {
199  Beta( inactive_index ) = 0.0;
200  }
201 
202  DEBUG_PRINT( "Duality Gap:" << duality_gap_2 );
203 
204  }
205 
206  return Beta;
207 
208 }
209 
210 }
211 
212 }
213 
214 #endif // SCREENINGSOLVER_HPP
Definition: fos.hpp:18
virtual 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, T lambda, unsigned int num_iterations)
Run the AbstractSolver for a fixed number of steps, specified by num_iterations.
#define DEBUG_PRINT(x,...)
Definition: debug.hpp:73
T square(T &val)
Compute the square of a value.
Definition: generics.hpp:169
Abstract base class for all iterative solvers.
Abstract base class for Solvers that use GAP SAFE screening rules.