#ifdef HAVE_PETSC
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <math.h>

#include <mpi.h>
#include <petsc.h>

#include "common_c.h"
#include "FCMangle.h"

#define fillsparsecpetscs FortranCInterface_GLOBAL_(fillsparsecpetscs, FILLSPARSECPETSCS)
#define fillsparsecpetscc FortranCInterface_GLOBAL_(fillsparsecpetscc, FILLSPARSECPETSCC)

#define COLMAJ2D(row,col,numrow) (row-1)+(col-1)*numrow
#define COLMAJ3D(a,b,c,amax,bmax,cmax) (a-1)+amax*((b-1)+bmax*(c-1))
#define ROWMAJ2D_ONE(row,col,numcol) (row-1)*numcol+(col-1)
typedef long long int gcorp_t;

void fillsparsecpetscs(gcorp_t* ieng, double* EGmass, Mat* lhsP)
{
        int npro = propar.npro;
        int nshl = shpdat.nshl;
        double* mb = (double*) malloc(sizeof(double)*nshl*nshl); //block to insert
        int e,i,j,aa; //following along with fillsparse.f
        PetscInt* locat = (PetscInt*) malloc(sizeof(PetscInt)*nshl);
        for(e=0;e<npro;e++)
        {
         for(aa=0;aa<nshl;aa++) locat[aa]=ieng[e+npro*aa]-1;
//         for(aa=0;aa<nshl;aa++) assert(locat[aa]>=0);
         for (i=0; i<nshl; i++)  {   // fill up Ke with respective egmass
           for (j=0; j<nshl; j++)  {
            mb[nshl*i + j] = EGmass[e + npro*(i + nshl*j)];
           }
         }
         //MatSetValuesBlocked(*lhsP, nshl , locat, nshl, locat, mb, ADD_VALUES);
         PetscInt petsc_nshl;
         petsc_nshl = (PetscInt) nshl;
         MatSetValues(*lhsP, petsc_nshl , locat, petsc_nshl, locat, mb, ADD_VALUES);
        }
        free(mb);
	free(locat);
}
void fillsparsecpetscc(gcorp_t* ieng, double* EGmass, Mat* lhsP)
{
        int npro = propar.npro;
        int nshl = shpdat.nshl;
        int nedof = conpar.nedof;
        double* mb = (double*) malloc(sizeof(double)*nedof*nedof); //block to insert
        int e,i,j,aa; //following along with fillsparse.f
        //int* locat = (int*) malloc(sizeof(int)*nshl);
        PetscInt* locat = (PetscInt*) malloc(sizeof(PetscInt)*nshl);
        for(e=0;e<npro;e++)
        {
         for(aa=0;aa<nshl;aa++) locat[aa]=ieng[e+npro*aa]-1;
//         for(aa=0;aa<nshl;aa++) assert(locat[aa]>=0);
         for (i=0; i<nedof; i++)  {   /* fill up Ke with respective egmass */
           for (j=0; j<nedof; j++)  {
            mb[nedof*i + j] = EGmass[e + npro*(i + nedof*j)];
           }
         }
         //MatSetValuesBlocked(*lhsP, nshl , locat, nshl, locat, mb, ADD_VALUES);
         PetscInt petsc_nshl;
         petsc_nshl = (PetscInt) nshl;
         MatSetValuesBlocked(*lhsP, petsc_nshl , locat, petsc_nshl, locat, mb, ADD_VALUES);
        }
        free(mb);
	free(locat);
}
#endif


#include <math.h>
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <gsl/gsl_math.h>
#include <gsl/gsl_blas.h>
#include <gsl/gsl_vector.h>
#include <gsl/gsl_matrix.h>
#include <gsl/gsl_multimin.h>
#include <gsl/gsl_sf.h>
#include <gsl/gsl_randist.h>
#include <gsl/gsl_cdf.h>
#include <gsl/gsl_linalg.h>
#include <getopt.h>
#include <string.h>

/******************************************************************************/
#define H 0.5
#define maxnd 2000

#define neutral 0
#define selected 1
#define max_n_int_evaluated 1000
#define max_n_s_evaluated 2000

#define undefined -99999999999.99
#define undefined_int 999999
#define max_str_len 100
#define n_decimal_places 6
#define max_s_ranges 100

#define s_evaluated_vec_file_const "s_evaluated.dat"
#define t2_evaluated_vec_file_const "t2_evaluated.dat"
#define n2_evaluated_vec_file_const "n2_evaluated.dat"
#define s_range_file_const "s_ranges_evaluated.dat"
#define phase_1_dir_const "n1_n2_t2_s_vec_dir"
#define phase_2_dir_const "n2_t2_s_vec_dir"
#define const_pop_file "control_generate_allele_distrib_n1.out.bin"
/******************************************************************************/
/*Function List*/
double compute_weighted_average(double *weighted_vec, double *phase1_mut_vec,
				double *phase2_mut_vec, int n1d, int n2d);
float assign_float_from_read_buff(char *buffer, int start);
int get_average_egf_vecs_1_and_2(double s,int n1, int n2, double t2_real,
				 int t2_lower, int t2_upper, double *egf_vec, char *buffer_p1_n2_t2_lower,
				 char *buffer_p2_n2_t2_lower, char *buffer_p1_n2_t2_upper,
				 char *buffer_p2_n2_t2_upper);
				 get_upper_lower_int(double parm, int *lower, int *upper, int n_int_evaluated, int *int_evaluated_vec);
get_upper_lower_double(double parm, double*lower, double *upper,int n_int_evaluated, double *double_evaluated_vec);
get_s_ranges();
get_int_evaluated_vec(int *int_evaluated_vec, int *n_int_evaluated,
		      int *int_lower, int *int_step, char *int_evaluated_vec_file);
scale_vector(double *vec, int n2, double total_density_s0);
int get_binary_egf_vec(char *buffer, int n, int t2, double s, double *egf_vec);

