9 #include <eigen3/Eigen/Dense> 15 #include "../Generic/debug.hpp" 16 #include "../Generic/generics.hpp" 20 template <
typename T >
30 FOS( Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic > x, Eigen::Matrix< T, Eigen::Dynamic, 1 > y );
34 Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic > ReturnBetas();
35 unsigned int ReturnOptimIndex();
36 Eigen::Matrix< T, Eigen::Dynamic, 1 > ReturnCoefficients();
37 Eigen::Matrix< T, Eigen::Dynamic, 1 > ReturnSupport();
40 Eigen::Matrix< T, Eigen::Dynamic, 1 > avfos_fit;
42 unsigned int optim_index;
45 std::vector< T > GenerateLambdaGrid(
const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> &X,
46 const Eigen::Matrix<T, Eigen::Dynamic, 1 > &Y,
50 bool ComputeStatsCond(
52 unsigned int stats_it,
54 const std::vector<T>& lambdas,
55 const Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic >& X,
56 const Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic >& Betas );
58 T duality_gap_target( T gamma, T C, T r_stats_it,
unsigned int n );
59 T dual_objective (
const Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic >& X, \
60 const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Y, \
61 const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Beta, \
63 T primal_objective(
const Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic >& X, \
64 const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Y, \
65 const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Beta, \
69 const Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic >& X,
70 const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Y,
71 const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Beta );
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,
77 const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Beta_prime,
80 Eigen::Matrix< T, Eigen::Dynamic, 1 > update_beta_ista (
81 const Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic >& X,
82 const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Y,
83 const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Beta,
87 Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic >
ISTA (
88 const Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic >& X, \
89 const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Y, \
90 const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Beta_0, \
91 unsigned int num_iterations, \
95 Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic > Betas;
96 Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic > old_Betas;
98 Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic > X;
99 Eigen::Matrix< T, Eigen::Dynamic, 1 > Y;
102 const unsigned int M = 100;
109 unsigned int statsIt = 1;
111 unsigned int n = 0, p = 0;
113 std::vector< T > lambda_grid;
115 unsigned int loop_index = 0;
119 template<
typename T >
129 FOS< T >::FOS(Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> x, Eigen::Matrix<T, Eigen::Dynamic, 1 > y ) : X( x ), Y( y ) {
130 static_assert(std::is_floating_point< T >::value,
"FOS can only be used with floating point types.");
133 template <
typename T >
138 template <
typename T >
143 template <
typename T >
148 template <
typename T >
153 template <
typename T >
156 T C_t =
static_cast<T
>( C );
157 T n_t =
static_cast<T
>( X.rows() );
165 template <
typename T >
166 T compute_lp_norm( T& matrix,
int norm_type ) {
167 return matrix.template lpNorm< norm_type >();
170 template <
typename T >
171 T compute_sqr_norm( T& matrix ) {
172 return matrix.squaredNorm();
177 template <
typename T >
187 unsigned int stats_it,
189 const std::vector<T> &lambdas,
190 const Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic >& X,
191 const Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic >& Betas ) {
193 bool stats_cond =
true;
195 for (
unsigned int i = 1; i <= stats_it; i++ ) {
197 Eigen::Matrix< T, Eigen::Dynamic, 1 > beta_k = Betas.col( i - 1 );
198 T rk = lambdas.at( i - 1 );
200 Eigen::Matrix< T, Eigen::Dynamic, 1 > beta_diff = Betas.col( stats_it - 1 );
202 T abs_max_betas = beta_diff.cwiseAbs().maxCoeff();
204 T n =
static_cast<T
>( X.rows() );
206 T check_parameter = n*abs_max_betas / ( r_stats_it + rk );
208 stats_cond &= ( check_parameter <= C );
215 template <
typename T >
221 const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Y,
224 T rMax = 2.0*( X.transpose() * Y ).
template lpNorm< Eigen::Infinity >();
231 template <
typename T >
244 T n_f =
static_cast<T
>( n );
249 template <
typename T >
251 const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Y, \
252 const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Beta, \
255 Eigen::Matrix< T, Eigen::Dynamic, 1 > error = Y - X*Beta;
256 T f_beta = error.squaredNorm() + r_stats_it*Beta.template lpNorm < 1 >();
262 template <
typename T >
264 const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Y, \
265 const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Beta, \
269 T s_chunk = r_stats_it / ( 2.0*X.transpose()*( X*Beta - Y ) ).template lpNorm< Eigen::Infinity >();
270 T s_chunk_prime = ( -
static_cast<T
>( Y.transpose()*( X*Beta - Y ) ) )/( Y - X*Beta ).squaredNorm();
271 T s = std::min( std::max( - s_chunk, s_chunk_prime ), s_chunk );
274 Eigen::Matrix< T, Eigen::Dynamic, 1 > nu_tilde = 2.0*s/r_stats_it*( X*Beta - Y );
276 T d_nu =
square( r_stats_it )/4.0*( nu_tilde + 2.0/r_stats_it*Y ).squaredNorm() - Y.squaredNorm();
281 template <
typename T >
283 const Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic >& X,
284 const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Y,
285 const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Beta ) {
287 return (X*Beta - Y).squaredNorm();
291 template <
typename T >
293 const Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic >& X,
294 const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Y,
295 const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Beta,
296 const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Beta_prime,
299 Eigen::Matrix< T, Eigen::Dynamic, 1 > f_beta = X*Beta_prime - Y;
300 T taylor_term_0 = f_beta.squaredNorm();
302 Eigen::Matrix< T, Eigen::Dynamic, 1 > f_grad = 2.0*X.transpose()*( f_beta );
303 Eigen::Matrix< T, Eigen::Dynamic, 1 > beta_diff = ( Beta - Beta_prime );
305 T taylor_term_1 = f_grad.transpose()*beta_diff;
307 T taylor_term_2 = L/2.0*beta_diff.squaredNorm();
309 return taylor_term_0 + taylor_term_1 + taylor_term_2;
312 template <
typename T >
314 const Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic >& X,
315 const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Y,
316 const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Beta,
320 Eigen::Matrix< T, Eigen::Dynamic, 1 > f_grad = 2.0*( X.transpose()*( X*Beta - Y ) );
321 Eigen::Matrix< T, Eigen::Dynamic, 1 > beta_to_modify = Beta - (1.0/L)*f_grad;
323 return beta_to_modify.unaryExpr(
SoftThres<T>( thres/L ) );
327 template <
typename T >
328 Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic >
FOS<T>::ISTA (
329 const Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic >& X, \
330 const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Y, \
331 const Eigen::Matrix< T, Eigen::Dynamic, 1 >& Beta_0, \
332 unsigned int num_iterations, \
339 Eigen::Matrix< T, Eigen::Dynamic, 1 > Beta = Beta_0;
341 for(
unsigned int i = 0; i < num_iterations; i++ ) {
343 unsigned int counter = 0;
345 Eigen::Matrix< T, Eigen::Dynamic, 1 > Beta_temp = update_beta_ista( X, Y, Beta, L, lambda );
350 while( ( f_beta( X, Y, Beta_temp ) > f_beta_tilda( X, Y, Beta_temp, Beta, L ) ) ) {
355 Beta_temp = update_beta_ista( X, Y, Beta, L, lambda );
359 Beta = update_beta_ista( X, Y, Beta, L, lambda );
369 template<
typename T >
382 lambda_grid = GenerateLambdaGrid( X, Y, M );
384 bool statsCont =
true;
385 unsigned int statsIt = 1;
387 Betas = Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic >::Zero( X.cols(), M );
391 while( statsCont && ( statsIt < M ) ) {
397 old_Betas = Betas.col( statsIt - 2 );
398 T rStatsIt = lambda_grid.at( statsIt - 1 );
406 T duality_gap = primal_objective( X, Y, old_Betas, rStatsIt ) + dual_objective( X, Y, old_Betas, rStatsIt );
409 unsigned int n =
static_cast< unsigned int >( X.rows() );
410 T gap_target = duality_gap_target( gamma, C, rStatsIt, n );
412 DEBUG_PRINT(
"Duality gap is " << duality_gap <<
" gap target is " << gap_target );
415 if( duality_gap <= gap_target ) {
417 DEBUG_PRINT(
"Duality gap is below specified threshold, exiting inner loop." );
418 Betas.col( statsIt - 1 ) = old_Betas;
426 Betas.col( statsIt - 1 ) =
ISTA( X, Y, old_Betas, 1, L_k_less_1, rStatsIt );
427 old_Betas = Betas.col( statsIt - 1 );
433 statsCont = ComputeStatsCond( C, statsIt, rStatsIt, lambda_grid, X, Betas );
436 avfos_fit = Betas.col( statsIt - 2 );
437 lambda = lambda_grid.at( statsIt - 2 );
438 optim_index = statsIt;
440 std::cout <<
"Stopping Index: " << optim_index << std::endl;
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.
void Algorithm()
Run the main FOS algorithm.
std::vector< T > LogScaleVector(T lower_bound, T upper_bound, unsigned int num_elements)
Generate a vector of logarithmically equally spaced points.
Soft Threshold functor used to apply hdim::soft_threshold to each element in a matrix or vector...
#define DEBUG_PRINT(x,...)
T square(T &val)
Compute the square of a value.
Run the Iterative Shrinking and Thresholding Algorthim.
FOS(Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic > x, Eigen::Matrix< T, Eigen::Dynamic, 1 > y)
Initialize a new algorithm, and instantiate member attributes X and Y.