Tutorial¶
Quickstart¶
Here is how to fit a simple likelihood function:
[1]:
paramnames = ['Hinz', 'Kunz']
def loglike(z):
return -0.5 * (((z - 0.5) / 0.01)**2).sum()
def transform(x):
return 10. * x - 5.
from snowline import ReactiveImportanceSampler
sampler = ReactiveImportanceSampler(paramnames, loglike, transform)
sampler.run()
[snowline] from: [0.57843083 0.54841861]
[snowline] error: [0.04 0.04]
FCN = 8.504590349689342e-06 | TOTAL NCALL = 33 | NCALLS = 33 |
EDM = 8.504597446812856e-06 | GOAL EDM = 5e-06 | UP = 0.5 |
Valid | Valid Param | Accurate Covar | PosDef | Made PosDef |
True | True | True | True | False |
Hesse Fail | HasCov | Above EDM | Reach calllim | |
False | True | False | False |
+ | Name | Value | Hesse Error | Minos Error- | Minos Error+ | Limit- | Limit+ | Fixed? |
0 | x0 | 0.550004 | 0.001 | 0 | 1 | No | ||
1 | x1 | 0.55 | 0.000999999 | 0 | 1 | No |
Maximum likelihood: L = -0.0 at:
Hinz 0.5000 +- 0.0100
Kunz 0.5000 +- 0.0100
+ | Name | Value | Hesse Error | Minos Error- | Minos Error+ | Limit- | Limit+ | Fixed? |
0 | x0 | 0.550004 | 0.001 | 0 | 1 | No | ||
1 | x1 | 0.55 | 0.000999999 | 0 | 1 | No |
+ | x0 | x1 |
x0 | 1.00 | -0.00 |
x1 | -0.00 | 1.00 |
[snowline] using correlated errors ...
[snowline] Initiating gaussian importance sampler
[snowline] sampling 400 ...
[snowline] sampling efficiency: 66.859%
[snowline] Optimizing proposal (from scratch) ...
[snowline] running variational Bayes ...
[snowline] reduced from 11 to 1 components
[snowline] Importance sampling 400 ...
[snowline] Likelihood function evaluations: 1254
[snowline] Status: Have 664 total effective samples, done.
logZ = -12.004 +- 0.016
Hinz 0.5002 +- 0.0093
Kunz 0.5001 +- 0.0094
[1]:
{'z': 6.121768494660925e-06,
'zerr': 9.778365113340843e-08,
'logz': -12.003659533467909,
'logzerr': 0.01584687737856605,
'ess': 0.8306634927133046,
'paramnames': ['Hinz', 'Kunz'],
'ncall': 1254,
'posterior': {'mean': [0.5002100640679656, 0.500095357345468],
'stdev': [0.009324597600373989, 0.009429434293540989],
'median': [0.5002633361636803, 0.5000592725506969],
'errlo': [0.4908281363332101, 0.4908949130735021],
'errup': [0.5096153847101901, 0.5095015916628629]},
'samples': array([[0.51847607, 0.50031419],
[0.48916595, 0.4964772 ],
[0.48966908, 0.49609046],
...,
[0.50308996, 0.52098058],
[0.48078254, 0.49163388],
[0.51788436, 0.49042943]])}
This gave us error estimates and even estimated the evidence (Z)!
[2]:
print("Loglikelihood was called %d times." % sampler.results['ncall'])
Loglikelihood was called 1254 times.
Visualisation¶
[3]:
import corner
corner.corner(sampler.results['samples'], labels=paramnames, show_titles=True);
[3]:
Advanced usage¶
Lets try a function that cannot be described by a simple gaussian.
[4]:
paramnames = ['Hinz', 'Kunz'] #, 'Fuchs', 'Gans', 'Hofer']
def loglike_rosen(theta):
a = theta[:-1]
b = theta[1:]
return -2 * (100 * (b - a**2)**2 + (1 - a)**2).sum()
def transform_rosen(u):
return u * 20 - 10
sampler = ReactiveImportanceSampler(paramnames, loglike_rosen, transform=transform_rosen)
sampler.run(min_ess=1000, max_ncalls=1000000)
[snowline] from: [0.58502399 0.64137597]
[snowline] error: [0.04 0.04]
FCN = 1.5438574401618172e-05 | TOTAL NCALL = 108 | NCALLS = 108 |
EDM = 1.532095749260301e-05 | GOAL EDM = 5e-06 | UP = 0.5 |
Valid | Valid Param | Accurate Covar | PosDef | Made PosDef |
True | True | True | True | False |
Hesse Fail | HasCov | Above EDM | Reach calllim | |
False | True | False | False |
+ | Name | Value | Hesse Error | Minos Error- | Minos Error+ | Limit- | Limit+ | Fixed? |
0 | x0 | 0.550057 | 0.0244292 | 0 | 1 | No | ||
1 | x1 | 0.550102 | 0.0489189 | 0 | 1 | No |
Maximum likelihood: L = -0.0 at:
Hinz 1.00 +- 0.49
Kunz 1.00 +- 0.98
+ | Name | Value | Hesse Error | Minos Error- | Minos Error+ | Limit- | Limit+ | Fixed? |
0 | x0 | 0.550057 | 0.0245552 | 0 | 1 | No | ||
1 | x1 | 0.550102 | 0.0491707 | 0 | 1 | No |
+ | x0 | x1 |
x0 | 1.00 | 1.00 |
x1 | 1.00 | 1.00 |
[snowline] using correlated errors ...
[snowline] Initiating gaussian importance sampler
[snowline] sampling 400 ...
[snowline] sampling efficiency: 7.636%
[snowline] Optimizing proposal (from scratch) ...
[snowline] running variational Bayes ...
[snowline] reduced from 9 to 5 components
[snowline] Importance sampling 400 ...
[snowline] Likelihood function evaluations: 1331
[snowline] Status: Have 199 total effective samples, sampling 560 next.
[snowline] sampling efficiency: 24.939%
[snowline] Optimizing proposal (from previous) ...
[snowline] running variational Bayes ...
[snowline] reduced from 9 to 4 components
[snowline] Importance sampling 560 ...
[snowline] Likelihood function evaluations: 1891
[snowline] Status: Have 468 total effective samples, sampling 784 next.
[snowline] sampling efficiency: 34.464%
[snowline] Optimizing proposal (from previous) ...
[snowline] running variational Bayes ...
[snowline] reduced from 9 to 4 components
[snowline] Importance sampling 784 ...
[snowline] Likelihood function evaluations: 2675
[snowline] Status: Have 807 total effective samples, sampling 1097 next.
[snowline] sampling efficiency: 37.652%
[snowline] Optimizing proposal (from scratch) ...
[snowline] running variational Bayes ...
[snowline] reduced from 9 to 3 components
[snowline] Importance sampling 1097 ...
[snowline] Likelihood function evaluations: 3772
[snowline] Status: Have 227 total effective samples, sampling 1535 next.
logZ = -8.186 +- 0.062
Hinz 0.93 +- 0.28
Kunz 0.94 +- 0.53
[4]:
{'z': 0.0002785050719200497,
'zerr': 1.7797202105897182e-05,
'logz': -8.186074287200647,
'logzerr': 0.061943858528078266,
'ess': 0.07027069704402318,
'paramnames': ['Hinz', 'Kunz'],
'ncall': 3772,
'posterior': {'mean': [0.9308315565168493, 0.9425510318025457],
'stdev': [0.28222458477378715, 0.5292537458321681],
'median': [0.934488248709286, 0.861655340503269],
'errlo': [0.5850081520267452, 0.3567512519148064],
'errup': [1.2499902303602202, 1.5484353582945574]},
'samples': array([[0.50018225, 0.20881789],
[1.26036353, 1.53925363],
[1.23306765, 1.4992189 ],
...,
[0.75975621, 0.55314246],
[0.57646141, 0.43793153],
[1.14470524, 1.24144435]])}
This already took quite a bit more effort.
[5]:
print("Loglikelihood was called %d times." % sampler.results['ncall'])
Loglikelihood was called 3772 times.
Lets see how well it did:
[6]:
from getdist import MCSamples, plots
import matplotlib.pyplot as plt
samples_g = MCSamples(samples=sampler.results['samples'],
names=sampler.results['paramnames'],
label='Gaussian',
settings=dict(smooth_scale_2D=3), sampler='nested')
mcsamples = [samples_g]
Removed no burn in
[7]:
import numpy as np
x = np.linspace(-0.5, 4, 100)
a, b = np.meshgrid(x, x)
z = -2 * (100 * (b - a**2)**2 + (1 - a)**2)
g = plots.get_single_plotter()
g.plot_2d(mcsamples, paramnames)
plt.contour(a, b, z, [-3, -2, -1], cmap='Reds')
plt.xlim(-0.5, 2)
plt.ylim(-0.5, 4);
[7]:
(-0.5, 4.0)
As you can see, the importance sampler was not able to perfectly follow the rosenbrock curvature. But it is a good start to roughly understand the uncertainties!
[8]:
from getdist import MCSamples, plots
import matplotlib.pyplot as plt
samples_g = MCSamples(samples=sampler.results['samples'],
names=sampler.results['paramnames'],
label='Gaussian',
settings=dict(smooth_scale_2D=3), sampler='nested')
mcsamples = [samples_g]
g = plots.get_subplot_plotter(width_inch=8)
g.settings.num_plot_contours = 3
g.triangle_plot(mcsamples, filled=False, contour_colors=plt.cm.Set1.colors)
#corner.corner(sampler.results['samples'], labels=sampler.results['paramnames'], show_titles=True);
WARNING:root:auto bandwidth for Hinz very small or failed (h=0.00023964947577243358,N_eff=9109.0). Using fallback (h=0.0326216421999094)
WARNING:root:auto bandwidth for Kunz very small or failed (h=0.00024176046498490726,N_eff=9109.0). Using fallback (h=0.03182405112999413)
Removed no burn in