fold_vector_double(double *vec, int counter);
fold_vector_int(int *vec, int counter);

int nearest_n2_ind(int n2_real);
read_phase1_phase2_file_into_buffer(int n1, int phase, int n2, int t2, char *buffer,
				    int file_size_bytes);
read_const_pop_file_into_buffer(int n1, char *buffer, int file_size_bytes);
compute_weighted_average_egf_vec(double t2_real, int t2_lower, int t2_upper,
				 double *egf_vec_lower, double *egf_vec_upper,
				 double *egf_vec, int n2d);
double compute_weighted_average(double *weighted_vec, double *phase1_mut_vec,
				double *phase2_mut_vec, int n1d, int n2d);
int get_const_pop_egf_vec(double s, int n1, double *egf_vec, char *buffer_const_pop,
			  int assign_tds0_mode);
assign_int_from_read_buff(int *res, char *buffer, int start);
float assign_float_from_read_buff(char *buffer, int start);
int compute_s_tab_num(double s);
int compute_file_size_bytes(int n);
set_up_file_name(int n1, char *froot, char *file_name);
get_data_path(char *data_path);
get_s_evaluated_vec(double *s_evaluated_vec, int *n_s_evaluated,
   int *n_s_evaluated_file, char *s_evaluated_vec_file);
get_lower_upper(int ind, double *s_evaluated_vec, int n_s_evaluated,
   double *lower, double *upper);
dumpvector(double *v, int min, int max, char *s);
dumpmatrix(double **m, int s1,
        int rows, int s2, int cols, char *s);
double selfn(double q, double s, double h);
setuprow(double **a, double p, int row, int n);
setupmatrix(double **a, int n1, int n2, double s, double h);
matrixinvert(int N, double **a,double *inverter);
tmiterate(double **a,double *mut1,
        int t, int n1, int n2,int decay,double *sumf);
tmiterate2(double **a,double *mut1,
        int t, int n1, int n2,int decay,double **a1);
eqf_using_matrix_inversion(int n1,double s,double **a,double *egf_out);
vector_average(int n1,int n2,double *fv1,double *fv2, double *fv_out);
vector_s_average(int n,double P1,double *fv1,double *fv2, double *fv_out);

output_sfs_to_file_thanasis_format(int n, int *sfs1,int *sfs2,char *sfs_filename);
output_sfs_to_file_peter_format(int n,int sample1, int sample2, int *sfs1,int *sfs2,char *sfs_filename);
get_sfs(int alleles,int *par,char *sfs_filename);

get_sfs_peter1(int *total_neu,int *total_sel,int *nalleles,int *sfs_sel,int *sfs_neu,char *sfs_filename);
get_sfs_peter2(int *total_neu,int *total_sel,int *nalleles,int *sfs_sel,int *sfs_neu,char *sfs_filename,int *sel_sites,int *sel_diff,int *neu_sites,int *neu_diff);

int binarysearchcumulative_from_zero(double *array, int size);
double randomly_select_allele_frequency(double *egf_vec, double *temp1, int nd);
set_up_cumulative_allele_freq_vec(int nd, double *egf_vec, double *cum_vec,
				  char *str);
generate_simulated_data(double *egf_vec, int nsites, int sample_size, int nd,
			int *sfs);

egf_scaling_s(int n1,double f0,double *v_s_in, double *v_s_out);
egf_scaling_f0(int n1,double f0,double *fv);
egf_scaling(int N,double f0,double *FV0,double *FVS);
binomial_sampling(int n1,int alleles,int sample, double *invy,int *discrete);

int set_up_density_vec_equal_effects(double s, int n_s_evaluated, double *gamma_density_vec);
int set_up_density_vec_step_effects(double alpha, double beta, int n_s_evaluated, double *gamma_density_vec);
double compute_beta_densities(double alpha, double *s_evaluated_vec,
			      int n_s_evaluated, double *gamma_density_vec, double beta);
double compute_gamma_densities(double alpha, double *s_evaluated_vec,
				int n_s_evaluated, double *gamma_density_vec, double beta);

double calculate_ne(int n1,int n2,int t);
/******************************************************************************/
/*Structure List*/
struct rangestruct
{
  double s_lower, s_upper, s_step;
  int s_lower_index;
};

struct rangestruct s_ranges[max_s_ranges+1];
/******************************************************************************/
/*Global variable List*/
double allele_freq_sampled[maxnd+1];
double total_density_s0;
char s_evaluated_vec_file[max_str_len], t2_evaluated_vec_file[max_str_len],
  n2_evaluated_vec_file[max_str_len], s_range_file[max_str_len],
  phase_1_dir[max_str_len], phase_2_dir[max_str_len],
  const_pop_dir[max_str_len];
char data_path[max_str_len], file_label_str[max_str_len];
int nranges, trace_level, n_sfs;
int n_s_evaluated, n_s_evaluated_file, gss_n2;
int t2_evaluated_vec[max_n_int_evaluated], n_t2_evaluated, t2_lower;
int t2_step, verbose_mode, neutrals_only_mode;
int n2_evaluated_vec[max_n_int_evaluated], n_n2_evaluated, n2_lower;
double s_evaluated_vec[max_n_s_evaluated];
/******************************************************************************/


/* Copyright (c) 2014, Giuseppe Argentieri <giuseppe.argentieri@ts.infn.it>

 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include "funcs.h"
#include "initial.h"

#include <stdio.h>
#include <gsl/gsl_math.h>
#include <gsl/gsl_linalg.h>
#include <gsl/gsl_odeiv2.h>
#include <gsl/gsl_ieee_utils.h>

int main ( int argc, char* argv[] )
{
	gsl_ieee_env_setup () ;			/* read GSL_IEEE_MODE */

	printf("Temperature: %g\n\n", T*HBAR*Delta/BOLTZ) ;

	double beta = 1.0/T ;           	/* Boltzmann factor: beta */
	double omega_1 = gsl_hypot(OMEGA,D) ;   /* omega' */

	struct f_params params;
	params.omega_c = omega_c ;
	params.beta = beta ;
	params.Omega = OMEGA ;
	params.omega_1 = omega_1 ;
	params.alpha = alpha ;

	int status1 = save_integrals ( &params ) ;
	int status2 = save_matrices ( &params ) ;

	/* read the Redfield matrix from a file */
	gsl_matrix* red_m = gsl_matrix_calloc ( 4, 4 ) ;
	int status3 = mat_read ( red_m, "REDFIELD_MATRIX" ) ;

	/* read the CP matrix from a file */
	gsl_matrix* cp_m = gsl_matrix_calloc ( 4, 4 ) ;
	int status4 = mat_read ( cp_m, "CP_MATRIX" ) ;

	/* Hamiltonian generator */
	const double om[] = { 0 , 0 , 0 , omega_1/2 } ;
	gsl_matrix* H = gsl_matrix_calloc ( 4, 4 ) ;
	int status5 = ham_gen ( H, om ) ;

	/*
	 * Find the stationary state by solving the linear systems
	 * and the associated stationary currents
	 */
	gsl_vector* req_red = gsl_vector_calloc (4) ;
	gsl_vector* req_cp = gsl_vector_calloc (4) ;

	printf("REDFIELD DYNAMICS\n") ;
	int status6 = stationary ( red_m , req_red ) ;
	printf("Stationary state: ( %.1f , %.9f , %.9f , %.9f )\n",
			VECTOR(req_red,0), VECTOR(req_red,1),
			VECTOR(req_red,2), VECTOR(req_red,3) ) ;
	printf("Stationary normalized (I/I0) DC current: %.9f\n\n",
			-VECTOR(req_red,3)*OMEGA/omega_1) ;

	printf("CP DYNAMICS\n") ;
	int status7 = stationary ( cp_m , req_cp ) ;
	printf("Stationary state: ( %.1f , %.9f , %.9f , %.9f )\n",
			VECTOR(req_cp,0), VECTOR(req_cp,1),
			VECTOR(req_cp,2), VECTOR(req_cp,3) ) ;
	printf("Stationary normalized (I/I0) DC current: %.9f\n\n",
			-VECTOR(req_cp,3)*OMEGA/omega_1) ;

	/* Save the stationary states into files */
	FILE* f = fopen ( "RED_STATIONARY.dat", "w" ) ;
	gsl_vector_fprintf ( f, req_red, "%.9f" ) ;
	FILE* g = fopen ( "CP_STATIONARY.dat", "w" ) ;
	gsl_vector_fprintf ( g, req_cp, "%.9f" ) ;

	fclose (f) ; fclose (g) ;

	/* polarization */
	double D30 = gsl_matrix_get(cp_m,3,0) ;
	double D33 = gsl_matrix_get(cp_m,3,3) ;
	double pol = -D30/D33 ;
	printf("n-Polarization of the CP dynamics -D30/D33: %.9f\n", pol ) ;

	/* polarization through the formula (for checking) */
	double P = polarization ( &params, omega_c ) ;
	printf("\n") ;
	printf("n-Polarization through the given formula: %.9f\n", P ) ;
	printf("Stationary normalized (I/I0) DC current: %.9f\n", -P*OMEGA/omega_1 ) ;

	/* free memory for matrices */
	gsl_matrix_free(red_m) ;
 	gsl_matrix_free(cp_m) ;

	return status1 + status2 + status3 + status4 + status5 + status6 + status7 ;
}


/* sys/infnan.c
 *
 * Copyright (C) 2001, 2004, 2007, 2010 Brian Gough
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#include <config.h>
#include <math.h>

#if HAVE_IEEEFP_H
#include <ieeefp.h>
#endif

#include <gsl/gsl_sys.h>

double gsl_nan (void)
{
  return gsl_fdiv (0.0, 0.0);
}

double gsl_posinf (void)
{
  return gsl_fdiv (+1.0, 0.0);
}

double gsl_neginf (void)
{
  return gsl_fdiv (-1.0, 0.0);
}

int gsl_isnan (const double x);
int gsl_isinf (const double x);
int gsl_finite (const double x);

#if defined(_MSC_VER) /* Microsoft Visual C++ */
#include <float.h>
int
gsl_isnan (const double x)
{
  return _isnan(x);
}

int
gsl_isinf (const double x)
{
  int fpc = _fpclass(x);

  if (fpc == _FPCLASS_PINF)
    return +1;
  else if (fpc == _FPCLASS_NINF)
    return -1;
  else
    return 0;
}

int
gsl_finite (const double x)
{
  return _finite(x);
}
#else

# if HAVE_DECL_ISFINITE
int
gsl_finite (const double x)
{
  return isfinite(x);
}
# elif HAVE_DECL_FINITE
int
gsl_finite (const double x)
{
  return finite(x);
}
# elif HAVE_IEEE_COMPARISONS
int
gsl_finite (const double x)
{
  const double y = x - x;
  int status = (y == y);
  return status;
}
# else
# error "cannot define gsl_finite without HAVE_DECL_FINITE or HAVE_IEEE_COMPARISONS"
# endif

# if HAVE_DECL_ISNAN
int
gsl_isnan (const double x)
{
  return isnan(x);
}
#elif HAVE_IEEE_COMPARISONS
int
gsl_isnan (const double x)
{
  int status = (x != x);
  return status;
}
# else
# error "cannot define gsl_isnan without HAVE_DECL_ISNAN or HAVE_IEEE_COMPARISONS"
# endif

# if HAVE_DECL_ISINF
int
gsl_isinf (const double x)
{
  /* isinf(3): In glibc 2.01 and earlier, isinf() returns a
     non-zero value (actually: 1) if x is an infinity (positive or
     negative).  (This is all that C99 requires.) */

  if (isinf(x))
    {
      return (x > 0) ? 1 : -1;
    }
  else
    {
      return 0;
    }
}
# else

int
gsl_isinf (const double x)
{
  if (! gsl_finite(x) && ! gsl_isnan(x))
    {
      return (x > 0 ? +1 : -1);
    }
  else
    {
      return 0;
    }
}

# endif
#endif


#include <jni.h>
#include <assert.h>
#include <lapacke.h>

/* LU */

JNIEXPORT jint Java_JAMAJni_LUDecomposition_dgetrf (JNIEnv *env, jclass klass, jint matrix_layout, jint m, jint n, jdoubleArray a, jint lda, jintArray ipiv){

    double *aElems;
    lapack_int *ipivElems;
    int info;

    aElems = (*env)-> GetDoubleArrayElements (env, a, NULL);
    ipivElems = (*env)-> GetIntArrayElements (env, ipiv, NULL);

    assert(aElems && ipivElems);

    info = LAPACKE_dgetrf ((int) matrix_layout, (lapack_int) m, (lapack_int) n, aElems, (lapack_int) lda, ipivElems);

    (*env)-> ReleaseDoubleArrayElements (env, a, aElems, 0);
    (*env)-> ReleaseIntArrayElements (env, ipiv, ipivElems, 0);

    return info;
}

JNIEXPORT jint Java_JAMAJni_LUDecomposition_dgetrs (JNIEnv *env, jclass klass, jint matrix_layout, jchar trans, jint n, jint nrhs, jdoubleArray a, jint lda, jintArray ipiv, jdoubleArray b, jint ldb){

    double *bElems;
    double *aElems;
    lapack_int *ipivElems;
    int info;

    aElems = (*env)-> GetDoubleArrayElements (env, a, NULL);
    bElems = (*env)-> GetDoubleArrayElements (env, b, NULL);
    ipivElems = (*env)-> GetIntArrayElements (env, ipiv, NULL);

    assert(aElems && bElems && ipivElems);

    info = LAPACKE_dgetrs ((int) matrix_layout, (char) trans, (lapack_int) n, (lapack_int) nrhs, aElems, (lapack_int) lda, ipivElems, bElems, (lapack_int) ldb);

    (*env)-> ReleaseDoubleArrayElements (env, a, aElems, JNI_ABORT);
    (*env)-> ReleaseDoubleArrayElements (env, b, bElems, 0);
    (*env)-> ReleaseIntArrayElements (env, ipiv, ipivElems, JNI_ABORT);

    return info;
}


#ifndef PRIMAL_DUAL_LOOPLESS_KATYUSHA0_H
#define PRIMAL_DUAL_LOOPLESS_KATYUSHA0_H

#include "Primal_Dual_LOOPLESS.h"

#include <string>
#include <gsl/gsl_rng.h>
#include <gsl/gsl_randist.h>
#include <stdio.h>      /* printf */
#include <time.h>
#include <fstream>
#include <algorithm>
#include <iomanip>
#include <ctime>
#include <sstream>

//This class implements the method loopless kATYUSHA with arbitrary sampling

/*
The optimization problem to solve is:

\sum_{i=1}^n \lambda_i\phi_i(A_i^{\top} w)+ g(w)
Assumption 1: For each i, \phi_i is 1-smooth
By default, lambda_i=1/n for all i.
*
* The dual problem is
*         g*(-sum_{i=1}^n \lambda_i \alpha_i A_i)+\sum_{i=1}^n \lambda_i \phi*_i(\alpha_i)
*/

template<typename L, typename D>
class Primal_Dual_LOOPLESS_Katyusha0: public Primal_Dual_LOOPLESS<L, D>
{

protected:
   D theta1;
   D theta2;
   D theta3;
   D eta; //the stepsize parameter alpha in the paper

   D x;
   D w;
   D y;
   D z;

   std::vector<D> primal_y;     // the y variable

   std::vector<D> primal_z;     // the z variable

   std::vector<D> primal_w;     // the w variable

public:

  virtual inline D gradient_of_phi_i(D, L){return D(NULL);}
  virtual inline D gradient_of_gstar_j(D, L){return D(NULL);}
  virtual inline D value_of_phi_i(D, L) {return D(NULL);}
  virtual inline D value_of_g_j(D, L){return D(NULL);}
  virtual inline D value_of_phistar_i(D,L) {return D(NULL);}
  virtual inline D value_of_gstar(vector<D> &){return D(NULL);}
  virtual inline D value_of_gstar_minus(vector<D> &, D){return D(NULL);}
  virtual inline D feasible_dual(vector<D> &){return D(NULL);}
  virtual inline D compute_delta_alpha(D,D,L){return D(NULL);}
  virtual inline void set_auxiliary_v(){}
  virtual inline D get_lambda1(){return D(NULL);}
  virtual inline D get_lambda2(){return D(NULL);}
  virtual inline void compute_just_in_time_prox_grad(D, D, D &, L,L, D, D &, L){}

  Primal_Dual_LOOPLESS_Katyusha0()
  : Primal_Dual_LOOPLESS<L,D>()
  {

  }

  Primal_Dual_LOOPLESS_Katyusha0(const char* matrix_file, const char* vector_file)
  : Primal_Dual_LOOPLESS<L,D>(matrix_file, vector_file)
  {

  }

  Primal_Dual_LOOPLESS_Katyusha0(const char* matrix_file)
  : Primal_Dual_LOOPLESS<L,D>(matrix_file)
  {

  }

  void set_theta(){
    theta2=this->L2/2/max(this->Lf,this->L2);
    if(this->Lf<=this->L2/this->p){
      D tmp=this->mu/this->L2/this->p;
      cout<<"this->L2="<<this->L2<<endl;
      cout<<"tmp="<<tmp<<endl;
      if(tmp>=1){
        theta1=theta2;
      }
      else{
        theta1=sqrt(tmp)*theta2;
      }
    }else
      theta1=min(sqrt(this->mu/this->Lf),this->p/2);
    theta3=1-theta1-theta2;
    eta=1./(theta1*(this->Lf+2*max(this->L2,this->Lf)));
    cout<<"this->Lf="<<this->Lf<<"; this->L2="<<this->L2<<"; theta1="<<theta1<<"; theta2="<<theta2<<"; theta3="<<theta3<<endl;
    cout<<"eta="<<eta<<endl;
  }

  inline D compute_current_xj_value(D ui, L j, L t0 , L t1)
  {
    w=primal_w[j];
    y=primal_y[j];
    z=primal_z[j];
    compute_just_in_time_prox_grad(eta, ui , z, t0, t1, w, y, j);
    x=theta1*z+theta2*w+theta3*y;
    return x;
  }

  inline void set_stepsize(){
    primal_y.clear();
    primal_z.clear();
    primal_w.clear();
    primal_y.resize(this->nfeatures,0);
    primal_z.resize(this->nfeatures,0);
    primal_w.resize(this->nfeatures,0);
    for(L j=0; j<this->nfeatures; j++){
      primal_y[j]=this->primal_x[j];
      primal_z[j]=this->primal_x[j];
      primal_w[j]=this->primal_x[j];
    }
    cout<<"w size="<<primal_w.size()<<endl;
    set_theta();
    cout<<"w 2="<<primal_w.size()<<endl;
  }

  inline void update_x(D xj,L j){
    this->primal_x[j]=xj;
    primal_z[j]=z;
    primal_y[j]=y;
  }

  inline void update_baralpha()
   {
     D yi=gsl_rng_uniform(this->rng);
     if(yi<=this->p){
         this->nb_iters+=this->nsamples/this->tau;
         D aitg=0;
         D deltaalphai=0;
         for(L i=0;i<this->nsamples;i++)
         {
           aitg=this->compute_AiTxk(i);
           deltaalphai=gradient_of_phi_i(aitg,i)-this->dual_alpha[i];
           this->dual_alpha[i]+=deltaalphai;
           for (L k = this->ptr[i]; k < this->ptr[i + 1];k++)
           {
             L j=this->row_idx[k];
             this->baralpha[j]+=this->lambda_f[i]*deltaalphai*this->A[k];
           }
         }

       for(L j=0;j<this->nfeatures;j++)
       primal_w[j]=this->primal_x[j];
     }
   }

  void loopless_Katyusha(vector<D> & x0, vector<D> & w0, string filename, vector<D> & L_phi, D val_mu, D val_epsilon, L max_nb, L nb_tau, L nb_c, L u, L p_mod, D scal_p)
  {
    filename="Katyusha"+filename;
    this->loopless( x0,  w0,  filename,  L_phi,  val_mu,  val_epsilon, max_nb, nb_tau, nb_c, u, p_mod,scal_p);
  }

  void loopless_Katyusha2(vector<D> & x0, vector<D> & w0, string filename, vector<D> & L_phi, D val_mu, D val_epsilon, L max_nb, L nb_tau, L nb_c, L u, L p_mod, D scal_p)
  {
    filename="Katyusha"+filename;
    this->loopless2( x0,  w0,  filename,  L_phi,  val_mu,  val_epsilon, max_nb, nb_tau, nb_c, u, p_mod,scal_p);
  }

  };

  #endif /* MIN_SMOOTH_CONVEX_H */


/* ode-initval/gear2.c
 *
 * Copyright (C) 1996, 1997, 1998, 1999, 2000 Gerard Jungman
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

/* Gear 2 */

/* Author:  G. Jungman
 */
#include <config.h>
#include <stdlib.h>
#include <string.h>
#include <gsl/gsl_math.h>
#include <gsl/gsl_errno.h>
#include "odeiv_util.h"
#include <gsl/gsl_odeiv.h>

/* gear2 state object */
typedef struct
{
  int primed;                   /* flag indicating that yim1 is ready */
  double t_primed;              /* system was primed for this value of t */
  double last_h;                /* last step size */
  gsl_odeiv_step *primer;       /* stepper to use for priming */
  double *yim1;                 /* y_{i-1}    */
  double *k;                    /* work space */
  double *y0;                   /* work space */
  double *y0_orig;
  double *y_onestep;
  int stutter;
}
gear2_state_t;

static void *
gear2_alloc (size_t dim)
{
  gear2_state_t *state = (gear2_state_t *) malloc (sizeof (gear2_state_t));

  if (state == 0)
    {
      GSL_ERROR_NULL ("failed to allocate space for gear2_state", GSL_ENOMEM);
    }

  state->yim1 = (double *) malloc (dim * sizeof (double));

  if (state->yim1 == 0)
    {
      free (state);
      GSL_ERROR_NULL ("failed to allocate space for yim1", GSL_ENOMEM);
    }

  state->k = (double *) malloc (dim * sizeof (double));

  if (state->k == 0)
    {
      free (state->yim1);
      free (state);
      GSL_ERROR_NULL ("failed to allocate space for k", GSL_ENOMEM);
    }

  state->y0 = (double *) malloc (dim * sizeof (double));

  if (state->y0 == 0)
    {
      free (state->k);
      free (state->yim1);
      free (state);
      GSL_ERROR_NULL ("failed to allocate space for y0", GSL_ENOMEM);
    }

  state->y0_orig = (double *) malloc (dim * sizeof (double));

  if (state->y0_orig == 0)
    {
      free (state->y0);
      free (state->k);
      free (state->yim1);
      free (state);
      GSL_ERROR_NULL ("failed to allocate space for y0_orig", GSL_ENOMEM);
    }

  state->y_onestep = (double *) malloc (dim * sizeof (double));

  if (state->y_onestep == 0)
    {
      free (state->y0_orig);
      free (state->y0);
      free (state->k);
      free (state->yim1);
      free (state);
      GSL_ERROR_NULL ("failed to allocate space for y0_orig", GSL_ENOMEM);
    }

  state->primed = 0;
  state->primer = gsl_odeiv_step_alloc (gsl_odeiv_step_rk4imp, dim);

  if (state->primer == 0)
    {
      free (state->y_onestep);
      free (state->y0_orig);
      free (state->y0);
      free (state->k);
      free (state->yim1);
      free (state);
      GSL_ERROR_NULL ("failed to allocate space for primer", GSL_ENOMEM);
    }

  state->last_h = 0.0;

  return state;
}

static int
gear2_step (double *y, gear2_state_t * state,
            const double h, const double t,
            const size_t dim, const gsl_odeiv_system * sys)
{
  /* Makes a Gear2 advance with step size h.
     y0 is the initial values of variables y.
     The implicit matrix equations to solve are:
     k = y0 + h * f(t + h, k)
     y = y0 + h * f(t + h, k)
   */

  const int iter_steps = 3;
  int nu;
  size_t i;
  double *y0 = state->y0;
  double *yim1 = state->yim1;
  double *k = state->k;

  /* Iterative solution of k = y0 + h * f(t + h, k)
     Note: This method does not check for convergence of the
     iterative solution!
   */

  for (nu = 0; nu < iter_steps; nu++)
    {
      int s = GSL_ODEIV_FN_EVAL (sys, t + h, y, k);

      if (s != GSL_SUCCESS)
        {
          return s;
        }

      for (i = 0; i < dim; i++)
        {
          y[i] = ((4.0 * y0[i] - yim1[i]) + 2.0 * h * k[i]) / 3.0;
        }
    }

  return GSL_SUCCESS;
}

static int
gear2_apply (void *vstate,
             size_t dim,
             double t,
             double h,
             double y[],
             double yerr[],
             const double dydt_in[],
             double dydt_out[], const gsl_odeiv_system * sys)
{
  gear2_state_t *state = (gear2_state_t *) vstate;

  state->stutter = 0;

  if (state->primed == 0 || t == state->t_primed || h != state->last_h)
    {
      /* Execute a single-step method to prime the process.  Note that
       * we do this if the step size changes, so frequent step size
       * changes will cause the method to stutter.
       *
       * Note that we reuse this method if the time has not changed,
       * which can occur when the adaptive driver is attempting to find
       * an appropriate step-size on its first iteration */

      int status;
      DBL_MEMCPY (state->yim1, y, dim);

      status =
        gsl_odeiv_step_apply (state->primer, t, h, y, yerr, dydt_in, dydt_out,
                              sys);

      /* Make note of step size and indicate readiness for a Gear step. */

      state->primed = 1;
      state->t_primed = t;
      state->last_h = h;
      state->stutter = 1;

      return status;
    }
  else
    {
      /* We have a previous y value in the buffer, and the step
       * sizes match, so we go ahead with the Gear step.
       */

      double *const k = state->k;
      double *const y0 = state->y0;
      double *const y0_orig = state->y0_orig;
      double *const yim1 = state->yim1;
      double *y_onestep = state->y_onestep;

      int s;
      size_t i;

      DBL_MEMCPY (y0, y, dim);

      /* iterative solution */

      if (dydt_out != NULL)
        {
          DBL_MEMCPY (k, dydt_out, dim);
        }

      /* First traverse h with one step (save to y_onestep) */

      DBL_MEMCPY (y_onestep, y, dim);

      s = gear2_step (y_onestep, state, h, t, dim, sys);

      if (s != GSL_SUCCESS)
        {
          return s;
        }

      /* Then with two steps with half step length (save to y) */

      s = gear2_step (y, state, h / 2.0, t, dim, sys);

      if (s != GSL_SUCCESS)
        {
          /* Restore original y vector */
          DBL_MEMCPY (y, y0_orig, dim);
          return s;
        }

      DBL_MEMCPY (y0, y, dim);

      s = gear2_step (y, state, h / 2.0, t + h / 2.0, dim, sys);

      if (s != GSL_SUCCESS)
        {
          /* Restore original y vector */
          DBL_MEMCPY (y, y0_orig, dim);
          return s;
        }

      /* Cleanup update */

      if (dydt_out != NULL)
        {
          s = GSL_ODEIV_FN_EVAL (sys, t + h, y, dydt_out);

          if (s != GSL_SUCCESS)
            {
              /* Restore original y vector */
              DBL_MEMCPY (y, y0_orig, dim);
              return s;
            }
        }

      /* Estimate error and update the state buffer. */

      for (i = 0; i < dim; i++)
        {
          yerr[i] = 4.0 * (y[i] - y_onestep[i]);
          yim1[i] = y0[i];
        }

      /* Make note of step size. */
      state->last_h = h;

      return 0;
    }
}

static int
gear2_reset (void *vstate, size_t dim)
{
  gear2_state_t *state = (gear2_state_t *) vstate;

  DBL_ZERO_MEMSET (state->yim1, dim);
  DBL_ZERO_MEMSET (state->k, dim);
  DBL_ZERO_MEMSET (state->y0, dim);

  state->primed = 0;
  state->last_h = 0.0;
  return GSL_SUCCESS;
}

static unsigned int
gear2_order (void *vstate)
{
  gear2_state_t *state = (gear2_state_t *) vstate;
  state = 0;                    /* prevent warnings about unused parameters */
  return 3;
}

static void
gear2_free (void *vstate)
{
  gear2_state_t *state = (gear2_state_t *) vstate;

  free (state->yim1);
  free (state->k);
  free (state->y0);
  free (state->y0_orig);
  free (state->y_onestep);
  gsl_odeiv_step_free (state->primer);

  free (state);
}

static const gsl_odeiv_step_type gear2_type = { "gear2",        /* name */
  1,                            /* can use dydt_in */
  0,                            /* gives exact dydt_out */
  &gear2_alloc,
  &gear2_apply,
  &gear2_reset,
  &gear2_order,
  &gear2_free
};

