HDIM  1.0.0
Packages for High Dimensional Linear Regression
fista.hpp
1 #ifndef FISTA_H
2 #define FISTA_H
3 
4 // C System-Headers
5 //
6 // C++ System headers
7 //
8 // Eigen Headers
9 //
10 // Boost Headers
11 //
12 // SPAMS Headers
13 //
14 // OpenMP Headers
15 //
16 // Project Specific Headers
17 #include "../../../Generic/generics.hpp"
18 #include "../subgradient_descent.hpp"
19 
20 namespace hdim {
21 
22 template < typename T, typename Base = internal::Solver< T > >
26 class FISTA : public internal::SubGradientSolver<T,Base> {
27 
28  public:
29  FISTA( const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Beta_0, T L_0 = 0.1 );
30 
31  protected:
32  Eigen::Matrix< T, Eigen::Dynamic, 1 > update_rule(
33  const Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic >& X,
34  const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Y,
35  const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Beta_0,
36  T lambda );
37 
38  private:
39 
40  Eigen::Matrix< T, Eigen::Dynamic, 1 > update_beta_fista (
41  const Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic >& X,
42  const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Y,
43  const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Beta,
44  T L,
45  T thres );
46 
47  Eigen::Matrix< T, Eigen::Dynamic, 1 > y_k;
48  Eigen::Matrix< T, Eigen::Dynamic, 1 > y_k_old;
49 
50  Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic > x_k_less_1;
51 
52  const T eta = 1.5;
53  T t_k = static_cast<T>( 1 );
54  T L = static_cast<T>( 0 );
55 };
56 
57 template < typename T, typename Base >
58 FISTA<T,Base>::FISTA( const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Beta_0, T L_0 ) : internal::SubGradientSolver<T,Base>( L_0 ) {
59  y_k = Beta_0;
60  t_k = 1;
61 }
62 
63 template < typename T, typename Base >
64 Eigen::Matrix< T, Eigen::Dynamic, 1 > FISTA<T,Base>::update_beta_fista (
65  const Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic >& X,
66  const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Y,
67  const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Beta,
68  T L,
69  T thres ) {
70 
71  Eigen::Matrix< T, Eigen::Dynamic, 1 > x_k = Beta;
72 
73  x_k_less_1 = x_k;
74  x_k = internal::SubGradientSolver<T,Base>::update_beta_ista( X, Y, y_k, L, thres );
75 
76  T t_k_plus_1 = ( 1.0 + std::sqrt( 1.0 + 4.0 * square( t_k ) ) ) / 2.0;
77  t_k = t_k_plus_1;
78 
79  y_k = x_k + ( t_k - 1.0 ) / ( t_k_plus_1 ) * ( x_k - x_k_less_1 );
80 
81  return x_k;
82 }
83 
84 #ifdef DEBUG
85 template < typename T, typename Base >
86 Eigen::Matrix< T, Eigen::Dynamic, 1 > FISTA<T,Base>::update_rule(
87  const Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic >& X,
88  const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Y,
89  const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Beta,
90  T lambda ) {
91 
93 
94  y_k = Beta;
95 
96  y_k_old = y_k;
97 
98  Eigen::Matrix< T, Eigen::Dynamic, 1 > y_k_temp = internal::SubGradientSolver<T,Base>::update_beta_ista( X, Y, y_k, L, lambda );
99 
100  unsigned int counter = 0;
101 
102  while( ( internal::SubGradientSolver<T,Base>::f_beta( X, Y, y_k_temp ) > internal::SubGradientSolver<T,Base>::f_beta_tilda( X, Y, y_k_temp, y_k_old, L ) ) ) {
103 
104  counter++;
105  DEBUG_PRINT( "Backtrace iteration: " << counter );
106 
107  L*= eta;
108 
109  DEBUG_PRINT( "L: " << L );
110  y_k_temp = internal::SubGradientSolver<T,Base>::update_beta_ista( X, Y, Beta, L, lambda );
111 
112  }
113 
114  return update_beta_fista( X, Y, Beta, L, lambda );;
115 }
116 #else
117 template < typename T, typename Base >
118 Eigen::Matrix< T, Eigen::Dynamic, 1 > FISTA<T,Base>::update_rule(
119  const Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic >& X,
120  const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Y,
121  const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Beta,
122  T lambda ) {
123 
125 
126  y_k = Beta;
127 
128  y_k_old = y_k;
129 
130  Eigen::Matrix< T, Eigen::Dynamic, 1 > f_grad = 2.0*( X.transpose()*( X*y_k_old - Y ) );
131 
132  Eigen::Matrix< T, Eigen::Dynamic, 1 > to_modify = y_k_old - (1.0/L)*f_grad;
133  Eigen::Matrix< T, Eigen::Dynamic, 1 > y_k_temp = to_modify.unaryExpr( SoftThres<T>( lambda/L ) );
134 
135  unsigned int counter = 0;
136 
137  T f_beta = ( X*y_k_temp - Y ).squaredNorm();
138 
139  Eigen::Matrix< T, Eigen::Dynamic, 1 > f_part = X*y_k_old - Y;
140  T taylor_term_0 = f_part.squaredNorm();
141 
142  Eigen::Matrix< T, Eigen::Dynamic, 1 > beta_diff = ( y_k_temp - y_k_old );
143 
144  T taylor_term_1 = f_grad.transpose()*beta_diff;
145 
146  T taylor_term_2 = L/2.0*beta_diff.squaredNorm();
147 
148  T f_beta_tilde = taylor_term_0 + taylor_term_1 + taylor_term_2;
149 
150  while( f_beta > f_beta_tilde ) {
151 
152  counter++;
153  DEBUG_PRINT( "Backtrace iteration: " << counter );
154 
155  L*= eta;
156 
157  DEBUG_PRINT( "L: " << L );
158  to_modify = y_k_old - (1.0/L)*f_grad;
159  y_k_temp = to_modify.unaryExpr( SoftThres<T>( lambda/L ) );
160 
161  f_beta = ( X*y_k_temp - Y ).squaredNorm();;
162 
163  beta_diff = ( y_k_temp - y_k_old );
164  taylor_term_1 = f_grad.transpose()*beta_diff;
165  taylor_term_2 = L/2.0*beta_diff.squaredNorm();
166 
167  f_beta_tilde = taylor_term_0 + taylor_term_1 + taylor_term_2;
168 
169  }
170 
171  Eigen::Matrix< T, Eigen::Dynamic, 1 > x_k = Beta;
172 
173  x_k_less_1 = x_k;
174 
175  to_modify = y_k_old - (1.0/L)*f_grad;
176  x_k = to_modify.unaryExpr( SoftThres<T>( lambda/L ) );
177 
178  T t_k_plus_1 = ( 1.0 + std::sqrt( 1.0 + 4.0 * square( t_k ) ) ) / 2.0;
179  t_k = t_k_plus_1;
180 
181  y_k = x_k + ( t_k - 1.0 ) / ( t_k_plus_1 ) * ( x_k - x_k_less_1 );
182 
183  return x_k;
184 }
185 #endif
186 
187 }
188 
189 
190 #endif // FISTA_H
Definition: fos.hpp:18
Abstract base class for Sub-Gradient Descent algorithms ,such as ISTA and FISTA, with backtracking li...
Soft Threshold functor used to apply hdim::soft_threshold to each element in a matrix or vector...
Definition: generics.hpp:288
#define DEBUG_PRINT(x,...)
Definition: debug.hpp:73
T square(T &val)
Compute the square of a value.
Definition: generics.hpp:169
Run the Fast Iterative Shrinking and Thresholding Algorthim.
Definition: fista.hpp:26