Soluzioni: Lezione 10

../_images/linea.png

10.1 - 10.3 determinazione del massimo della verosimiglianza

  • esercizio_01.cpp

/*
c++ -o esercizio_01 funzioni.cc casual.cc esercizio_01.cpp

Testo:
  Si scriva una libreria di funzioni per determinare il parametro τ della distribuzione 
  esponenziale utilizzata per generare gli eventi presenti nel file dati_esponenziali.txt, 
  a partire dal vector di numeri creato negli esercizi precedenti.

  Si implementino i prototipi delle funzioni presentate a lezione.
  Si confronti il risultato ottenuto con la media dei numeri salvati nel vector.
  Come dipende il risultato dall'intervallo inziale passato alla funzione sezione_aurea_max?
*/

#include <iostream>
#include <fstream>
#include <vector>
#include <cmath>

#include "statistiche_vector.h"
#include "funzioni.h"
#include "casual.h"

using namespace std ;

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

    if (argc < 2)
      {
        cerr << "uso: " << argv[0] << " numero_di_eventi [t_zero]" << endl ;
        exit (1) ;
      }

    double t_zero = 5. ;
    if (argc == 3) 
      {
        t_zero = atof (argv[2]) ;
      }

    vector<double> data ;
    for (int i = 0 ; i < atoi (argv[1]) ; ++i)
      {
        data.push_back (rand_exp (t_zero)) ;
      }

    cout << "generati " << data.size () << " eventi" << endl ;

    double media_v = media (data) ;
    cout << "media = " << media_v << endl ; 

    double massimo = sezione_aurea_max (loglikelihood, 0.5 * media_v, 1.5 * media_v, data) ;

    cout << "massimo della likelihood = " << massimo << endl ; 

    return 0 ;
}
  • casual.h

#ifndef casual_h
#define casual_h

double rand_range (double min, double max) ;

float rand_exp (double t_zero) ;

float rand_pois (double media) ;

double rand_IFC_Exp (double mu) ;

#endif
  • casual.cc

#include "casual.h"
#include <cstdlib>
#include <cmath>

double rand_range (double min, double max)
{
  return min + (max - min) * rand () / static_cast<double> (RAND_MAX);
}

float rand_exp (double t_zero)
{
  return -1. * log (1 - rand_range (0., 1.)) * t_zero ;
}

float rand_pois (double media) 
{
  double t_tot = rand_exp (1.) ;
  int N_evt = 0 ;
  while (t_tot < media)
    {
      ++N_evt ;
      t_tot += rand_exp (1.) ;
    }
  return N_evt ;
}


// generazione numeri casuali con il metodo dell'inversa della funzione cumulativa
double rand_IFC_Exp (double mu)
{
  double y = rand_range (0., 1.) ;
  double x = -mu * log (1 - y) ;
  return x ;
}
  • funzioni.h

#ifndef funzioni_h
#define funzioni_h

#include <vector>

double esponenziale (double x, double tau) ;

double loglikelihood (
  const std::vector<double> & data, 
  double param
) ;

double loglikelihoodprod (
  const std::vector<double> & data, 
  double param
) ;

double sezione_aurea_max (
  double logl (const std::vector<double> & , double),
  double xMin,
  double xMax,
  const std::vector<double> & data,
  double precision = 0.0001
) ;

double h (
  const std::vector<double> & data, 
  double param,
  double max
) ;

double bisezione (
  double h (const std::vector<double> & , double, double),
  double xMin,
  double xMax,
  const std::vector<double> & data,
  double massimo,
  double precision = 0.0001
) ;

#endif
  • funzioni.cc

#include "funzioni.h"
#include <cmath>
#include <iostream>

using namespace std ;

double esponenziale (double x, double tau)
{
   if (tau == 0.) return 1. ;
   return exp (-1. * x / tau) / tau ;
}


// ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- 


double loglikelihood (
  const vector<double> & data, 
  double param
)
{
  double result = 0. ; 
  for (int i = 0 ; i < data.size () ; ++i) result += log (esponenziale (data.at (i), param)) ;
  return result ;   
}

// ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- 


double loglikelihoodprod (
  const vector<double> & data, 
  double param
)
{
  double result = 1. ; 
  for (int i = 0 ; i < data.size () ; ++i) result *= esponenziale (data.at (i), param) ;
  return log (result) ;   
}


// ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- 
  

double sezione_aurea_max (
  double logl (const vector<double> & , double),
  double xMin,
  double xMax,
  const vector<double> & data,
  double precision
)
{
  double x_2 = xMin ;
  double x_3 = xMax ;
  while ((xMax - xMin) > precision)
    {
      x_2 = xMin + (xMax - xMin) * 0.618 ;
      x_3 = xMin + (xMax - xMin) * 0.382 ;

      if (logl (data, x_3) < logl (data, x_2)) xMin = x_3 ;
      else                                     xMax = x_2 ;
//      cout << "estremi " << xMin << "\t" << xMax << "\t" << xMax - xMin << "\n" ;

    }
  return 0.5 * (xMax + xMin) ;
}


// ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- 


double h (
  const vector<double> & data, 
  double param,
  double max
)
{
  return loglikelihood (data, param) + 0.5 - loglikelihood (data, max) ;   
}


// ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- 
  

double bisezione (
  double h (const vector<double> & , double, double),
  double xMin,
  double xMax,
  const vector<double> & data,
  double massimo,
  double precision
)
{
  double xAve = xMin ;
  while ((xMax - xMin) > precision)
    {
      xAve = 0.5 * (xMax + xMin) ;
      if (h (data, xAve, massimo) * h (data, xMin, massimo) > 0.) xMin = xAve ;
      else                                                        xMax = xAve ;
    }
  return xAve ;
}
../_images/linea.png

10.4 varianza dello stimatore ottenuto

  • esercizio_04.cpp

/*
c++ -o esercizio_04 funzioni.cc casual.cc esercizio_04.cpp

Testo:

Si utilizzi il metodo della bisezione per trovare i due punti τ - στ e τ + στ nel caso 
dell'esercizio precedente.

Si confronti il valore di στ ottenuto in questo modo con quello calcolato a partire
dalla media aritmetica dei numeri salvati nel vector
*/

#include <iostream>
#include <fstream>
#include <vector>
#include <cmath>

#include "statistiche_vector.h"
#include "funzioni.h"
#include "casual.h"

using namespace std ;

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

    if (argc < 2)
      {
        cerr << "uso: " << argv[0] << " numero_di_eventi [t_zero]" << endl ;
        exit (1) ;
      }

    double t_zero = 5. ;
    if (argc == 3) 
      {
        t_zero = atof (argv[2]) ;
      }

    vector<double> data ;
    for (int i = 0 ; i < atoi (argv[1]) ; ++i)
      {
        data.push_back (rand_exp (t_zero)) ;
      }

    cout << "generati " << data.size () << " eventi" << endl ;

    double media_v = media (data) ;
    cout << "media = " << media_v << endl ; 

    double massimo = sezione_aurea_max (loglikelihood, 0.5 * media_v, 1.5 * media_v, data) ;

    cout << "massimo della likelihood = " << massimo << endl ; 

    double zero_sx = bisezione (h, 0.5 * media_v, massimo, data, massimo) ;
    double zero_dx = bisezione (h, massimo, 1.5 * media_v, data, massimo) ;

    cout << "zero_sx = " << zero_sx << endl ;
    cout << "zero_dx = " << zero_dx << endl ;

    cout << "sigma = " << 0.5 * (zero_dx - zero_sx) << endl ;
    cout << "sigma stimata = " << media_v / sqrt (data.size ()) << endl ;

    return 0 ;
}
  • statistiche_vector.h

#ifndef statistiche_vector_h
#define statistiche_vector_h

#include <vector>

template <class T>
T media (const std::vector<T> & input_v) 
{
  T somma = 0 ;
  for (int i = 0 ; i < input_v.size () ; ++i) somma += input_v.at (i) ;
  return somma / static_cast<float> (input_v.size ()) ;
}


template <class T>
T varianza (const std::vector<T> & input_v) 
{
  T somma = 0 ;
  T sommaSq = 0 ;
  for (int i = 0 ; i < input_v.size () ; ++i) 
    {
      somma += input_v.at (i) ;
      sommaSq += input_v.at (i) * input_v.at (i) ;
    }  
  return sommaSq / static_cast<float> (input_v.size ()) - 
         (somma / static_cast<float> (input_v.size ()) * somma / static_cast<float> (input_v.size ())) ;
}


#endif
../_images/linea.png

10.5 distribuzione di probabilità dello stimatore ottenuto

  • esercizio_05.cpp

/*
c++ -o esercizio_05 `root-config --glibs --cflags` funzioni.cc casual.cc esercizio_05.cpp

Testo:
  Utilizzando il generatore di numeri pseudo-casuali secondo una pdf esponenziale sviluppato nella 
  Lezione 4, si disegni la distribuzione di probabilita' dello stimatore di τ in funzione del numero 
  di eventi a disposizione per la stima.
*/

#include <iostream>
#include <fstream>
#include <vector>
#include <cmath>

#include "TH1F.h"
#include "TCanvas.h"
#include "TApplication.h"

#include "statistiche_vector.h"
#include "funzioni.h"
#include "casual.h"

