#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <mex.h>
#include <math.h>
#include "matrix.h"

#include "flsa.h"


/*

  Functions contained in "flsa.h"

1. The algorithm for sloving (1) with a given (labmda1, lambda2)
 
  void flsa(double *x, double *z, double *info,
		  double * v, double *z0, 
		  double lambda1, double lambda2, int n, 
		  int maxStep, double tol, int tau, int flag)
*/


/*

  We solve the Fused Lasso Signal Approximator (FLSA) problem:

     min_x  1/2 \|x-v\|^2  + lambda1 * \|x\|_1 + lambda2 * \|A x\|_1,      (1)

  It can be shown that, if x* is the solution to

     min_x  1/2 \|x-v\|^2  + lambda2 \|A x\|_1,                            (2)

  then 
     x**= sgn(x*) max(|x*|-lambda_1, 0)                                    (3)

  is the solution to (1).

  By some derivation (see the description in sfa.h), (2) can be solved by

     x*= v - A^T z*,

  where z* is the optimal solution to

     min_z  1/2  z^T A AT z - < z, A v>,
		subject to  \|z\|_{infty} \leq lambda2                             (4)
*/



/*


  In flsa, we solve (1) corresponding to a given (lambda1, lambda2)

  void flsa(double *x, double *z, double *gap,
		  double * v, double *z0, 
		  double lambda1, double lambda2, int n, 
		  int maxStep, double tol, int flag)

  Output parameters:
      x:        the solution to problem (1)
	  z:        the solution to problem (4)
	  infor:    the information about running the subgradient finding algorithm
	                 infor[0] = gap:         the computed gap (either the duality gap
	                                            or the summation of the absolute change of the adjacent solutions)
					 infor[1] = steps:       the number of iterations
					 infor[2] = lambad2_max: the maximal value of lambda2_max
					 infor[3] = numS:        the number of elements in the support set
								
  Input parameters:
      v:        the input vector to be projected
	  z0:       a guess of the solution of z

	  lambad1:  the regularization parameter
	  labmda2:  the regularization parameter
	  n:        the length of v and x

      maxStep:  the maximal allowed iteration steps
	  tol:      the tolerance parameter
	  flag:     the flag for initialization and deciding calling sfa
                     switch (flag)
					     >0: sfa
						 <0: sfa_ls

                     switch ( abs(flag))
					     case 1, 2, 3, or 4: 
						               z0 is a "good" starting point 
						               (such as the warm-start of the previous solution,
									   or the user want to test the performance of this starting point;
									   the starting point shall be further projected to the L_{infty} ball,
									   to make sure that it is feasible)

						 case 11, 12, 13, or 14: z0 is a "random" guess, and thus not used
						               (we shall initialize z with zero if lambda2 is less than 0.5 *zMax
									         and otherwise initialize z with zero with the solution of the linear system;
											 this solution is projected to the L_{infty} ball)

*/


/*

We write the wrapper for calling from Matlab

void flsa(double *x, double *z, double *gap,
		  double * v, double *z0, 
		  double lambda1, double lambda2, int n, 
		  int maxStep, double tol, int flag)
*/


void mexFunction (int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
{
    /*set up input arguments */
    double* v=            mxGetPr(prhs[0]);
	double* z0=           mxGetPr(prhs[1]);

	double lambda1=       mxGetScalar(prhs[2]);
	double lambda2=       mxGetScalar(prhs[3]);
    int     n=   (int )   mxGetScalar(prhs[4]);

	int    maxStep= (int) mxGetScalar(prhs[5]);
	double tol=           mxGetScalar(prhs[6]);
	int    tau=     (int) mxGetScalar(prhs[7]);
	int    flag= (int)    mxGetScalar(prhs[8]);
	
    
    double *x, *z, *infor;
    /* set up output arguments */
    plhs[0] = mxCreateDoubleMatrix( n, 1, mxREAL); 	
    plhs[1] = mxCreateDoubleMatrix( n-1, 1, mxREAL); 
	plhs[2] = mxCreateDoubleMatrix( 1, 4, mxREAL);
    x=  mxGetPr(plhs[0]);
	z=  mxGetPr(plhs[1]);
	infor=mxGetPr(plhs[2]);

	flsa(x, z, infor,
		  v, z0, 
		  lambda1, lambda2, n, 
		  maxStep, tol, tau, flag);
}