const gsl_odeiv_step_type *gsl_odeiv_step_gear2 = &gear2_type;


/* specfunc/bessel_K1.c
 *
 * Copyright (C) 1996, 1997, 1998, 1999, 2000 Gerard Jungman
 * Copyright (C) 2016 Pavel Holoborodko, Patrick Alken
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

/* Author:  G. Jungman */

#include <config.h>
#include <gsl/gsl_math.h>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_poly.h>
#include <gsl/gsl_sf_exp.h>
#include <gsl/gsl_sf_bessel.h>

#include "error.h"

#include "chebyshev.h"
#include "cheb_eval.c"

/*-*-*-*-*-*-*-*-*-*-*-* Private Section *-*-*-*-*-*-*-*-*-*-*-*/

/*
 Minimax rational approximation for [0,1), peak relative error = 1.83*GSL_DBL_EPSILON.
 Source: http://www.advanpix.com/?p=3987
*/
static double k1_poly[9] = {
  -3.0796575782920622440538935e-01,
  -8.5370719728650778045782736e-02,
  -4.6421827664715603298154971e-03,
  -1.1253607036630425931072996e-04,
  -1.5592887702110907110292728e-06,
  -1.4030163679125934402498239e-08,
  -8.8718998640336832196558868e-11,
  -4.1614323580221539328960335e-13,
  -1.5261293392975541707230366e-15
};

static double i1_poly[7] = {
  8.3333333333333325191635191e-02,
  6.9444444444467956461838830e-03,
  3.4722222211230452695165215e-04,
  1.1574075952009842696580084e-05,
  2.7555870002088181016676934e-07,
  4.9724386164128529514040614e-09
};

/*
 Chebyshev expansion for [1,8], peak relative error = 1.28*GSL_DBL_EPSILON.
 Source: Pavel Holoborodko.
*/
static double ak1_data[25] = {
  +2.07996868001418246e-01,
  +1.62581565017881476e-01,
  -5.87070423518863640e-03,
  +4.95021520115789501e-04,
  -5.78958347598556986e-05,
  +8.18614610209334726e-06,
  -1.31604832009487277e-06,
  +2.32546031520101213e-07,
  -4.42206518311557987e-08,
  +8.92163994883100361e-09,
  -1.89046270526983427e-09,
  +4.17568808108504702e-10,
  -9.55912361791375794e-11,
  +2.25769353153867758e-11,
  -5.48128000211158482e-12,
  +1.36386122546441926e-12,
  -3.46936690565986409e-13,
  +9.00354564415705942e-14,
  -2.37950577776254432e-14,
  +6.39447503964025336e-15,
  -1.74498363492322044e-15,
  +4.82994547989290473e-16,
  -1.35460927805445606e-16,
  +3.84604274446777234e-17,
  -1.10456856122581316e-17
};

static cheb_series ak1_cs = {
  ak1_data,
  24,
  -1, 1,
  9
};

/*
 Chebyshev expansion for [8,inf), peak relative error = 1.25*GSL_DBL_EPSILON.
 Source: SLATEC/dbsk1e.f
*/
static double ak12_data[14] = {
  +.637930834373900104E-1,
  +.283288781304972094E-1,
  -.247537067390525035E-3,
  +.577197245160724882E-5,
  -.206893921953654830E-6,
  +.973998344138180418E-8,
  -.558533614038062498E-9,
  +.373299663404618524E-10,
  -.282505196102322545E-11,
  +.237201900248414417E-12,
  -.217667738799175398E-13,
  +.215791416161603245E-14,
  -.229019693071826928E-15,
  +.258288572982327496E-16
};

static cheb_series ak12_cs = {
  ak12_data,
  13,
  -1, 1,
  7
};

/*-*-*-*-*-*-*-*-*-*-*-* Functions with Error Codes *-*-*-*-*-*-*-*-*-*-*-*/

int gsl_sf_bessel_K1_scaled_e(const double x, gsl_sf_result * result)
{
  /* CHECK_POINTER(result) */

  if(x <= 0.0) {
    DOMAIN_ERROR(result);
  }
  else if(x < 2.0*GSL_DBL_MIN) {
    OVERFLOW_ERROR(result);
  }
  else if(x < 1.0) {
    const double lx = log(x);
    const double ex = exp(x);
    const double x2 = x*x;
    const double t  = 0.25*x2;
    const double i1 = 0.5 * x * (1.0 + t * (0.5 + t * gsl_poly_eval(i1_poly,6,t)));
    result->val  = ex * (x2 * gsl_poly_eval(k1_poly,9,x2) + x * lx * i1 + 1) / x;
    result->err  = ex * (1.6+fabs(lx)*0.6) * GSL_DBL_EPSILON;
    result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);
    return GSL_SUCCESS;
  }
  else if(x <= 8.0) {
    const double sx = sqrt(x);
    gsl_sf_result c;
    cheb_eval_e(&ak1_cs, (16.0/x-9.0)/7.0, &c);
    result->val  = (1.375 + c.val) / sx; /* 1.375 = 11/8 */
    result->err  = c.err / sx;
    result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);
    return GSL_SUCCESS;
  }
  else {
    const double sx = sqrt(x);
    gsl_sf_result c;
    cheb_eval_e(&ak12_cs, 16.0/x-1.0, &c);
    result->val  = (1.25 + c.val) / sx;
    result->err  = c.err / sx;
    result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);
    return GSL_SUCCESS;
  }
}

int gsl_sf_bessel_K1_e(const double x, gsl_sf_result * result)
{
  /* CHECK_POINTER(result) */

  if(x <= 0.0) {
    DOMAIN_ERROR(result);
  }
  else if(x < 2.0*GSL_DBL_MIN) {
    OVERFLOW_ERROR(result);
  }
  else if(x < 1.0) {
    const double lx = log(x);
    const double x2 = x*x;
    const double t  = 0.25*x2;
    const double i1 = 0.5 * x * (1.0 + t * (0.5 + t * gsl_poly_eval(i1_poly,6,t)));
    result->val  = (x2 * gsl_poly_eval(k1_poly,9,x2) + x * lx * i1 + 1) / x;
    result->err  = (1.6+fabs(lx)*0.6) * GSL_DBL_EPSILON;
    result->err += 2.0 * GSL_DBL_EPSILON * fabs(result->val);
    return GSL_SUCCESS;
  }
  else {
    gsl_sf_result K1_scaled;
    int stat_K1 = gsl_sf_bessel_K1_scaled_e(x, &K1_scaled);
    int stat_e  = gsl_sf_exp_mult_err_e(-x, 0.0,
                                           K1_scaled.val, K1_scaled.err,
                                           result);
    result->err = fabs(result->val) * (GSL_DBL_EPSILON*fabs(x) + K1_scaled.err/K1_scaled.val);
    return GSL_ERROR_SELECT_2(stat_e, stat_K1);
  }
}

/*-*-*-*-*-*-*-*-*-* Functions w/ Natural Prototypes *-*-*-*-*-*-*-*-*-*-*/

#include "eval.h"

double gsl_sf_bessel_K1_scaled(const double x)
{
  EVAL_RESULT(gsl_sf_bessel_K1_scaled_e(x, &result));
}

double gsl_sf_bessel_K1(const double x)
{
  EVAL_RESULT(gsl_sf_bessel_K1_e(x, &result));
}


/* integration/rational.c
 *
 * Copyright (C) 2017 Konrad Griessinger, Patrick Alken
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

/*
 * The code in this module is based on IQPACK, specifically the LGPL
 * implementation found in HERMITE_RULE:
 * https://people.sc.fsu.edu/~jburkardt/c_src/hermite_rule/hermite_rule.html
 */

#include <stdio.h>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_math.h>
#include <gsl/gsl_integration.h>
#include <gsl/gsl_sf_gamma.h>

static int
rational_check(const size_t n, const gsl_integration_fixed_params * params)
{
  if (fabs(params->b - params->a) <= GSL_DBL_EPSILON)
    {
      GSL_ERROR("|b - a| too small", GSL_EDOM);
    }
  else if (params->alpha <= -1.0)
    {
      GSL_ERROR("alpha must be > -1", GSL_EDOM);
    }
  else if (params->beta >= 0.0 || params->alpha+params->beta+2*n >= 0.0 || 0.0 >= params->alpha+2*n)
    {
      GSL_ERROR("beta < alpha + beta + 2n < 0 is required", GSL_EDOM);
    }
  else if (params->a + params->b <= 0.0)
    {
      GSL_ERROR("a + b <= 0 is not allowed", GSL_EDOM);
    }
  else
    {
      return GSL_SUCCESS;
    }
}

static int
rational_init(const size_t n, double * diag, double * subdiag, gsl_integration_fixed_params * params)
{
  const double absum = params->beta + params->alpha;
  const double a1 = params->alpha + 1.0;
  const double aba1 = absum*a1;
  double ab2i = absum + 2.0;
  size_t i;

  /* construct the diagonal and subdiagonal elements of Jacobi matrix */

  diag[0] = -a1/(absum + 2.0);
  subdiag[0] = sqrt( -diag[0] * ( params->beta + 1.0 ) / ( (absum + 2.0)*(absum + 3.0) ) );

  for (i = 1; i < n-1; i++)
    {
      ab2i += 2.0;
      diag[i] = ( -aba1 - 2.0 * i * ( absum + i + 1.0 ) ) / ( ab2i * ( ab2i - 2.0 ) );
      subdiag[i] = sqrt( (i+1.0) * ( params->alpha + i + 1.0 ) / ( ab2i - 1.0 ) * ( params->beta + i + 1.0 ) / ( ab2i * ab2i ) * ( absum + i + 1.0 ) / ( ab2i + 1.0 ) );
    }

  diag[n-1] = ( -aba1 - 2.0 * (n-1.0) * ( absum + n ) ) / ( (absum + 2.0*n) * ( absum + 2.0*n - 2.0 ) );
  subdiag[n-1] = 0.0;

  params->zemu = gsl_sf_gamma(params->alpha + 1.0) * gsl_sf_gamma(-absum - 1.0) / gsl_sf_gamma(-params->beta);
  params->shft = params->a;
  params->slp = params->b + params->a;
  params->al = params->alpha;
  params->be = params->beta;

  return GSL_SUCCESS;
}

static const gsl_integration_fixed_type rational_type =
{
  rational_check,
  rational_init
};

const gsl_integration_fixed_type *gsl_integration_fixed_rational = &rational_type;


/* stable/stable_integration.h
 *
 * Functions to perform numerical integration used when calculating
 * the PDF and CDF of alpha-stable distributions. Based on GSL
 * numerical quadrature methods.
 *
 * Copyright (C) 2013. Javier Royuela del Val
 *                     Federico Simmross Wattenberg
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; If not, see <http://www.gnu.org/licenses/>.
 *
 *
 *  Javier Royuela del Val.
 *  E.T.S.I. Telecomunicación
 *  Universidad de Valladolid
 *  Paseo de Belén 15, 47002 Valladolid, Spain.
 *  jroyval@lpi.tel.uva.es
 *
 */
#ifndef _STABLE_INTEGRATION_H_
#define _STABLE_INTEGRATION_H_

#include "stable.h"

#include <gsl/gsl_integration.h>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_sf_erf.h>
#include <gsl/gsl_math.h>

int stable_integration_METHODNAME(unsigned short method, char *s);

void
stable_integration(StableDist *dist,double(function)(double, void*),
                   double a, double b,
                   double epsabs, double epsrel, unsigned short limit,
                   double *result, double *abserr, unsigned short method);

#endif