/* bccgls.c
   $Revision: 281 $ $Date: 2006-12-13 09:03:53 -0800 (Wed, 13 Dec 2006) $

   ----------------------------------------------------------------------
   This file is part of BCLS (Bound-Constrained Least Squares).

   Copyright (C) 2006 Michael P. Friedlander, Department of Computer
   Science, University of British Columbia, Canada. All rights
   reserved. E-mail: <mpf@cs.ubc.ca>.

   BCLS is free software; you can redistribute it and/or modify it
   under the terms of the GNU Lesser General Public License as
   published by the Free Software Foundation; either version 2.1 of the
   License, or (at your option) any later version.

   BCLS 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 Lesser General
   Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with BCLS; if not, write to the Free Software
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
   USA
   ----------------------------------------------------------------------

*/
/*!
  \file
  This file implements conjugate gradients for the normal equations
  (CGLS).
*/

#include <cblas.h>
#include <string.h>
#include <assert.h>
#include <float.h>

#include "bcls.h"
#include "bclib.h"
#include "bccgls.h"

/*!

  \brief Mat-vec routine called by CGLS.

  CGLS call this routine, which in turn calls bcls_aprod:
  - If      mode == BCLS_PROD_A,   y      = A dxFree.
  - else if mode == BCLS_PROD_At,  dxFree = A'y.

  This routine is declared "static" so that it won't be confused with
  the user's own Aprod routine.

  \param[in,out] ls      BCLS solver context.
  \param[in]     mode    Specifies if the product with A or A' is required.
  \param[in]     m       Number of rows in A.
  \param[in]     nFree   Length of dxFree (and ix which is recovered via ls).
  \param[in,out] dxFree  RHS or LHS (depending on the mode).
  \param[in,out] y       RHS or LHS (depending on the mode).

*/
static void
aprod_free( BCLS *ls, const int mode, const int m, const int nFree,
	    double dxFree[], double y[] )
{
    int    *ix = ls->ix;
    double *dx = ls->dx;  // Used as workspace.

    assert( mode == BCLS_PROD_A || mode == BCLS_PROD_At );

    if (mode == BCLS_PROD_A) {

        bcls_scatter( nFree, ix, dxFree, dx );          // dx(ix) = dxFree.
	bcls_aprod( ls, BCLS_PROD_A, nFree, ix, dx, y );// y = A dx.

    } else {

	bcls_aprod( ls, BCLS_PROD_At, nFree, ix, dx, y );// dx = A' y.
        bcls_gather( nFree, ix, dx, dxFree );            // dxFree = dx(ix);
    }

    return;
}

/*!

  \brief CG for least squares.

  This routine implements CG for solving the symmetric linear system

     ( N'N + damp I ) x = N'r + c

  where N is an m-by-n submatrix of the general matrix A.  This
  implementation is adapted from Hestenes and Stiefel's CG for
  least-squares method to accomodate the damping term and the
  additional vector on the RHS.  (See, eg, Bjork, Numerical Methods
  for Least-Squares Problems, 1996, p. 289.)

  \param[in,out] ls     BCLS solver context.
  \param[in]     m      No. of rows in A.
  \param[in]     n      No. of cols in A.
  \param[in]     kmax   Maximum no. of CG iterations.
  \param[in]     tol    Required optimality tolerance:
                        - norm( A'A x - A'b ) / norm(A'b)
  \param[in]     damp   Regularization term on x.
  \param[in]     c      Additional vector (set NULL if not present).
  \param[out]    x      Solution vector.
  \param[in,out] r      On entry, r must be defined.\n
                        On exit,  r is the residual.
  \param[in,out] s      Work vector.
  \param[in,out] p      Work vector.
  \param[out]    itns   No. of CG iterations.
  \param[out]    opt    Relative residual (see tol, above).
  \param[in]     nout   File for log output (set NULL if not needed).

  \returns
  - 0:  Required accuracy was achieved.
  - 1:  The iteration limit (kmax) was reached.
  - 2:  N'N appears to be singular.

  \todo Update normx rather than recompute at each iteration.

*/
static int
bcls_cgls( BCLS *ls, int m, int n, int kmax, double tol, double damp,
	   double c[], double x[], double r[], double s[], double p[],
	   int *itns, double *opt, FILE *nout )
{
    int
        k = 0, info = 0, converged = 0, unstable = 0;
    double
        xmax = 0.0, resNE, Arnorm, Arnorm0,
        normp, norms, normx = 0.0, alpha, beta,
        gamma, gamma1, delta;
    const int
        damped = damp > 0.0;
    const double
        eps = DBL_EPSILON;

    // Initialize.
    bcls_dload( n, 0.0, x, 1 );                  // x  = 0
    aprod_free( ls, BCLS_PROD_At, m, n, s, r );  // s  = A'r
    if (c)
        cblas_daxpy( n, 1.0, c, 1, s, 1 );       // s += c
    cblas_dcopy( n, s, 1, p, 1 );                // p  = s
    Arnorm0    = cblas_dnrm2( n, s, 1 );
    gamma      = Arnorm0 * Arnorm0;

    if (nout) {
        fprintf(nout,"\n CGLS:\n");
        fprintf(nout,"  Rows............. %8d\t", m);
        fprintf(nout,"  Columns.......... %8d\n", n);
        fprintf(nout,"  Optimality tol... %8.1e\t", tol);
        fprintf(nout,"  Iteration limit.. %8d\n", kmax);
        fprintf(nout,"  Damp............. %8.1e\t", damp);
        fprintf(nout,"  Linear term...... %8s\n",
                (c) ? "yes" : "no" );
        fprintf(nout, "\n\n%5s %17s %17s %9s %10s\n",
                "k", "x(1)","x(n)","normx","resNE");
        fprintf(nout, "%5d %17.10e %17.10e %9.2e %10.2e\n",
                k, x[0], x[n-1], normx, 1.0 );
    }
    // -----------------------------------------------------------------
    // Main loop.
    // -----------------------------------------------------------------
    while ( k < kmax  &&  !converged  &&  !unstable ) {

        k++;

        aprod_free( ls, BCLS_PROD_A, m, n, p, s );   // s = A p

        norms = cblas_dnrm2( m, s, 1 );
        delta = norms * norms;
        if (damped) {
            normp  = cblas_dnrm2( n, p, 1 );
            delta += damp * normp * normp;
        }
        if (delta <= eps)
            delta =  eps;

        alpha = gamma / delta;

        cblas_daxpy( n,  alpha, p, 1, x, 1 );        // x  = x + alpha*p
        cblas_daxpy( m, -alpha, s, 1, r, 1 );        // r  = r - alpha*s
        aprod_free( ls, BCLS_PROD_At, m, n, s, r );  // s  = A'r
        if (damped)
            cblas_daxpy( n, -damp, x, 1, s, 1 );     // s += - damp*x
        if (c)
            cblas_daxpy( n,   1.0, c, 1, s, 1 );     // s += c

        Arnorm = cblas_dnrm2( n, s, 1 );
        gamma1 = gamma;
        gamma  = Arnorm * Arnorm;
        beta   = gamma / gamma1;

        cblas_dscal( n, beta, p, 1 );                // p  = beta*p
        cblas_daxpy( n, 1.0, s, 1, p, 1);            // p += s

        // Check convergence.
        normx     = cblas_dnrm2( n, x, 1 );
        xmax      = fmax( xmax, normx );
        converged = Arnorm <= Arnorm0 * tol;
        unstable  = normx * tol >= 1.0;

        // Output.
        resNE = Arnorm / Arnorm0;
        if (nout)
            fprintf(nout, "%5d %17.10e %17.10e %9.2e %10.2e\n",
                    k, x[0], x[n-1], normx, resNE );

    } // while

    double shrink = normx / xmax;
    if (converged)
        info = 0;
    else if (k >= kmax)
        info = 1;
    else if (shrink <= sqrt(tol))
        info = 2;

    // Output.
    if (nout) fprintf(nout,"\n");
    *itns = k;
    *opt  = resNE;
    return info;
}

/*!

  \brief Compute a Newton step using CGLS.

  See the description of #bcls_newton_step.

  \param[in,out] ls      BCLS solver context
  \param[in]     m       No. of rows in A.
  \param[in]     nFree   No. of free columns, i.e., no. of cols in N.
  \param[in]     ix      Index of vars for which a Newton step is computed.
  \param[in]     damp    Regularization term on dxFree.
  \param[in]     itnLim  Maximum no. of CG iterations.
  \param[in]     tol     Required optimality tolerance:
                         - norm( N'N x - N'b ) / norm(N'b).
  \param[in]     dxFree  Newton direction in the free vars (len = nFree).
  \param[in]     x       Current iterate.
  \param[in]     c       Linear term.  (Set to NULL if not present.)
  \param[in,out] r       On entry, r is current residual: r = b - Ax. \n
                         Will be used as workspace.
  \param[in]     itns    No. of CG iterations.
  \param[in]     opt     Relative residual (see tol, above).

  \return The termination flag returned by #bcls_cgls.

*/
int
bcls_newton_step_cgls( BCLS *ls, int m, int nFree, int ix[], double damp,
                       int itnLim, double tol, double dxFree[], double x[],
                       double c[], double r[], int *itns, double *opt )
{
    int
        j;
    double
        *u;
    const double
        damp2 = damp*damp;

    if (c) {
        u = ls->wrk_u;
        bcls_gather( nFree, ix, c, u );       // u  =   c(ix).
        cblas_dscal( nFree, -1.0, u, 1 );     // u  = - c(ix).
        if ( damp > 0.0 )                     // u += - damp2 x(ix).
            for (j = 0; j < nFree; j++)
                u[j] -= damp2 * x[ix[j]];
    }
    else
        u = NULL;

    return bcls_cgls( ls, m, nFree, itnLim, tol, damp2,
                      u, dxFree, r, ls->wrk_v, ls->wrk_w,
                      itns, opt, ls->minor_file );
}


#include <stdio.h>
#include <math.h>  /*per sin i cos*/
#include <stdlib.h> /*pel malloc i calloc*/
#include <gsl/gsl_errno.h>
#include <gsl/gsl_matrix.h>
#include <gsl/gsl_odeiv.h>
#include <gsl/gsl_rng.h>
#include <gsl/gsl_randist.h>
#include "memory.h"

// what data to save
int writeData; /* command line input */

// simulation run time
double tStop; /* command line input */

//capacitance
double c=1.;

// leak
double glk=1;
double vlk=-70;

// Na channel
double gna=37;
double vna=55;

// Na activation [m]
double thetam=30;
double sm=15;

// Na inactivation [h]
double thetah=-39;
double sh=3.1;
double tauh0=1;
double tauh1=500;
double thh=57;
double sigmah=3;

// K channel
double gk=45;
double vk=-80;

// K activation
double thetan=-32.;
double sn=-8.;
double taun0=1;
double taun1=100.;
double thn=80.;
double sigman=26.;

// A channel
double ga; /* command line input */

// A activation [a]
double taua   = 2;
double thetaa = -50;
double sigmaa = 20;

// A inactivation [b]
double taub=150;
double thetab=-70;
double sigmab=-6;

// kinetics rescaling
double phi=0.75;

// synapse
double vsyne = 0.;
double vsyni = -85.;
double gsyne, gsyni; /* command line input */
double rsyne, rsyni; /* command line input */
double betae = .2;
double betai = .18;
double te, ti, teNext,tiNext; /* synapse event times */

double v,m,b,n,a,se,si;
double minf,hinf,ninf,binf,ainf;
double tauh,taun,taua;
double ina,ik,ilk,ia,isyne,isyni;
double alphae;

//double twopi=8*atan(1.);
double twopi=3.1415926535;

int func (double t, const double x[], double dx[], void *params);

int jac (double t, const double y[], double *dfdy, double dfdt[], void *params);

int main(int argc, char *argv[]){

    double *x,*dx;
    double vlast,tspike;
    double si0;
    double rand;
    int ndim=6;
    int i;
    FILE *output;
    double tol=1.0e-5;
    double mu;

    //const gsl_odeiv_step_type * T  = gsl_odeiv_step_rk8pd;  // Runge-Kutta Prince-Dormand 8-9.
    //const gsl_odeiv_step_type * T  = gsl_odeiv_step_rk2imp; // Runge-Kutta 2 implicit.
    const gsl_odeiv_step_type * T  = gsl_odeiv_step_rk4imp; // Runge-Kutta 4 implicit.
    //const gsl_odeiv_step_type * T  = gsl_odeiv_step_bsimp; // Burlirsch-Stoer implicit.. Need jacobian!
    //const gsl_odeiv_step_type * T  = gsl_odeiv_step_gear1; // Gear 1 implicit.
    //const gsl_odeiv_step_type * T  = gsl_odeiv_step_gear2; // Gear 2 implicit.

    gsl_odeiv_step * s  = gsl_odeiv_step_alloc (T, ndim);
    gsl_odeiv_control * c  = gsl_odeiv_control_y_new (tol, 0.0);
    gsl_odeiv_evolve * e = gsl_odeiv_evolve_alloc (ndim);

    gsl_odeiv_system sys = {func, jac, ndim, &mu};

    /* Random generator stuff */
    const gsl_rng_type *U;
    gsl_rng *r;
    gsl_rng_env_setup();
    U = gsl_rng_default;
    r = gsl_rng_alloc (U);

    /* Parameters From Command Line */
    writeData = atof(argv[1]);
    tStop     = atof(argv[2]);
    ga        = atof(argv[3]);
    gsyne     = atof(argv[4]);
    gsyni     = atof(argv[5]);
    rsyne     = atof(argv[6]);
    rsyni     = atof(argv[7]);

    double t, tf;
    double h = 1.e-3;
    int status;

    char name1[100];
    int number1,number2,number3;
    int ncount=0;
    int nite;
    double sum;

    if (writeData==1){  /* save all data */
      sprintf(name1, "data1cpt_ga%g_ge%g_gi%g_re%.1f_ri%g.txt",ga,gsyne, gsyni, rsyne,rsyni);}
    else if (writeData==2){ /* save spikes */
      sprintf(name1, "spike1cpt_ga%g_ge%g_gi%g_re%.1f_ri%g.txt",ga,gsyne, gsyni, rsyne,rsyni);}
    output=fopen(name1, "w");

   /*open the data file*/
    output=fopen(name1, "w");
    if (output==NULL){
    printf("Error in opening data file\n");
    exit(1);
    }

/*memory allocation*/
x  = new_vector(0, ndim-1);
dx = new_vector(0, ndim-1);

/*Initial point*/
double v0=-70;
x[0]=v0; /* v */
x[1]=1./(1.+exp((v0-thetan)/sn));     /* n */
x[2]=1/(1+exp(-(v0-thetaa)/sigmaa));  /* a */
x[3]=1/(1+exp(-(v0-thetab)/sigmab));  /* b */
x[4]=0; /* se */
x[5]=0; /* si */

/*integrate*/

t=0.;
nite=0.;
vlast=v0;
te = 0;
ti = -999.; tiNext = 1000./rsyni; si0 = 0;
te = -999.; rand =gsl_ran_flat(r, 0,1); teNext = -1000.*log(1-rand)/(rsyne);
if (teNext<tiNext){tf=teNext;}
else {tf=tiNext;}

while (t<tStop){

  while (t<tf){

   status = gsl_odeiv_evolve_apply (e, c, s, &sys, &t, tf, &h, x);

   if (status != GSL_SUCCESS)
    break;

  if (writeData==1){ /* save everything */
  fprintf(output," %.5f ",t);
  for (i=0;i<ndim;i++){
   fprintf(output," %.5f ",x[i]);
   }
  fprintf(output, "\n");
  }

  /* spike detection */
  tspike =0.;
  if ((x[0]>=-10)&&(vlast<-10)){
     ncount++;
     tspike=t;
     if (writeData==2){ /* save spikes */
        fprintf(output," %.5f %.5f",tspike, si0);  fprintf(output, "\n");
     }
  }

  vlast=x[0];

  nite++;
  }

  // generate next excitatory event
  if   (tf>=teNext){
    te = teNext;
    rand=gsl_ran_flat(r, 0,1); teNext+=-1000.*log(1-rand)/(rsyne);

    // for instantaneous rise se
    x[4]=1.; // ceiling at 1

    si0 =  x[5]; // si value at the excitatory event onset
    if (writeData==2){fprintf(output," %.5f %.5f ",-tf, x[5]);  fprintf(output, "\n");} /* save excitatory events */
  }

  // generate next inhibitory event
  if   (tf>=tiNext){tiNext+=1000./rsyni; x[5]=1.;} // ceiling at 1
  if (teNext<tiNext){tf=teNext;}
  else {tf=tiNext;}

  }

  if (writeData==2){fprintf(output," %.5f  %.5f ",tStop , tStop);  fprintf(output, "\n");}
  free_vector(x,0);
  free_vector(dx,0);

  fclose(output);

  gsl_odeiv_evolve_free (e);
  gsl_odeiv_control_free (c);
  gsl_odeiv_step_free (s);

}

/* Vector field we want to integrate*/

int func (double t, const double x[], double dx[], void *params)
{
    double mu = *(double *)params;

   double m3,n4,a3;

//  general variables

v = x[0];
m = 1./(1.+exp(-(v+thetam)/sm));   // m—>minf instantaneous
n = x[1];
a = x[2] ; // 1/(1+exp(-(v-thetaa)/sigmaa)); // a->ainf instantaneous
b = x[3];
se= x[4];
si= x[5];

//  currents
m3=m*m*m;
n4=n*n*n*n;
a3=a*a*a;
ina= gna*m3*(1-n)*(v-vna);
ik = gk*n4*(v-vk);
ia = ga*a3*b*(v-vk);
ilk= glk*(v-vlk);
isyne = gsyne*se*(v-vsyne);
isyni = gsyni*si*(v-vsyni);

/* update voltage */
dx[0] = - (ilk + ina + ik + ia + isyni + isyne)/c;

/* update n gating */
ninf=1./(1.+exp((v-thetan)/sn));
taun=taun0+taun1/(1+exp((v+thn)/sigman));
dx[1]=phi*(ninf-n)/taun;

/* update a gating */
ainf = 1/(1+exp(-(v-thetaa)/sigmaa));
dx[2] = (ainf-a)/taua;

/* update b gating */
binf = 1./(1+exp(-(v-thetab)/sigmab));
dx[3]=(binf-b)/taub;

/* update excitation */
dx[4] = -betae*se; // instantaneous rise, exponential decay

/* update inhibition */
dx[5] = -betai*si;

  return GSL_SUCCESS;
}

/* The jacobian
 * In case we wanna use implict Burslish-Stoer methods
 */
int jac (double t, const double y[], double *dfdy, double dfdt[], void *params)
{
    double mu = *(double *)params;
    gsl_matrix_view dfdy_mat = gsl_matrix_view_array (dfdy, 2, 2);
    gsl_matrix * m = &dfdy_mat.matrix;

    // Si usamos Burlish-Stoer tenemos de dar el Jacobiano
    /*gsl_matrix_set (m, 0, 0, 0.0);
    gsl_matrix_set (m, 0, 1, 1.0);
    gsl_matrix_set (m, 1, 0, -2.0*mu*y[0]*y[1] - 1.0);
    gsl_matrix_set (m, 1, 1, -mu*(y[0]*y[0] - 1.0));*/

    // Si usamos otro método podemos dejar el jacobiano
    // todo a cero.
    gsl_matrix_set (m, 0, 0, 0.0);
    gsl_matrix_set (m, 0, 0, 0.0);
    gsl_matrix_set (m, 0, 0, 0.0);
    gsl_matrix_set (m, 0, 0, 0.0);
    dfdt[0] = 0.0;
    dfdt[1] = 0.0;

    return GSL_SUCCESS;
}


#include <sys/types.h> // per utilizzare variabili di tipo pthread_t
#include <stdlib.h> // utilità generale (allocazione, controllo processi, etc.)
#include <pthread.h> // per utilizzo dei thread
#include <string.h> // per elaborazione su stringhe
#include <math.h>

#include <gsl/gsl_vector.h> // per usare i vettori
#include <gsl/gsl_matrix.h> // per usare le matrici

#include <gsl/gsl_eigen.h> // per calcolare autovalori e autovettori

#include <gsl/gsl_statistics.h> // per usare funzioni di probabilità

#include <gsl/gsl_linalg.h> // per usare funzioni su matrici
#include <gsl/gsl_permutation.h> // per usare le permutazioni

#define debug 0 // variabile per settare le stampe di controllo
#define troncamento 100 // per approssimazione alla 3° cifra significativa dopo la virgola

int controllo = 1; // variabile per verificare la chiamata di funzioni

double **data_set_origine, **data_set, **data_compression, **autovettori;
double *autovalori;
int dimensione = 0;

struct registro{ // puntatori alle celle per eseguire il prodotto matriciale A*B
	double *mtx_1, *mtx_2; //mtx_1: riga di A, mtx_2: colonna di B
	int *indici; // posizione in cui salvare il singolo valore dell'operazione
} catalogo;

struct gsl{ // puntatori agli autovalori e autovettori di tipo gsl
	gsl_vector *vector; // autovalori
	gsl_matrix *matrix; // autovettori
} puntatori_gsl;

void stampa(int tipo, double **mt1, double *mt2, char nome[], int nr, int nc){ // il tipo indica che tipo di stampa effettuo
	int i,j = 0;
	switch(tipo){
		case 0: //stampa dimensione
			printf("%s: %d \n", nome, nr); //Dimensioni
		break;
		case 1: //stampa la matrice con il proprio nome
			printf("Stampa matrice %s: \n", nome);
			for(i = 0; i < nr; i++){
				for(j = 0; j < nc; j++){
					if(j == 0){
						printf("|   ");
					}
					printf("%2.2f\t", mt1[i][j]);
					if(j == nc-1){
						printf("|");
					}
				}
				printf("\n");
			}
		break;
		case 2://stampa media in forma estesa
			printf("Stampa valor medio: \n");
			for(i = 0; i < nr; i++){
				printf("media[%d]=%2.2f \n", i, mt2[i]);
			}
		break;
		case 3: //stampa gli autovalori in forma matriciale
			printf("Stampa autovalori(covarianza): \n");
			for(i = 0; i < dimensione; i++){
				if(i == 0){
					printf("|   ");
				}
				printf("%2.4g\t", autovalori[i]);
				if(i == dimensione-1){
					printf("| \n");
				}
			}
		break;
		case 5: //stampa errori verifica
			printf("Errore la verifica non è andata a buon fine\n");
			printf("La matrice Verifica è diversa dalla matrice di partenza \n");
		break;
		case 6://stampa matrici monodimensionali in maniera estesa
			printf("Stampa Matrice Estesa %s: \n", nome);
			for(i = 0; i < dimensione; i++){
				printf("%s[%d]=%2.2f \n", nome, i, mt2[i]);
			}
		break;
		case 7: //stampa matrici bidimensionali in maniera estesa
			printf("Stampa Matrice Estesa %s : \n", nome);
			for(i = 0; i < dimensione; i++){
				for(j = 0; j < dimensione; j++){
					printf("%s[%d][%d]=%2.2f \n", nome, i, j, mt1[i][j]);
				}
			}
		break;
	}
	printf("\n");
}

void *thread_function(void *candidato){ // singola iterazione del prodotto matriciale
	int i = 0;
    int *indici;
	double *mtx_1, *mtx_2;
	struct registro *catalogo;

	// casting degli argomenti della thread_function
	catalogo=(struct registro*)candidato;
	mtx_1=catalogo->mtx_1;
	mtx_2=catalogo->mtx_2;
	indici=catalogo->indici;

	/*
		esecuzione del prodotto matriciale (a singoli elementi): si esegue il singolo prodotto, il risultato
		lo si salva sulla posizione corrente del'array tmp[0]; infine si somma il precedente risultato al valore presente
		nella cella 0 di tmp (tmp[0][0] svolgerà il ruolo di sommatore, senza dover creare una variabile temporanea).
	*/
	for(i=0; i<dimensione; i++){
		if(debug==1){printf("mtx_1[%d] = %2.2f  ,  mtx_2[%d] = %2.2f\n", i, mtx_1[i], i, mtx_2[i]);}
		mtx_1[i]=mtx_1[i]*mtx_2[i];
		if(debug==1){printf("singolo prodotto: %2.2f\n", mtx_1[i]);}
		if(i>0){
			mtx_1[0]=mtx_1[0]+mtx_1[i];
			if(debug==1){printf("somma: %2.2f\n", mtx_1[0]);}
		}
	} i=0;

	// inserimento della somma nell'apposita cella della matrice globale: data_compression
	data_compression[indici[0]][indici[1]]=mtx_1[0];
	if(debug==1){
		printf("data_compression[%d][%d]=%2.2f\n", indici[0], indici[1], data_compression[indici[0]][indici[1]]);
	}

	return NULL;
}

double *media(int nrighe){ // media sulle righe del data set
	int i, j = 0;
	double somma = 0;
	double *media;

	media=malloc(nrighe*sizeof(double)); // alloccamento dinamico
	if(media==NULL){printf("ERRORE: media non alloccata.\n");}

	for(i=0; i<nrighe; i++){
		for(j=0; j<dimensione; j++){
			somma = somma+data_set[i][j]; // somma su riga i-esima del data_set
			if(debug==1){printf("somma = %2.2f\n", somma);}
		}
		media[i]=somma/dimensione; // valor medio della i-esima riga del data_set
		somma=0; // reset per riga successiva
		if(debug){printf("Media: %2.2f \n", media[i]);}
	}

	return media;
}

double **covarianza(double *media, int nrighe){ // matrice di covarianza del data set
	int i, j, k = 0;
	double **covarianza;
	double	*tmp1, *tmp2;

	// alloccamento dinamico
	tmp1=malloc(nrighe*sizeof(double));
	if(tmp1==NULL){printf("ERRORE - covarianza: tmp1 non alloccato.\n"); exit(0);}

	tmp2=malloc(nrighe*sizeof(double));
	if(tmp2==NULL){printf("ERRORE - covarianza: tmp2 non alloccato.\n"); exit(0);}

	covarianza=malloc(dimensione*sizeof(double*));
	if(covarianza==NULL){printf("ERRORE - covarianza: covarianza non alloccato.\n"); exit(0);}

	for(i=0; i<dimensione; i++){
		covarianza[i]=malloc(dimensione*sizeof(double));
		if(covarianza[i]==NULL){printf("ERRORE - covarianza: covarianza[%d] non alloccato.\n", i); exit(0);}
	}

	/*
		dei 4 for, definiamo "principali" quelli riferiti alla variabile 'i' e 'j' in quanto vanno ad identificare la cella  (i, j) della matrice di
		covarianza; i for riferiti alla variabile 'k' sono for di settaggio dei due array temporanei, che andranno a considerare le colonne
		del data set.
		Ad ogni ciclo dell' i-for si fisserà una riga (partendo dalla riga 0), e si andrà a "combinare" con tutte le colonne del data set (a
		partire dalla riga 0).
	*/

	for(i=0; i<dimensione; i++){
		for(k=0; k<nrighe; k++){ // fissiamo colonna i-esima
			tmp1[k]=data_set[k][i];
			if(debug==1){
				stampa(6, NULL, tmp1, "tmp1", 0, 0);
			}
		}
		for(j=0; j<dimensione; j++){
			for(k=0; k<nrighe; k++){ // consideriamo colonna j-esima
				tmp2[k]=data_set[k][j];
				if(debug==1){
					stampa(6, NULL, tmp2, "tmp2", 0, 0);
				}
			}
			covarianza[i][j]=gsl_stats_covariance(tmp1, 1, tmp2, 1, nrighe); // calcolo della covarianza
		}
		if(debug==1){
			stampa(7, covarianza, NULL, "Covarianza", 0, 0);
		}
	}

	free(tmp1);
	free(tmp2);

	return covarianza;
}

