Esercizi Montecarlo - Laboratorio di fisica moderna A|B 2020

In sostituzione delle misure di fisica moderna

Tool

Generatore di numeri casuali: conviene usare numpy.random

Esempio: 10 mila numeri casuali fra 0 e 1

In [1]:
import numpy as np
import matplotlib.pyplot as plt

# 10000 numeri casuali fra 0 e 1
numeri = np.random.rand(10000)

print("Shape dell'array numeri ->",numeri.shape)
plt.hist(numeri,50)
plt.show()
Shape dell'array numeri -> (10000,)

Esempio: contare quanti di questi sono maggiori di 0.6

In [3]:
maggiori = numeri > 0.6 # questa operazione risulta in un array di lunghezza uguale a quella di "numeri" con all'interno True and False
                        # è un array di booleani
    
totale = maggiori.sum()          # l'operazione di somma su un array di booleani considera True=1 e False=0

print(totale)
3917

1. Misura area (stima di $\pi$)

In [4]:
N = 1000

posiz_palla = 2*(np.random.rand(N)-0.5), 2*(np.random.rand(N)-0.5) 
palle_dentro = np.sqrt(posiz_palla[0]**2 + posiz_palla[1]**2) < 1 
dentro = palle_dentro.sum() # se si fa una somma su un array di booleani, True=1, False=0
stima = dentro/N*4
print(stima)
3.172
In [5]:
trial = np.logspace(1, 6, num=50, base=10).astype(int)
risultati=[]
for N in trial:
    posiz_palla = 2*(np.random.rand(N)-0.5), 2*(np.random.rand(N)-0.5) 
    palle_dentro = np.sqrt(posiz_palla[0]**2 + posiz_palla[1]**2)<1 
    dentro = palle_dentro.sum() # se si fa una somma su un array di booleani, True=1, False=0
    stima = dentro/N*4
    risultati.append(stima)
In [6]:
trial
Out[6]:
array([     10,      12,      15,      20,      25,      32,      40,
            51,      65,      82,     104,     132,     167,     212,
           268,     339,     429,     542,     686,     868,    1098,
          1389,    1757,    2222,    2811,    3556,    4498,    5689,
          7196,    9102,   11513,   14563,   18420,   23299,   29470,
         37275,   47148,   59636,   75431,   95409,  120679,  152641,
        193069,  244205,  308884,  390693,  494171,  625055,  790604,
       1000000])
In [7]:
fig, ax = plt.subplots(1,2, dpi=100, figsize=(12,5))
ax[0].plot(trial, risultati, 'sr--')
ax[0].axhline(y=np.pi,color='k', label=f'$\pi$={np.pi:.5f}...')
ax[0].set_xscale('log')
ax[0].set_ylabel('Stima $\pi$', fontsize=16)
ax[0].set_xlabel('N', fontsize=16)
ax[0].legend(fontsize=16)

ax[1].plot(trial, np.abs(np.array(risultati)-np.pi), 'sr--')
ax[1].set_yscale('log')
ax[1].set_xscale('log')
ax[1].set_ylabel('Precisione della stima', fontsize=16)
ax[1].set_xlabel('N', fontsize=16)
plt.show()
In [40]:
# plt.subplots(dpi=200, figsize=(10,10))
# plt.scatter(posiz_palla[0], posiz_palla[1], c=palle_dentro, s=0.001, cmap='seismic')

# plt.gcf().savefig('scatter.pdf')
# plt.show()

2. Random walk

In [10]:
# 1000 passi casuali di valore -1 oppure +1
passi = np.random.choice([-1,1], 1000000)
position = passi.cumsum()
print('Posizione media:',position.mean())
print('RMS posizione:', position.std())
Posizione media: -395.87084
RMS posizione: 659.4577219880698
In [11]:
trial = np.logspace(1, 6, num=20, base=10).astype(int)
passi = np.random.choice([-1,1], trial[-1])
risultati=[]
for N in trial:
    position = passi[:N].cumsum()
    risultati.append([position[:N].mean(),np.abs(position[:N]).max()])
    
risultati = np.array(risultati)
In [16]:
risultati[:,0], trial, passi.shape
Out[16]:
(array([ -2.5       ,  -2.83333333,  -1.54545455,  -1.19672131,
         -1.17857143,   1.07281553,   2.02638522,   2.56402878,
          5.03689168,  15.78843683,  31.12473721,  28.58187842,
          3.01237486,  47.05086096,  90.65606572,  96.26655453,
         43.97773699,  58.77273842,  84.85346589, 152.083336  ]),
 array([     10,      18,      33,      61,     112,     206,     379,
            695,    1274,    2335,    4281,    7847,   14384,   26366,
          48329,   88586,  162377,  297635,  545559, 1000000]),
 (1000000,))
In [12]:
fig = plt.figure(constrained_layout=True, figsize=(12,5), dpi=100)

gs = fig.add_gridspec(2, 2)
ax1 = fig.add_subplot(gs[:, 0])
ax2 = fig.add_subplot(gs[0, 1])
ax3 = fig.add_subplot(gs[1, 1])