using namespace std ;

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

    if (argc < 2)
      {
        cerr << "uso: " << argv[0] << " mu_true numero_di_eventi [numero_di_toy = 10000]" << endl ;
        exit (1) ;
      }

    double mu_true = atof (argv[1]) ;
    int numero_eventi = atoi (argv[2]) ;

    int N_toys = 10000 ;
    if (argc > 3) N_toys = atoi (argv[3]) ;

    TApplication theapp ("theapp", 0, 0) ;

    TH1F h_max (
        "h_max", "max likelihood distribution", 
        N_toys / 100, 
        mu_true - 3 * mu_true / sqrt (numero_eventi),
        mu_true + 3 * mu_true / sqrt (numero_eventi)
      ) ;

    for (int i_toy = 0 ; i_toy < N_toys ; ++i_toy)
      {
        if (i_toy % 1000 == 0) cout << "running toy " << i_toy << endl ;
        vector<double> data_loc ;
        for (int i_sample = 0 ; i_sample < numero_eventi ; ++i_sample)
          {
            data_loc.push_back (rand_IFC_Exp (mu_true)) ;
          } 

        double media_v = media (data_loc) ;
        double sigma_subsample = media_v / sqrt (data_loc.size ()) ;
        double massimo = sezione_aurea_max (loglikelihood, 0.5 * media_v, 1.5 * media_v, data_loc) ;
        h_max.Fill (massimo) ;
      }

    h_max.SetLineColor (kGray) ;
    h_max.SetFillColor (kOrange + 1) ;
    h_max.GetXaxis ()->SetTitle ("stimatore di #tau") ;
    h_max.GetYaxis ()->SetTitle ("conteggi per bin") ;    
    TCanvas c1 ;
    c1.SetLeftMargin (0.10) ; 
    h_max.Draw () ;
    c1.Update();
    theapp.Run () ;

    return 0 ;
}
../_images/linea.png

10.6 limite asintotico

  • esercizio_06.cpp

/*
c++ -o esercizio_06 `root-config --glibs --cflags` funzioni.cc casual.cc esercizio_06.cpp

Testo:
    In regime asintotico, la distribuzione degli scarti (τ - τvero) / στ ha forma Normale.

    Si utilizzi il metodo dei toy experiment per riempire l'istogramma degli scarti, dato un numero di eventi per toy experiment.
    Si calcoli la media e la sigma della distribuzione degli scarti e se ne disegni il valore al variare del numero di eventi a 
    disposizione per la stima, riempiendo un TGraph con il numero di eventi a disposizione sull'asse orizziontale ed il valore 
    del parametro sull'asse verticale.
*/

#include <iostream>
#include <fstream>
#include <vector>
#include <cmath>

#include "TH1F.h"
#include "TCanvas.h"
#include "TApplication.h"
#include "TGraph.h"

#include "statistiche_vector.h"
#include "funzioni.h"
#include "casual.h"

using namespace std ;

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

    if (argc < 2)
      {
        cerr << "uso: " << argv[0] << " mu_true numero_di_eventi [numero_di_estrazioni = 10000]" << endl ;
        exit (1) ;
      }

    double mu_true = atof (argv[1]) ;

    int numero_eventi = 10000;
    if (argc > 2) numero_eventi = atoi (argv[2]) ;

    std::vector<int> N_toys_vec = {50, 100, 1000, 10000} ;

    TApplication theapp ("theapp", 0, 0) ;

    TGraph g;
    g.SetMarkerStyle(8);
    g.SetLineStyle(9);
    g.SetTitle(";Ntoys;(#tau - #hat{#tau})/#hat{#sigma_{#tau}}");

    std::vector<TH1F> histos;

    
    for(int idx = 0; idx < N_toys_vec.size(); ++idx)
      {
        int N_toys = N_toys_vec.at(idx);

        std::string h_name = "N_toy " + std::to_string(N_toys);

        TH1F h(
            h_name.c_str(), h_name.c_str(), 
            sqrt(N_toys), 
            -2,
            2
        ) ;

        h.SetLineColor(kBlue);
        h.SetFillColor(0);
        h.SetLineWidth(2);
        h.GetXaxis()->SetTitle("(#hat{#tau} - #tau) / #sigma_{#tau}");
        h.GetYaxis()->SetTitle("Events per bin");

        std::vector<double> pulls;

        for (int i_toy = 0 ; i_toy < N_toys ; ++i_toy)
        {
            if (i_toy % 1000 == 0) cout << "running toy " << i_toy << endl ;
            vector<double> data_loc ;
            for (int i_sample = 0 ; i_sample < numero_eventi ; ++i_sample)
            {
                data_loc.push_back (rand_IFC_Exp (mu_true)) ;
            } 

            double media_v = media (data_loc) ;
            double sigma_subsample = media_v / sqrt (data_loc.size ()) ;
            
            double pull = (mu_true - media_v) / sigma_subsample;
            pulls.push_back(pull);
            h.Fill(pull);
        }

        g.SetPoint(idx, N_toys, media(pulls));
        histos.push_back(h);

      }

    TCanvas c1 ;
    c1.Divide(2,2 , 0.0001, 0.0001);
    c1.SetLeftMargin (0.10) ; 
    for(int i = 0; i < N_toys_vec.size(); ++i){
        c1.cd(i+1);
        histos.at(i).Draw("hist");
    };
    c1.Update();

    TCanvas c2 ;
    c2.SetLogx();
    c2.SetLeftMargin (0.10) ; 
    g.Draw("APL");
    c2.Update();

    theapp.Run () ;

    return 0 ;
}
../_images/linea.png