struct gsl eigen(double **covarianza){ // calcolo autovalori e autovettori della matrice di covarianza
	int i=0, j=0;
	gsl_matrix *matrice, *evec;
	gsl_vector *evel;
	gsl_eigen_symmv_workspace *campo;
	struct gsl pointer_gsl;

	// allocazione
	matrice=gsl_matrix_alloc(dimensione, dimensione); // alloccamento matrice bid: "dimensione" righe e "dimensione" colonne
	if(matrice==NULL){printf("ERRORE - eigen: matrice non alloccato"); exit(0);}

	evec=gsl_matrix_alloc(dimensione, dimensione); // alloccamento matrice bid: "dimensione" righe e "dimensione" colonne
	if(evec==NULL){printf("ERRORE - eigen: evec non alloccato"); exit(0);}

	evel=gsl_vector_calloc(dimensione); // alloccamento vettore: "dimensione" posizioni
	if(evel==NULL){printf("ERRORE - eigen: evel non alloccato"); exit(0);}

	campo=gsl_eigen_symmv_alloc(dimensione); // alloccamento del workspace, dimensione pari a: "dimensione"
	if(campo==NULL){printf("ERRORE - eigen: campo non alloccato"); exit(0);}

	// copiamo "covarianza" nella "matrice"
	for(i=0; i<dimensione; i++){
		for(j=0; j<dimensione; j++){
			if(debug==1){printf("covarianza[%d][%d] = %2.2f\n", i, j, covarianza[i][j]);}
			gsl_matrix_set(matrice, i, j, covarianza[i][j]); // inserimento del valore nella "matrice"
			if(debug==1){printf("matrice[%d][%d] = %2.2f\n", i, j, gsl_matrix_get(matrice, i, j));}
		}
	}

	controllo=gsl_eigen_symmv(matrice, evel, evec, campo); // calcolo degli autovalori e autovettori
	if(controllo!=0){printf("ERRORE - eigen: gsl_eigen_symmv fallito.\n"); exit(0);}

	// salvataggio dei puntatori agli autovalori  e autovettori nella struttura "gsl"
	pointer_gsl.vector=evel;
	pointer_gsl.matrix=evec;

	gsl_matrix_free(matrice);
	gsl_eigen_symmv_free(campo);

	return pointer_gsl;
}

void ordinamento(gsl_matrix *vettori){ // ordinamento decrescente degli autovalori
	int i,j = 0;
	double tmp = 0;

	for(i=0; i<dimensione; i++){
		if(autovalori[i]<0){
			autovalori[i]=autovalori[i]*(-1);
		}
	}

	/*
		dato che c'è una corrispondenza biunivoca fra l'array degli autovalori e la matrice degli autovettori, allora
		ordinando gli autovalori si ordinano anche gli autovettori, per mantenere la precedente proprietà.
	*/
	for(i = 0; i < dimensione; i++){
		for(j = 0; j < dimensione; j++){
			if(debug==1){printf("autovalori[%d] = %2.2f  ,  autovalori[%d] = %2.2f\n", j, autovalori[j], i, autovalori[i]);}
			if(autovalori[j] < autovalori[i]){
				tmp=autovalori[i];
				if(debug==1){printf("tmp = %2.2f\n", tmp);}
				autovalori[i]=autovalori[j];
				autovalori[j]=tmp;
				if(debug==1){printf("autovalori[%d] = %2.2f  ,  autovalori[%d] = %2.2f\n", j, autovalori[j], i, autovalori[i]);}
				gsl_matrix_swap_columns(vettori, i, j);
				if(controllo!=0){printf("ERRORE - ordinamento: gsl_matrix_swap_columns fallito.\n"); exit(0);}
			}
		}
		tmp=0;
	}
}

double **sottrazione_matriciale(int nrighe, double *media){ // data set "differenziato"
	int i, j = 0;
	double **sottrazione;

	// alloccamento dinamico
	sottrazione=malloc(nrighe*sizeof(double*));
	if(sottrazione==NULL){printf("ERRORE - sottrazione_matriciale: sottrazione non alloccato.\n"); exit(0);}
	for(i=0; i<nrighe; i++){
		sottrazione[i]=malloc(dimensione*sizeof(double));
		if(sottrazione[i]==NULL){printf("ERRORE - sottrazione_matriciale: sottrazione[%d] non alloccato.\n", i); exit(0);}
	}

	// ogni riga del data set viene differenziato per la media della riga stessa
	for(i=0; i<nrighe; i++){
		for(j=0; j<dimensione; j++){
			sottrazione[i][j]=data_set[i][j]-media[i];
			if(debug==1){printf("data_set[%d][%d] = %2.2f  ,  media[%d] = %2.2f  ,  sottrazione[%d][%d] = %2.2f\n",
					i, j, data_set[i][j], i, media[i], i, j, sottrazione[i][j]);
			}
		}
	}

	return sottrazione;
}

int prodotto_matriciale(int righe_1, int colonne_1, int righe_2, int colonne_2, double **matrice_1, double **matrice_2){ //Funzione per fare il prodotto matriciale
	int i, i_1, j_1, contatore, fine = 0;
	int *indici;
	double *mtx_1, *mtx_2;
	pthread_t *thread;

	struct registro *enciclopedia; // array di strutture registro

	if(colonne_1 != righe_2){
		printf("ERRORE - prodotto_matriciale: non è soddisfatta la condizione del prodotto matriciale.\n");
		return -1;
	}

	enciclopedia=malloc(righe_1*colonne_2*sizeof(struct registro)); //creazione struttura
	if(enciclopedia==NULL){printf("ERRORE - prodotto_matriciale: enciclopedia non alloccata.\n"); exit(0);}

	/*
		Definiamo come "prodotto", il prodotto dei valori (in stessa posizione) fra due array, e successiva somma dei singoli
		prodotti.
		Definiamo come "singola iterazione" o "singola procedura" il prodotto fra la riga i-esima della matrice A per la colonna
		j-esima della matrice B, al variare di i e j.
	*/

		// settaggio dei parametri da inviare ai thread (obbligatori, altrimenti parte il segmentation fault)
		contatore=0;
		i_1=0;
		j_1=0;

		/*
			Il seguente while serve a riempire l'array di strutture che contengono: la riga di A, la colonna di B e gli indici di posizione
			in cui salvare il risultato della singola procedura del prodotto matriciale.
		*/
		while(fine==0){ // alloccamento dinamico di due array "temporanei" e salvataggio indirizzi nell'array tmp

			mtx_1=malloc(colonne_1*sizeof(double)); // riga di A
			if(mtx_1==NULL){printf("ERRORE - prodotto_matriciale: mtx_1 non alloccato.\n"); exit(0);}

			mtx_2=malloc(righe_2*sizeof(double*)); // colonna di B
			if(mtx_2==NULL){printf("ERRORE - prodotto_matriciale: mtx_2 non alloccato.\n"); exit(0);}

			indici=malloc(2*sizeof(int)); // array degli indici di posizione del data_compression
			if(indici==NULL){printf("ERRORE - prodotto_matriciale: indici non alloccato.\n"); exit(0);}

			if(debug==1){
				printf("contatore = %d, colonne_2=%d, righe_1=%d, i_1=%d, j_1=%d\n",
																	contatore, colonne_2, righe_1, i_1, j_1);
				}

			for(i = 0; i < colonne_1; i++){
				mtx_1[i]=matrice_1[i_1][i]; // copia della riga i_1 di A in mtx_1
				mtx_2[i]=matrice_2[i][j_1]; // copia della colonna j_1 di B in mtx_2
			}

			if(debug==1){
				stampa(6, NULL, mtx_1, "MTX_1", 0, 0);
				stampa(6, NULL, mtx_2, "MTX_2", 0, 0);
			}

			// salvataggio dimensioni ed indici di posizione nella singola struttura
			indici[0]=i_1;
			indici[1]=j_1;

			// salvataggio dei parametri in una struttura "registro"
			enciclopedia[contatore].mtx_1 = mtx_1;
			enciclopedia[contatore].mtx_2 = mtx_2;
			enciclopedia[contatore].indici = indici;

			contatore++; // rappresenta l'indice dell'array di struttura
			if(debug==1){
				printf("contatore = %d\n", contatore);
			}

			if(debug==1){
				printf("j_1+1 = %d  ,  colonne_2 = %d  ,  i_1+1 = %d  ,  righe_1 = %d\n", j_1+1, colonne_2, i_1+1, righe_1);
				}
			if(j_1+1<colonne_2){ // andiamo alla colonna successiva di B
				j_1++;
				if(debug==1){
					printf("j_1 = %d\n", j_1);
				}
			}else if(i_1+1<righe_1){ // andiamo alla riga successiva di A
				i_1++;
				j_1=0; // la riga parte dalla colonna 0
				if(debug==1){
					printf("i_1 = %d\n", i_1);
				}
			}else{
				fine=1; // sono stati passati tutti i valori, il while è finito
			}
		}
		contatore=0;
		i=0;
		i_1=0;
		j_1=0;
		fine=0;

		// alloccamento array di thread
		thread=malloc(righe_1*colonne_2*sizeof(pthread_t));
		if(thread==NULL){
			printf("ERRORE - prodotto_matriciale: thread non alloccato.\n");
			exit(0);
		}

		// verifica del corretto contenuto delle strutture
		if(debug==1){
			int j = 0;
			for(i=0; i<righe_1*colonne_2; i++){
				printf("Stampa del contenuto delle strutture.\n");
				printf("------------\n");
				for(j=0; j<colonne_1; j++){
					printf("enciclopedia[%d].mtx_1[%d]= %2.2f\n", i, j, enciclopedia[i].mtx_1[j]);
				}
				for(j=0; j<colonne_1; j++){
					printf("enciclopedia[%d].mtx_2[%d]= %2.2f\n", i, j, enciclopedia[i].mtx_2[j]);
				}
				for(j=0; j<2; j++){
					printf("enciclopedia[%d].indici[%d]=%d\n", i, j, enciclopedia[i].indici[j]);
				}
			}
			printf("------------\n");
		}

		for(i=0; i<righe_1*colonne_2; i++){

			/*
			chiamata del singolo thread, gli argomenti sono: riga della matrice 1, colonna della matrice 2, indice della riga considerata e
			indice della  colonna considerata.
			*/
			//printf("------------\n");
			controllo=pthread_create(&thread[i], NULL, (void*)thread_function, (void*)&enciclopedia[i]);
			if(controllo!=0){printf("ERRORE - prodotto_matriciale: pthread_create fallito.\n"); exit(0);}
			//printf("------------\n");
		}
		controllo=pthread_join(thread[(righe_1*colonne_2)-1], NULL); // il main attende l'ultimo thread prima di proseguire
		if(controllo!=0){printf("ERRORE - prodotto_matriciale: pthread_join fallito.\n"); exit(0);}

		free(mtx_1);
		free(mtx_2);
		free(indici);
		free(enciclopedia);

		return 0;
}

double **inversione_matriciale(gsl_matrix *evec){ // matrice degli autovettori invertita
	int i, j = 0;
	int *segno;
	double **inversione;
	gsl_matrix *inverse;
	gsl_permutation *permutazione;

	// alloccamento dinamico
	inversione=malloc(dimensione*sizeof(double*));
	if(inversione==NULL){printf("ERRORE - inversione_matriciale: inversione non alloccato.\n"); exit(0);}
	for(i=0; i<dimensione; i++){
		inversione[i]=malloc(dimensione*sizeof(double));
		if(inversione[i]==NULL){printf("ERRORE - inversione_matriciale: inversione[%d] non alloccato.\n", i); exit(0);}
	}

	inverse=gsl_matrix_alloc(dimensione, dimensione); //alloccamento della matrice inversa
	if(inverse==NULL){printf("ERRORE - inversione_matriciale: inverse non alloccato.\n"); exit(0);}

	permutazione=gsl_permutation_calloc(dimensione); // alloccamento dell'array di permutazione
	if(permutazione==NULL){printf("ERRORE - inversione_matriciale: permutazione non alloccato.\n"); exit(0);}

	segno=malloc(1*sizeof(int)); // inizializzazione della variabile
	if(segno==NULL){printf("ERRORE - inversione_matriciale: segno non alloccato.\n"); exit(0);}

	controllo=gsl_linalg_LU_decomp(evec, permutazione, segno); //decompoposizione (obbligatorio)
	if(controllo!=0){printf("ERRORE - inversione_matriciale: gsl_linalg_LU_decomp fallito.\n");}

	controllo=gsl_linalg_LU_invert(evec, permutazione, inverse); //inversione matriciale
	if(controllo!=0){printf("ERRORE - inversione_matriciale: gsl_linalg_LU_invert fallito.\n");}

	// matrice inversa inserita in una matrice "non di libreria"
	for(i=0; i<dimensione; i++){
		for(j=0; j<dimensione; j++){
			inversione[i][j]=gsl_matrix_get(inverse, i, j);
		}
	}
	gsl_matrix_free(inverse);
	gsl_permutation_free(permutazione);
	free(segno);

	return inversione;
}

double **addizione_matriciale(int nrighe, double *media){ // data compression "addizionato"
	int i, j = 0;
	double **addizione;

	// alloccamento dinamico
	addizione=malloc(nrighe*sizeof(double*));
	if(addizione==NULL){printf("ERRORE - addizione_matriciale: addizione non alloccato.\n"); exit(0);}
	for(i=0; i<nrighe; i++){
		addizione[i]=malloc(dimensione*sizeof(double));
		if(addizione[i]==NULL){printf("ERRORE - addizione_matriciale: addizione[%d] non alloccato.\n", i); exit(0);}
	}

	// ogni riga del data compression viene addizzionato per la media (della stessa riga) del data set
	for(i=0; i<nrighe; i++){
		for(j=0; j<dimensione; j++){
			addizione[i][j]=data_compression[i][j]+media[i];
			if(debug==1){printf("data_compression[%d][%d] = %2.2f  ,  media[%d] = %2.2f  ,  addizione[%d][%d] = %2.2f\n",
					i, j, data_compression[i][j], i, media[i], i, j, addizione[i][j]);
			}
		}
	}

	return addizione;
}

double **inversione_operazione(int nrighe, double *media, gsl_matrix *evec){ // invertiamo l'algoritmo
	double **verifica;

	// verifica = data_compression*autovettori(invertiti) + media_righe_data_set = data_set

	// operazione di inversione della matrice
	verifica=inversione_matriciale(evec);
	//stampa(1, verifica, NULL, "Inversa", dimensione, 0);

	// operazione di prodotto matriciale
	if(0 != prodotto_matriciale(nrighe, dimensione, dimensione, dimensione, data_compression, verifica)){
		printf("ERRORE - inversione_operazione: funzione prodotto_matriciale ha riportato un errore, esecuzione arrestata.\n");
		exit(0);
	}

	//stampa(1, data_compression, NULL, "Prodotto Matriciale", nrighe, 0);

	verifica=addizione_matriciale(nrighe, media); // operazione di somma matriciale

	return verifica;
}

void trasponi(int nr, int nc){ // esegue la trasposizione della matrice
	int i, j;
	j = 0;

	for(j = 0; j < nc; j++){
		for(i = 0; i < nr; i++){
				data_set[j][i] = data_set_origine[i][j];
			}
	}
}

void ottieni(char stringa[], int riga){ // estrazione del data set
	int set=0, last_set=0;
	int i, j=0, k;
	char buf[100];
	double a;

	k=0;
	for(i = 0; i < strlen(stringa); i++){ //per leggere tutti i caratteri
		if( (((int)stringa[i]) == 43) || (((int)stringa[i]) == 45) || (((int)stringa[i]) == 46) || ((((int)stringa[i]) > 47) && (((int)stringa[i]) < 58))){
			set=1; //dico che erano caratteri
			buf[j]=stringa[i]; //salvo il numero
			j++; //incremento il puntatore
		}else{
			set=0;
		}
		if((set==0 && last_set==1) || (set==1 && i == (strlen(stringa)-1))){ //controllo se ho letto tutto il numero
			a=atof(buf); //converto la stringa in un double
			data_set_origine[riga][k]=a; //salvo il numero
			k++; //incremento la colonna
			strcpy(buf, ""); //svuoto il buf
			j=0;//pongo il puntatore del buf a 0 così da poter leggere il numero seguente
		}
		last_set=set; //dico qual'era il valore precedente
	}
}

int colonne(char stringa[]){ //conto il numero di colonne
	int set=0, last_set=0; //variabili per puntare il carattere e il penultimo carattere
	int i, j=0; //variabili locali, j è il numero di colonne

	for(i = 0; i < strlen(stringa); i++){
		/*controllo se il carattere in questione è un numero, il segno + o -, oppure il .*/
		if( (((int)stringa[i]) == 43) || (((int)stringa[i]) == 45) || (((int)stringa[i]) == 46) || ((((int)stringa[i]) > 47) && (((int)stringa[i]) < 58))){
			set=1;
		}else{
			set=0;
		}
		if((last_set == 1 && set == 0)||(set == 1 && i == (strlen(stringa) -1))){ //controllo se ho finito di leggere il numero
			j++;
		}
		last_set=set;
	}
	return j; //ritorno il numero di colonne
}

int lettura(){ // funzione per leggere il file in input
	FILE *fp; // file per la lettura
	char pathname[1000]; //percorso file
	char buf[2000];
	char *s;
	int i=0, nrighe=0, ncolonne=1;
	int j=0;

	/*prendo in ingresso il nome del file*/
	printf("Inserisci l'indirizzo del file: \n");
	scanf("%s", pathname);
	if( (fp = fopen(pathname, "r")) == NULL ){ // apro il file e controllo se è avvenuto con successo
		printf("ERRORE - lettura: apertura file %s fallito.\n", pathname);
		exit(0);
	}

	/*inizio la lettura del file*/
	while(1){ // conto il numero di righe e colonne
		stpcpy(buf, "");
		s = fgets(buf, sizeof(buf), fp);
		if(s == NULL) break; // se la linea è vuota ho letto tutto il file
		nrighe++; // conto le righe
		if(j == 0){
			ncolonne=colonne(buf);
			j++;
		}
	}

	data_set_origine=malloc(nrighe*sizeof(double*));//allocco la memoria del data set
	data_set=malloc(ncolonne*sizeof(double*));

	if(data_set == NULL){
		printf("ERRORE - lettura: data_set non alloccato.\n");
		exit(0);
	}

	if(data_set_origine == NULL){
		printf("ERRORE - lettura: data_set non alloccato.\n");
		exit(0);
	}

	for(i = 0; i < nrighe; i++){//alloco tutta la memoria
		data_set_origine[i]=malloc(ncolonne*sizeof(double));
		data_set[i]=malloc(nrighe*sizeof(double));

		if(data_set[i] == NULL){
			printf("ERRORE - lettura: data_set[%d] non alloccato.\n", i);
			exit(0);
		}

		if(data_set_origine[i] == NULL){
			printf("ERRORE - lettura: data_set_origine[%d] non alloccato.\n", i);
			exit(0);
		}
	}

	rewind(fp);

	for(i = 0; i < nrighe; i++){
		stpcpy(buf, "");
		s = fgets(buf, sizeof(buf), fp);
		ottieni(buf, i);
	}

	fclose(fp);

	trasponi(nrighe, ncolonne);

	dimensione = nrighe;
	return ncolonne;
}

int main(int argc, char **argv){
	int nrighe, i, j = 0; //variabili di gestione
	double *valor_medio, **matrice_covarianza, **sottrazione, **verifica; //array per il salvataggio dei dati
	struct gsl pointer_gsl; //inizializzazione struttura

	if(debug){printf("MODALITA' DEBUG ATTIVA\n");}

	nrighe=lettura(); // apertura e lettura del data set, nrighe=ncolonne perchè abbiamo trasposto la matrice

	stampa(0, NULL, NULL, "nrighe", nrighe, 0);
	stampa(0, NULL, NULL, "Dimensione del Data_set", dimensione, 0); // stampa dimensioni del data set

	//stampa(1, data_set_origine, NULL, "Data Set", dimensione, nrighe);
	stampa(1, data_set, NULL, "Data Set Trasposto", nrighe, dimensione);

	// alloccamento dinamico
	data_compression=malloc(nrighe*sizeof(double*));
	if(data_compression==NULL){printf("ERRORE - main: data_compression non alloccato.\n"); exit(0);}
	for(i=0; i<nrighe; i++){
		data_compression[i]=malloc(dimensione*sizeof(double));
		if(data_compression[i]==NULL){printf("ERRORE - main: data_compression[%d] non alloccato.\n", i); exit(0);}
	}

	autovalori=malloc(dimensione*sizeof(double));
	if(autovalori==NULL){printf("ERRORE - main: autovalori non alloccato.\n"); exit(0);}

	autovettori=malloc(dimensione*sizeof(double*));
	if(autovettori==NULL){printf("ERRORE - main: autovettori non alloccato.\n"); exit(0);}
	for(i=0; i<dimensione; i++){
		autovettori[i]=malloc(dimensione*sizeof(double));
		if(autovettori==NULL){printf("ERRORE - main: autovettori[%d] non alloccato.\n", i); exit(0);}
	}

	valor_medio=media(nrighe); // calcolo dei valor medi
	//stampa(2, NULL, valor_medio, NULL, nrighe, 0);

	matrice_covarianza=covarianza(valor_medio, nrighe); // calcolo della matrice di covarianza
	//stampa(1, matrice_covarianza, NULL, "Covarianza", dimensione, dimensione);

	pointer_gsl=eigen(matrice_covarianza); // calcolo degli autovalori e autovettori

	for(i=0; i<dimensione; i++){ // settaggio degli autovalori nell'apposito array
		autovalori[i]=gsl_vector_get(pointer_gsl.vector, i);
	}

	//stampa(3, NULL, NULL, NULL, 0, 0); // stampa autovalori (non ordinanti)

	gsl_vector_free(pointer_gsl.vector);

	ordinamento(pointer_gsl.matrix); // ordinamento decrescente di autovalori e autovettori

	for(i=0; i<dimensione; i++){ // settaggio degli autovettori negll'apposito array
		for(j=0; j<dimensione; j++){
			autovettori[i][j]=gsl_matrix_get(pointer_gsl.matrix, i, j); // estrazione del valore da "evec"
			if(autovettori[i]==NULL){printf("ERRORE - main: gsl_matrix_get fallito.\n"); exit(0);}
		}
	}

	//stampa(3, NULL, NULL, NULL, 0, 0); // stampa autovalori
	//stampa(1, autovettori, NULL, "Autovettori", dimensione, dimensione); // stampa autovettori

	sottrazione=sottrazione_matriciale(nrighe, valor_medio); // operazione di sottrazione matriciale
	//stampa(1, sottrazione, NULL, "Sottrazione", nrighe, 0);

	if(0 != prodotto_matriciale(nrighe, dimensione, dimensione, dimensione, sottrazione, autovettori)){ // operazione di prodotto matriciale
		printf("ERRORE - main: funzione prodotto_matriciale ha riportato un errore, esecuzione arrestata.\n");
		return 0;
	}

	stampa(1, data_compression, NULL, "Data Compression", nrighe, dimensione);

	free(sottrazione);

	verifica=inversione_operazione(nrighe, valor_medio, pointer_gsl.matrix); // operazione inversa (ricavo il data set)
	stampa(1,  verifica, NULL, "Verifica", nrighe, dimensione);

	gsl_matrix_free(pointer_gsl.matrix);

	stampa(1, data_set, NULL, "Dataset", nrighe, dimensione);

	for(i=0; i<nrighe; i++){ // verifica della buona riuscita dell'operazione d'inversione
		for(j=0; j<dimensione; j++){
			//tronco alla 3° cifra decimale per trascurare piccole variazioni, dovute ad errori di approssimazione
			if((floor(data_set[i][j]*troncamento)/troncamento) != ((floor(verifica[i][j]*troncamento))/troncamento)){
				stampa(5, NULL, NULL, NULL, 0, 0);
			}
		}
	}
	printf("programma terminato.\n");

	return 0;
}


/* specfunc/atanint.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 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_mode.h>
#include <gsl/gsl_sf_expint.h>

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

static double atanint_data[21] = {
  1.91040361296235937512,
 -0.4176351437656746940e-01,
  0.275392550786367434e-02,
 -0.25051809526248881e-03,
  0.2666981285121171e-04,
 -0.311890514107001e-05,
  0.38833853132249e-06,
 -0.5057274584964e-07,
  0.681225282949e-08,
 -0.94212561654e-09,
  0.13307878816e-09,
 -0.1912678075e-10,
  0.278912620e-11,
 -0.41174820e-12,
  0.6142987e-13,
 -0.924929e-14,
  0.140387e-14,
 -0.21460e-15,
  0.3301e-16,
 -0.511e-17,
  0.79e-18,
};
static cheb_series atanint_cs = {
  atanint_data,
  20,
  -1, 1,
  10
};

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

int
gsl_sf_atanint_e(const double x, gsl_sf_result * result)
{
  const double ax  = fabs(x);
  const double sgn = GSL_SIGN(x);

  /* CHECK_POINTER(result) */

  if(ax == 0.0) {
    result->val = 0.0;
    result->err = 0.0;
    return GSL_SUCCESS;
  }
  else if(ax < 0.5*GSL_SQRT_DBL_EPSILON) {
    result->val = x;
    result->err = 0.0;
    return GSL_SUCCESS;
  }
  else if(ax <= 1.0) {
    const double t = 2.0 * (x*x - 0.5);
    gsl_sf_result result_c;
    cheb_eval_e(&atanint_cs, t, &result_c);
    result->val  = x * result_c.val;
    result->err  = x * result_c.err;
    result->err += GSL_DBL_EPSILON * fabs(result->val);
    return GSL_SUCCESS;
  }
  else if(ax < 1.0/GSL_SQRT_DBL_EPSILON) {
    const double t = 2.0 * (1.0/(x*x) - 0.5);
    gsl_sf_result result_c;
    cheb_eval_e(&atanint_cs, t, &result_c);
    result->val  = sgn * (0.5*M_PI*log(ax) + result_c.val/ax);
    result->err  = result_c.err/ax + fabs(result->val*GSL_DBL_EPSILON);
    result->err += GSL_DBL_EPSILON * fabs(result->val);
    return GSL_SUCCESS;
  }
  else {
    result->val = sgn * (0.5*M_PI*log(ax) + 1.0 / ax);
    result->err = 2.0 * fabs(result->val * GSL_DBL_EPSILON);
    return GSL_SUCCESS;
  }
}

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

#include "eval.h"

double gsl_sf_atanint(const double x)
{
  EVAL_RESULT(gsl_sf_atanint_e(x, &result));
}


/*
How to use blas and lapack with the standard
interfaces provided by their respective projects, repectively through
`cblas.h` and `lapacke.h`
*/

#include <assert.h>
#include <math.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>

#include <cblas.h>
#include <lapacke.h>

/**
 * assert two integers are equal
 * if not, print them to stderr and assert false
 */
void assert_eqi(int i1, int i2) {
    if (i1 != i2) {
        fprintf(stderr, "%d\n%d\n\n\n", i1, i2);
        assert(false);
    }
}

/**
 * assert two doubles are equal within err precision
 * if not, print them to stderr
 */
void assert_eqd(double d1, double d2, double err) {
    if (fabs(d1 - d2) > err) {
        fprintf(stderr, "%f\n%f\n\n\n", d1, d2);
        assert(false);
    }
}

/** print an array of doubles to stderr */
void print_vecd(int n, double * v) {
    int i;
    for (i=0; i<n; i++) {
        fprintf(stderr, "%.2f ", v[i]);
    }
    printf("\n");
}

/*
bool eq_vecd2(int n, double * v1, double * v2, double err)
{
    if(fabs(d1 - d2) > err)
        return false
    return true;
}

void assert_eqvd(int n, double * v1, double * v2, double err){
    if(eq_vecd(n, v1, v2, err) != true){
        print_vecd(n, v1);
        print_vecd(n, v2);
    }
}
*/

int main(void) {
    int info, ipiv2[2];
    float err = 1e-6;
    float x2[2], b2[2], c2[2];
    float a2x2[2][2];

	/* cblas */
	{
        x2[0] =  1.0;
        x2[1] = -2.0;
        assert_eqd(cblas_snrm2(2, x2, 1), sqrt(5.0), err);
    }

	/* lapacke */
	{
		/*
		sgesv

		Matrix vector multiply.
		*/
		{
			a2x2[0][0] = 1.0;
			a2x2[1][0] = 2.0;
			a2x2[0][1] = 3.0;
			a2x2[1][1] = 4.0;
			b2[0] = 5.;
			b2[1] = 11.;

			info = LAPACKE_sgesv(
				LAPACK_COL_MAJOR,
				2,
				1,
				&a2x2[0][0],
				2,
				&ipiv2[0],
				&b2[0],
				2
			);
			c2[0] = 1.0;
			c2[1] = 2.0;
			assert_eqi(info, 0);
			assert_eqd(b2[0], c2[0], err);
			assert_eqd(b2[1], c2[1], err);
		}
    }

    return EXIT_SUCCESS;
}


#include <stdio.h>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_matrix.h>
#include <gsl/gsl_odeiv.h>

#include <GL/glut.h>

#define SLICE	360

int *jac;

int rhs (double t, const double y[], double f[], void *params_ptr);
//int jacobian (double t, const double y[], double *dfdy, double dfdt[], void *params_ptr);

void draw_differential_eq_plot(void);
void draw_lattice(void);

typedef struct _xy_plot xy_plot;
struct _xy_plot
{
	double x;
	double y;
};

xy_plot plot_res[1001];

void display(void)
{
	glClearColor(0.0, 0.0, 0.0, 1.0);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glLoadIdentity();

	glColor3f(1, 0, 0);

	glBegin(GL_LINE_LOOP);
	glVertex3f(100.0, 0.0, 0.0);
        glVertex3f(-100.0, 0.0, 0.0);
        glEnd();

        glColor3f(0.0, 1.0, 0.0);

        glBegin(GL_LINE_LOOP);
        glVertex3f(0.0, 100.0, 0.0);
        glVertex3f(0.0, -100.0, 0.0);
    glEnd();

	draw_differential_eq_plot();
	draw_lattice();
	glutSwapBuffers();
}

void reshape(int w, int h)
{
    GLfloat n_range = 100.0f;

    if(h == 0)
        h = 1;

    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

#if 0
    if(w <= h)
        glOrtho(-n_range, n_range, -n_range * h / w, n_range * h / w, -n_range, n_range);
    else
        glOrtho(-n_range * w / h, n_range * w / h, -n_range, n_range, -n_range, n_range);
#endif

	glOrtho(-10, 10, -0.5, 0.5, -1, 1);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

int calc_vertices_num(void)
{
	double tmin = 0.0, tmax = 10.0, delta_t = 0.01;
	return (tmax - tmin) / delta_t;
}

void calc_differential_eq(void)
{
    int dimension = 2;		/* number of differential equations */

    double eps_abs = 1.e-8;	/* absolute error requested */
    double eps_rel = 1.e-10;	/* relative error requested */

    const gsl_odeiv_step_type *type_ptr = gsl_odeiv_step_rkf45;

    gsl_odeiv_step *step_ptr = gsl_odeiv_step_alloc (type_ptr, dimension);
    gsl_odeiv_control *control_ptr = gsl_odeiv_control_y_new (eps_abs, eps_rel);
    gsl_odeiv_evolve *evolve_ptr = gsl_odeiv_evolve_alloc (dimension);

    gsl_odeiv_system my_system;	/* structure with the rhs function, etc. */

    double mu = 10;		/* parameter for the diffeq */
    double y[2];			/* current solution vector */

    double t, t_next;		/* current and next independent variable */
    double tmin, tmax, delta_t;	/* range of t and step size for output */

    double h = 1e-6;		/* starting step size for ode solver */

	int cnt = 0;
	int vertex_num = calc_vertices_num();
#if 0
	double res_x[vertex_num + 1] = {0};
	double res_y[vertex_num + 1] = {0};

	double *res_x = (double *)malloc(sizeof(double) * (vertex_num + 1));
	double *res_y = (double *)malloc(sizeof(double) * (vertex_num + 1));
#endif

    my_system.function = rhs;	/* the right-hand-side functions dy[i]/dt */
    my_system.jacobian = NULL;
    my_system.dimension = dimension;	/* number of diffeq's */
    my_system.params = NULL;

    tmin = 0.;			/* starting t value */
    tmax = 10.;			/* final t value */
    delta_t = 0.01;

    y[0] = 0.16;			/* initial x value */
    y[1] = 0.;			/* initial v value */

    t = tmin;             /* initialize t */
    printf ("%.5e %.5e %.5e\n", t, y[0], y[1]);	/* initial values */

    for (t_next = tmin + delta_t; t_next <= tmax; t_next += delta_t)
    {
        while (t < t_next)	/* evolve from t to t_next */
        {
            gsl_odeiv_evolve_apply (evolve_ptr, control_ptr, step_ptr,
                                    &my_system, &t, t_next, &h, y);
        }

		plot_res[cnt].x = t;
		plot_res[cnt].y = y[0];
        printf ("%.5e %.5e %.5e\n", t, plot_res[cnt].x, plot_res[cnt].y); /* print at t=t_next */

		cnt++;
    }

    gsl_odeiv_evolve_free (evolve_ptr);
    gsl_odeiv_control_free (control_ptr);
    gsl_odeiv_step_free (step_ptr);
}

void draw_lattice(void)
{
	int i;

	glColor3f(1, 1, 0);
	glBegin(GL_LINES);
		for (i = 1; i <= 10; i++)
		{
			glVertex2f(i, -0.01);
			glVertex2f(i, 0.01);
		}
	glEnd();
}

void draw_differential_eq_plot(void)
{
	float t = -100.0, step = 0.01;
	float x = 0, x2 = 0, y2, cx, cy;
	float tmp;
	int cache = 0;
	int i;

	glBegin(GL_LINES);
	//for(; ; t += step)
	for (i = 0; i < 1000; i++)
	{
		x2 = plot_res[i].x;
		y2 = plot_res[i].y;

		if(cache)
		{
			glVertex2f(cx, cy);	// 이전값
			glVertex2f(x2, y2);	// 현재값
		}

		cache = 1;
		cx = x2;
		cy = y2;
		printf("t = %f, y2 = %f\n", x2, y2);
	}
	glEnd();

}

int main (int argc, char **argv)
{
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE);
	glutInitWindowSize(800, 800);
	glutInitWindowPosition(0, 0);
	glutCreateWindow("Digital Signal Processing");

	calc_differential_eq();

	glutDisplayFunc(display);
	glutReshapeFunc(reshape);
	glutMainLoop();

    return 0;
}

/*************************** rhs ****************************/
/*
   x' = v                  ==>  dy[0]/dt = f[0] = y[1]
   v' = -x + \mu v (1-x^2) ==>  dy[1]/dt = f[1] = -y[0] + mu*y[1]*(1-y[0]*y[0])

   x''(t) + x'(t) + x(t) = 0
   x''(t) = -x'(t) - x(t)

   x' = v            ===> dy[0]/dt = f[0] = y[1]
   v' = -v - x       ===> dy[1]/dt = f[1] = -y[1] - y[0]
*/

// https://www.wolframalpha.com/input/?i=y%27%27+%2B+y%27+%2B+y+%3D+0%2C+y%280%29+%3D+1%2C+y%27%280%29+%3D+0, y(0) = 1
// https://www.wolframalpha.com/input/?i=%28sqrt%283%29+*+sin%28sqrt%283%29+%2F+2%29+%2B+3+*+cos%28sqrt%283%29+%2F+2%29%29+%2F+%283+*+sqrt%28e%29%29, y(1)
// (sqrt(3) * sin(sqrt(3) / 2) + 3 * cos(sqrt(3) / 2)) / (3 * sqrt(e)), y(1) = 0.6597001...
int
rhs (double t, const double y[], double f[], void *params_ptr)
{
	/*
    f[0] = y[1];
    f[1] = -y[0] + mu * y[1] * (1. - y[0] * y[0]);
	*/

	// 10 * y'' + 10 * y' + 90 * y = 0
	// y'' + y' + 9 * y = 0
	// y'' = - y' - 9 * y
	// 파이썬의 dsolve가 자체적으로 표준형을 만들어주는 반면
	// GSL의 경우 성능은 더 좋지만 이와 같은 작업을 사용자에게 위임하고 있음
	f[0] = y[1];
	f[1] = -y[1] - 9 * y[0];

    return GSL_SUCCESS;		/* GSL_SUCCESS defined in gsl/errno.h as 0 */
}

/*************************** Jacobian ****************************/
/*
*/

#if 0
int
jacobian (double t, const double y[], double *dfdy,
          double dfdt[], void *params_ptr)
{
    /* get parameter(s) from params_ptr; here, just a double */
    double mu = *(double *) params_ptr;

    gsl_matrix_view dfdy_mat = gsl_matrix_view_array (dfdy, 2, 2);

    gsl_matrix *m_ptr = &dfdy_mat.matrix;	/* m_ptr points to the matrix */

    /* fill the Jacobian matrix as shown */
    gsl_matrix_set (m_ptr, 0, 0, 0.0);	/* df[0]/dy[0] = 0 */
    gsl_matrix_set (m_ptr, 0, 1, 1.0);	/* df[0]/dy[1] = 1 */
    gsl_matrix_set (m_ptr, 1, 0, -2.0 * mu * y[0] * y[1] - 1.0); /* df[1]/dy[0] */
    gsl_matrix_set (m_ptr, 1, 1, -mu * (y[0] * y[0] - 1.0));     /* df[1]/dy[1] */

    /* set explicit t dependence of f[i] */
    dfdt[0] = 0.0;
    dfdt[1] = 0.0;

    return GSL_SUCCESS;		/* GSL_SUCCESS defined in gsl/errno.h as 0 */
}
#endif


/* Copyright (c) Facebook, Inc. and its affiliates.
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#include <cblas.h>
#include <complex.h>

#defmacro DEFINE_SVV(TNAME, TYPE, OPNAME, OPTEXT)

  #define OPER(a,b) OPTEXT

  TYPE TNAME##Vector_##OPNAME(TYPE *a, TYPE *b, int n)
  {
    /* try cblas */
  #if #TYPE == "float" && #OPNAME == "dot"
    return cblas_sdot(n, a, 1, b, 1);
  #elif #TYPE == "double" && #OPNAME == "dot"
    return cblas_ddot(n, a, 1, b, 1);
  #else
    int i;
    TYPE s = 0;
  # pragma unroll(i)
    for(i=0;i<n;i++)
      s += OPER(a[i],b[i]);
    return s;
  #endif
  }

#endmacro

#defmacro FORALLTYPES(macro,...)
  macro(Int, int, __VA_ARGS__)
  macro(Long, long, __VA_ARGS__)
  macro(Float, float, __VA_ARGS__)
  macro(Double, double, __VA_ARGS__)
  macro(Complex, complex double, __VA_ARGS__)
#endmacro

FORALLTYPES(DEFINE_SVV,dot,(a)*(b));
FORALLTYPES(DEFINE_SVV,sqrdist,((a)-(b))*((a)-(b)))

#define DEFINE_TYPEINFO(TNAME,TYPE) { #TNAME, #TYPE },
struct { const char *tname, *type; } typeInfo[] = {
  FORALLTYPES(DEFINE_TYPEINFO)
};


/* roots/demo1.c
 *
 * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 Reid Priedhorsky, 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 <stdio.h>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_math.h>
#include <gsl/gsl_roots.h>

#include "demof.h"
#include "demof.c"

int
main ()
{
  int status;
  int iterations = 0, max_iterations = 100;
  gsl_root_fdfsolver *s;
  double x0, x = 5.0, r_expected = sqrt (5.0);
  gsl_function_fdf FDF;
  struct quadratic_params params = {1.0, 0.0, -5.0};

  FDF.f = &quadratic;
  FDF.df = &quadratic_deriv;
  FDF.fdf = &quadratic_fdf;
  FDF.params = &params;

  s = gsl_root_fdfsolver_alloc (gsl_root_fdfsolver_newton);
  gsl_root_fdfsolver_set (s, &FDF, x);

  printf ("using %s method\n", gsl_root_fdfsolver_name (s));

  printf ("%-5s %10s %10s %10s %10s\n",
          "iter", "root", "actual", "err", "err(est)");
  do
    {
      iterations++;
      status = gsl_root_fdfsolver_iterate (s);
      x0 = x;
      x = gsl_root_fdfsolver_root (s);
      status = gsl_root_test_delta (x, x0, 0, 0.001);

      if (status == GSL_SUCCESS)
        printf ("Converged:\n");

      printf ("%5d %10.7f %10.7f %+10.7f %10.7f\n",
              iterations, x, r_expected, x - r_expected, x - x0);
    }
  while (status == GSL_CONTINUE && iterations < max_iterations);

}


#include <gsl/gsl_sf_hyperg.h>

#define kl 2
#define ll 3
#define alpha 1

double potential(double x) {
  return 0.5 * pow(alpha, 2) *
         (kl * (kl - 1) / pow(sin(alpha * x), 2) +
          ll * (ll - 1) / pow(cos(alpha * x), 2));
}
double ground_state_energy() { return 0.5 * pow(alpha, 2) * pow(kl + ll, 2); }
double exact(double x) {
  return pow(cos(alpha * x), ll) * pow(sin(alpha * x), kl) /
         sqrt(3.0 * M_PI / 512.0);
}

#undef V0
#undef kl
#undef ll
#undef alpha


#include <math.h>
#include <stdlib.h>
#include <gsl/gsl_integration.h>
//#include <stdio.h>

double f(double d, void* fdata){
    double * double_fdata = (double*) fdata;

    double par_obs = double_fdata[0];
    double var_par = double_fdata[1];
    double DM = double_fdata[2];
    double var_DM = double_fdata[3];
    double par_offset = double_fdata[4];
    double L = double_fdata[5];

    //printf("Data = %f, %f, %f, %f, %f\n", d, par_corrected, var_par, DM, var_DM);
    return pow(d, 2) * exp(-0.5 * (2*d/L + pow(par_obs - (1./d + par_offset), 2.)/var_par + pow(DM - (5*log10(d) - 5), 2.)/var_DM));
}

double integrate_likelihood(const double xmin, const double xmax, double *fdata, double rel_tolerance) {
    gsl_integration_workspace * w = gsl_integration_workspace_alloc (1000);

    gsl_function F;
    F.function = &f;
    F.params = fdata;

    double result, err;

    gsl_integration_qag (&F, xmin, xmax, 0, rel_tolerance, 1000, 1, w, &result, &err);

    gsl_integration_workspace_free (w);

    return result;
}


#include <stdio.h>
#include <stdlib.h>
#include <gsl/gsl_rstat.h>
#include <gsl/gsl_statistics.h>
#include <gsl/gsl_rng.h>
#include <gsl/gsl_randist.h>
#include <gsl/gsl_sort.h>

int
main(void)
{
  const size_t N = 10000;
  double *data = malloc(N * sizeof(double));
  gsl_rstat_quantile_workspace *work_25 = gsl_rstat_quantile_alloc(0.25);
  gsl_rstat_quantile_workspace *work_50 = gsl_rstat_quantile_alloc(0.5);
  gsl_rstat_quantile_workspace *work_75 = gsl_rstat_quantile_alloc(0.75);
  gsl_rng *r = gsl_rng_alloc(gsl_rng_default);
  double exact_p25, exact_p50, exact_p75;
  double val_p25, val_p50, val_p75;
  size_t i;

  /* add data to quantile accumulators; also store data for exact
   * comparisons */
  for (i = 0; i < N; ++i)
    {
      data[i] = gsl_ran_rayleigh(r, 1.0);
      gsl_rstat_quantile_add(data[i], work_25);
      gsl_rstat_quantile_add(data[i], work_50);
      gsl_rstat_quantile_add(data[i], work_75);
    }

  /* exact values */
  gsl_sort(data, 1, N);
  exact_p25 = gsl_stats_quantile_from_sorted_data(data, 1, N, 0.25);
  exact_p50 = gsl_stats_quantile_from_sorted_data(data, 1, N, 0.5);
  exact_p75 = gsl_stats_quantile_from_sorted_data(data, 1, N, 0.75);

  /* estimated values */
  val_p25 = gsl_rstat_quantile_get(work_25);
  val_p50 = gsl_rstat_quantile_get(work_50);
  val_p75 = gsl_rstat_quantile_get(work_75);

  printf ("The dataset is %g, %g, %g, %g, %g, ...\n",
         data[0], data[1], data[2], data[3], data[4]);

  printf ("0.25 quartile: exact = %.5f, estimated = %.5f, error = %.6e\n",
          exact_p25, val_p25, (val_p25 - exact_p25) / exact_p25);
  printf ("0.50 quartile: exact = %.5f, estimated = %.5f, error = %.6e\n",
          exact_p50, val_p50, (val_p50 - exact_p50) / exact_p50);
  printf ("0.75 quartile: exact = %.5f, estimated = %.5f, error = %.6e\n",
          exact_p75, val_p75, (val_p75 - exact_p75) / exact_p75);

  gsl_rstat_quantile_free(work_25);
  gsl_rstat_quantile_free(work_50);
  gsl_rstat_quantile_free(work_75);
  gsl_rng_free(r);
  free(data);

  return 0;
}


#include <gsl/gsl_complex.h>
#include <gsl/gsl_complex_math.h>
#include <stdio.h>
#include <stdlib.h>

#pragma comment(lib,"gsl")

int main(int argc, char** argv)
{
    gsl_complex a,b;
    GSL_SET_COMPLEX(&a,3,4);//a=3+4i
    GSL_SET_COMPLEX(&b,6,8);//b=6+8i
    gsl_complex c = gsl_complex_add(a,b);
    printf("a+b\treal : %f image : %f\n",c.dat[0],c.dat[1]);
    c = gsl_complex_sub(a,b);
    printf("a-b\treal : %f image : %f\n",c.dat[0],c.dat[1]);
    c = gsl_complex_mul(a,b);
    printf("a*b\treal : %f image : %f\n",c.dat[0],c.dat[1]);
    c = gsl_complex_div(a,b);
    printf("a/b\treal : %f image : %f\n",c.dat[0],c.dat[1]);
    // system("PAUSE");
    return 0;
}