ax1.plot(position, lw=1, color='r')
ax1.set_ylabel('posizione', fontsize=16)
ax1.set_xlabel('passi', fontsize=16)


ax2.plot(trial, risultati[:,0], 's--r',lw=1)
ax2.set_xscale('log')
ax2.axhline(y=0, lw=1, color='k')
ax2.set_ylabel('posizione media', fontsize=16)

ax3.plot(trial, risultati[:,1], 's--r',lw=1)
ax3.plot(trial, np.sqrt(trial), '-k', label='sqrt(N)', lw=1)
ax3.set_xscale('log')
ax3.set_yscale('log')
ax3.legend(fontsize=16)
ax3.set_ylabel('distanza', fontsize=16)
ax3.set_xlabel('N', fontsize=16)

plt.show()

3. Decadimenti esponenziali

In [5]:
N0=100000
p=0.1

Nresidui = N0
Nlist=[]
while Nresidui>N0/100:
    Nlist.append(Nresidui)
    dec_prob = np.random.rand(Nresidui)<p
    Nresidui -= dec_prob.sum()
    
Nlist = np.array(Nlist)
In [6]:
Nlist.shape
Out[6]:
(44,)
In [7]:
import scipy.optimize as opt

def expo(t, C, p):
    return C*np.exp(-p*t)
    
plt.subplots(dpi=100)
par, _ = opt.curve_fit(expo, np.arange(Nlist.size), Nlist, p0=[10000,0.1])
plt.plot(Nlist, 'sr')
x = np.arange(Nlist.size)
plt.plot(x, expo(x, 100000, 0.1), label='Fit: C $e^{-\\tau t}$ (C=%d, $\\tau$=%.2f)'% (par[0], par[1]), color='k')
plt.xlabel('tempo')
plt.ylabel('particelle')
plt.legend()
plt.show()
print(par)
[1.00102817e+05 1.05296029e-01]

Monty Hall problem

In [17]:
import numpy as np

premio = 'diamante'
no_premio = 'vuota'
In [18]:
# il conduttore del gioco nasconde un'auto dietro una porta
# 2 capre dietro le altre
conduttore = list(np.random.permutation([premio, no_premio, no_premio]))

# il giocatore sceglie una delle 3 porte
scelta_giocatore  = np.random.choice([0,1,2])
premio_giocatore = conduttore.pop(scelta_giocatore) # pop returns the object at INDEX position 
print('Situazione conduttore:',conduttore)
print('Situazione giocatore :',premio_giocatore)
Situazione conduttore: ['vuota', 'diamante']
Situazione giocatore : vuota
In [19]:
# il conduttore elimina una porta con la capra (mostrandola al giocatre)
# e chiede di scegliere: CAMBI O TIENI?

conduttore.remove(no_premio)

conduttore = conduttore[0] # stringa, non lista con 1 stringa
print('Situazione conduttore:',conduttore)
print('Situazione giocatore :',premio_giocatore)
Situazione conduttore: diamante
Situazione giocatore : vuota
In [22]:
# scelta del giocatore
scelta = 'cambia'

if scelta=='cambia':
    conduttore, premio_giocatore = premio_giocatore, conduttore
    
print('Situazione conduttore:',conduttore)
print('Situazione giocatore :',premio_giocatore,'-->','vince!' if premio_giocatore==premio else 'perde!')
Situazione conduttore: diamante
Situazione giocatore : vuota --> perde!

Loop

In [23]:
def gioca(N=1000, scelta = 'cambia'):
    
    vittorie = 0    
    for i in range(N):
        # piazza i premi
        conduttore = list(np.random.permutation([premio, no_premio, no_premio]))

        # il giocatore sceglie una delle 3 scatola
        scelta_giocatore  = np.random.choice([0,1,2])
        premio_giocatore = conduttore.pop(scelta_giocatore)
        # il conduttore rimuove dalle sue scatole una vuota
        conduttore.remove(no_premio)
        conduttore = conduttore[0] # stringa, non lista con 1 stringa
        # il conduttore propone lo scambio, se il giocatore ci sta
        # le scatole si scambiano
        if scelta=='cambia':
            conduttore, premio_giocatore = premio_giocatore, conduttore

        # esito
        if premio_giocatore==premio:
            vittorie +=1

    return vittorie
In [24]:
risultati={'tieni':[], 'cambia':[]}

for i in range(1000):
    risultati['tieni'].append(gioca(1000, 'tieni')/1000)
    risultati['cambia'].append(gioca(1000, 'cambia')/1000)
    
risultati['tieni'] = np.array(risultati['tieni'])
risultati['cambia'] = np.array(risultati['cambia'])
In [25]:
import matplotlib.pyplot as plt
In [26]:
for s in ['tieni', 'cambia']:
    plt.hist(risultati[s], 30, label=s+f' (media = {risultati[s].mean():.2f})')
    
plt.legend()
plt.show()
In [ ]: