def test_unbinned_maximum_likelihood(): ''' Test the "unbinned_maximum_likelihood" FCN. ''' # Simple fit to a Gaussian m = minkit.Parameter('m', bounds=(5, 15)) c = minkit.Parameter('c', 10., bounds=(5, 15)) s = minkit.Parameter('s', 1., bounds=(0.5, 2)) g = minkit.Gaussian('gaussian', m, c, s) data = g.generate(10000) with helpers.fit_test(g) as test: with minkit.minimizer('uml', g, data, minimizer='minuit') as minuit: test.result = minuit.migrad() # Add constraints cc = minkit.Parameter('cc', 10) sc = minkit.Parameter('sc', 0.1) gc = minkit.Gaussian('constraint', c, cc, sc) with helpers.fit_test(g) as test: with minkit.minimizer('uml', g, data, minimizer='minuit', constraints=[gc]) as minuit: test.result = minuit.migrad()
def test_unbinned_extended_maximum_likelihood(): ''' Test the "unbinned_extended_maximum_likelihood" FCN. ''' m = minkit.Parameter('m', bounds=(-5, +15)) # Create an Exponential PDF k = minkit.Parameter('k', -0.1, bounds=(-0.2, 0)) e = minkit.Exponential('exponential', m, k) # Create a Gaussian PDF c = minkit.Parameter('c', 10., bounds=(8, 12)) s = minkit.Parameter('s', 1., bounds=(0.5, 2)) g = minkit.Gaussian('gaussian', m, c, s) # Add them together ng = minkit.Parameter('ng', 10000, bounds=(0, 100000)) ne = minkit.Parameter('ne', 1000, bounds=(0, 100000)) pdf = minkit.AddPDFs.two_components('model', g, e, ng, ne) data = pdf.generate(int(ng.value + ne.value)) with helpers.fit_test(pdf) as test: with minkit.minimizer('ueml', pdf, data, minimizer='minuit') as minuit: test.result = minuit.migrad() # Add constraints cc = minkit.Parameter('cc', 10) sc = minkit.Parameter('sc', 1) gc = minkit.Gaussian('constraint', c, cc, sc) with helpers.fit_test(pdf) as test: with minkit.minimizer('ueml', pdf, data, minimizer='minuit', constraints=[gc]) as minuit: test.result = minuit.migrad()
def test_range(): ''' Test for disjointed ranges. ''' # Do calculations in a range m = minkit.Parameter('m', bounds=(0, 10)) k = minkit.Parameter('k', -0.5, bounds=(-0.8, -0.3)) e = minkit.Exponential('exponential', m, k) m.set_range('sides', [(0, 4), (6, 10)]) helpers.check_numerical_normalization(e, range='sides') data = e.generate(10000) with helpers.fit_test(e) as test: with minkit.minimizer('uml', e, data, minimizer='minuit', range='sides') as minuit: test.result = minuit.migrad() # Test generation of data only in the range data = e.generate(10000, range='sides') with helpers.fit_test(e) as test: with minkit.minimizer('uml', e, data, minimizer='minuit', range='sides') as minuit: test.result = minuit.migrad()
def test_range(): ''' Test the "Range" class. ''' # Simple constructor v = [(1, 2), (5, 6)] r = minkit.Range(v) assert np.allclose(r.bounds, v) # Do calculations in a range m = minkit.Parameter('m', bounds=(0, 10)) k = minkit.Parameter('k', -0.5, bounds=(-0.8, -0.3)) e = minkit.Exponential('exponential', m, k) m.set_range('sides', [(0, 4), (6, 10)]) assert np.allclose(e.norm(range='sides'), e.numerical_normalization(range='sides')) data = e.generate(10000) with helpers.fit_test(e) as test: with minkit.minimizer('uml', e, data, minimizer='minuit', range='sides') as minuit: test.result = minuit.migrad() # Test generation of data only in the range data = e.generate(10000, range='sides') with helpers.fit_test(e) as test: with minkit.minimizer('uml', e, data, minimizer='minuit', range='sides') as minuit: test.result = minuit.migrad()
def test_formulapdf(tmpdir): ''' Test the "FormulaPDF" class. ''' x = minkit.Parameter('x', bounds=(-2. * np.pi, +2 * np.pi)) a = minkit.Parameter('a', 1., bounds=(0.9, 1.1)) b = minkit.Parameter('b', 0., bounds=(-0.1, 0.1)) pdf = minkit.FormulaPDF.unidimensional('pdf', 'pow(sin(a * x + b), 2)', x, [a, b]) norm = pdf.norm() data = pdf.generate(10000) with helpers.fit_test(pdf) as test: with minkit.minimizer('uml', pdf, data) as minimizer: test.result = minimizer.migrad() # Include the integral pdf = minkit.FormulaPDF.unidimensional( 'pdf', 'pow(sin(a * x + b), 2)', x, [a, b], primitive='- sin(2 * (a * x + b)) -2 * (a * x + b) / (4 * a)') assert np.allclose(norm, pdf.norm()) with helpers.fit_test(pdf) as test: with minkit.minimizer('uml', pdf, data) as minimizer: test.result = minimizer.migrad() # In two dimensions x = minkit.Parameter('x', bounds=(0, 10)) y = minkit.Parameter('y', bounds=(0, 10)) ax = minkit.Parameter('ax', -0.01, bounds=(-1, 0)) ay = minkit.Parameter('ay', -0.01, bounds=(-1, 0)) pdf = minkit.FormulaPDF('pdf', 'exp(ax * x) * exp(ay * y)', [x, y], [ax, ay]) data = pdf.generate(10000) with helpers.fit_test(pdf) as test: with minkit.minimizer('uml', pdf, data) as minimizer: test.result = minimizer.migrad() # Test the JSON conversion with open(os.path.join(tmpdir, 'pdf.json'), 'wt') as fi: json.dump(minkit.pdf_to_json(pdf), fi) with open(os.path.join(tmpdir, 'pdf.json'), 'rt') as fi: p = minkit.pdf_from_json(json.load(fi)) check_pdfs(p, pdf)
def test_sweights(): ''' Test the "sweights" function. ''' m = minkit.Parameter('m', bounds=(0, +20)) # Create an Exponential PDF k = minkit.Parameter('k', -0.1, bounds=(-0.2, 0)) e = minkit.Exponential('exponential', m, k) # Create a Gaussian PDF c = minkit.Parameter('c', 10., bounds=(0, 20)) s = minkit.Parameter('s', 1., bounds=(0.1, 2)) g = minkit.Gaussian('gaussian', m, c, s) # Add them together ng = minkit.Parameter('ng', 10000, bounds=(0, 100000)) ne = minkit.Parameter('ne', 1000, bounds=(0, 100000)) pdf = minkit.AddPDFs.two_components('model', g, e, ng, ne) data = pdf.generate(int(ng.value + ne.value)) with minkit.minimizer('ueml', pdf, data, minimizer='minuit') as minuit: r = minuit.migrad() print(r) # Now we fix the parameters that are not yields, and we re-run the fit for p in (e, g): for a in p.args: a.constant = True with minkit.minimizer('ueml', pdf, data, minimizer='minuit') as minuit: r = minuit.migrad() print(r) result = minkit.minuit_to_registry(r.params) # Calculate the s-weights (first comes from the Gaussian, second from the exponential) sweights, V = minkit.sweights(pdf.pdfs, result.reduce(['ng', 'ne']), data, return_covariance=True) # The s-weights are normalized assert np.allclose(minkit.core.aop.sum(sweights[0]), result.get(ng.name).value) assert np.allclose(minkit.core.aop.sum(sweights[1]), result.get(ne.name).value) # The uncertainty on the yields is reflected in the s-weights assert np.allclose(minkit.core.aop.sum(sweights[0]**2), V[0][0]) assert np.allclose(minkit.core.aop.sum(sweights[1]**2), V[1][1])
def test_interppdf(tmpdir): ''' Test the InterpPDF class. ''' m = minkit.Parameter('m', bounds=(-3, +3)) centers = np.linspace(*m.bounds, 100) values = np.exp(-0.5 * centers**2) ip = minkit.InterpPDF.from_ndarray('ip', m, centers, values) ip.max() # check that we can calculate the maximum # Test the JSON conversion with open(os.path.join(tmpdir, 'ip.json'), 'wt') as fi: json.dump(minkit.pdf_to_json(ip), fi) with open(os.path.join(tmpdir, 'ip.json'), 'rt') as fi: p = minkit.pdf_from_json(json.load(fi)) check_pdfs(p, ip) # Check copying the PDF ip.copy() # Combine the PDF with another k = minkit.Parameter('k', -0.1, bounds=(-1, +1)) e = minkit.Exponential('exp', m, k) y = minkit.Parameter('y', 0.5, bounds=(0, 1)) pdf = minkit.AddPDFs.two_components('pdf', ip, e, y) data = pdf.generate(10000) with fit_test(pdf) as test: with minkit.minimizer('uml', pdf, data, minimizer='minuit') as minimizer: test.result = minimizer.migrad() bdata = data.make_binned(20) with fit_test(pdf) as test: with minkit.minimizer('bml', pdf, bdata, minimizer='minuit') as minimizer: test.result = minimizer.migrad() # Test the construction from a binned data set minkit.InterpPDF.from_binned_dataset('pdf', bdata)
def fit_and_check(fcn, minkit_model, minkit_data, roofit_model, roofit_data, constraints=None): ''' Fit the models of the two backends to a FCN and check that the results are the same. ''' if constraints is None: minkit_constraint, roofit_constraint = None, rt.RooFit.ExternalConstraints( rt.RooArgSet()) else: minkit_constraint, rc = constraints roofit_constraint = rt.RooFit.ExternalConstraints(rt.RooArgSet(*rc)) roofit_model.pdf.fitTo(roofit_data, rt.RooFit.Save(), roofit_constraint) with minkit.minimizer(fcn, minkit_model, minkit_data, constraints=minkit_constraint) as minimizer: minimizer.migrad() for p in roofit_model.args: # check that the value and errors coincide mp = minkit_model.args.get(p.GetName()) assert np.allclose(mp.value, p.getVal(), rtol=RTOL) assert np.allclose(mp.error, p.getError(), rtol=RTOL)
def test_constpdf(tmpdir): ''' Test a fit with a constant PDF. ''' pdf = helpers.default_add_pdfs(extended=False) # Check for "get_values" and "set_values" p = pdf.norm() pdf.set_values(**pdf.get_values()) assert np.allclose(p, pdf.norm()) # Test a simple fit data = pdf.generate(10000) with fit_test(pdf) as test: with minkit.minimizer('uml', pdf, data, minimizer='minuit') as minuit: test.result = minuit.migrad() # Test the JSON conversion with open(os.path.join(tmpdir, 'pdf.json'), 'wt') as fi: json.dump(minkit.pdf_to_json(pdf), fi) with open(os.path.join(tmpdir, 'pdf.json'), 'rt') as fi: s = minkit.pdf_from_json(json.load(fi)) check_multi_pdfs(s, pdf)
def test_minimization_profile(): ''' Test the calculation of minimization profiles by the minimizers. ''' pdf = helpers.default_gaussian('g', 'x', 'c', 's') args = pdf.args c = args.get('c') s = args.get('s') # Change the bounds to avoid evaluations to zero c.bounds = (-2, +2) data = pdf.generate(1000) cv = np.linspace(*c.bounds, 10) sv = np.linspace(*s.bounds, 10) mp = tuple(a.flatten() for a in np.meshgrid(cv, sv)) with minkit.minimizer('uml', pdf, data) as minimizer: minimizer.minimize() minimizer.minos_profile('c') minimizer.minimization_profile('c', cv) minimizer.minimization_profile(['c', 's'], mp)
def test_minimizer(): ''' Test the "minimizer" function ''' m = minkit.Parameter('m', bounds=(20, 80)) c = minkit.Parameter('c', 50, bounds=(30, 70)) s = minkit.Parameter('s', 5, bounds=(1, 10)) g = minkit.Gaussian('gaussian', m, c, s) initials = g.get_values() arr = np.random.normal(c.value, s.value, 10000) data = minkit.DataSet.from_array(arr, m) with helpers.fit_test(g) as test: with minkit.minimizer('uml', g, data, minimizer='minuit') as minuit: test.result = pytest.shared_result = minuit.migrad() pytest.shared_names = [p.name for p in g.all_args] # Unweighted fit to uniform distribution fails arr = np.random.uniform(*m.bounds, 100000) data = minkit.DataSet.from_array(arr, m) with minkit.minimizer('uml', g, data, minimizer='minuit') as minuit: r = minuit.migrad() print(r) reg = minkit.minuit_to_registry(r.params) assert not np.allclose(reg.get(s.name).value, initials[s.name]) # With weights fits correctly data.weights = minkit.as_ndarray(g(data)) with helpers.fit_test(g) as test: with minkit.minimizer('uml', g, data, minimizer='minuit') as minuit: test.result = minuit.migrad() # Test the binned case data = data.make_binned(bins=100) with helpers.fit_test(g) as test: with minkit.minimizer('bml', g, data, minimizer='minuit') as minuit: test.result = minuit.migrad()
def test_convpdfs(tmpdir): ''' Test the "ConvPDFs" class. ''' m = minkit.Parameter('m', bounds=(-20, +20)) # Create two Gaussians c1 = minkit.Parameter('c1', 0, bounds=(-2, +2)) s1 = minkit.Parameter('s1', 3, bounds=(0.5, +10)) g1 = minkit.Gaussian('g1', m, c1, s1) c2 = minkit.Parameter('c2', 0, bounds=(-2, +2)) s2 = minkit.Parameter('s2', 4, bounds=(0.5, +10)) g2 = minkit.Gaussian('g2', m, c2, s2) pdf = minkit.ConvPDFs('convolution', g1, g2) data = pdf.generate(10000) # Check that the output is another Gaussian with bigger standard deviation mean = minkit.core.aop.sum(data[m.name]) / len(data) var = minkit.core.aop.sum((data[m.name] - mean)**2) / len(data) assert np.allclose(var, s1.value**2 + s2.value**2, rtol=0.1) # Check that the normalization is correct with pdf.bind() as proxy: assert np.allclose(proxy.integral(), 1.) assert np.allclose(proxy.norm(), 1.) assert np.allclose(proxy.numerical_normalization(), 1.) # Ordinary check for PDFs values, edges = np.histogram(minkit.as_ndarray(data[m.name]), bins=100, range=m.bounds) centers = minkit.DataSet.from_array(0.5 * (edges[1:] + edges[:-1]), m) pdf_values = minkit.plotting.scaled_pdf_values(pdf, centers, values, edges) assert np.allclose(np.sum(pdf_values), np.sum(values), rtol=0.01) # Test a fit with fit_test(pdf) as test: with minkit.minimizer('uml', pdf, data, minimizer='minuit') as minuit: test.result = minuit.migrad() # Test the JSON conversion with open(os.path.join(tmpdir, 'pdf.json'), 'wt') as fi: json.dump(minkit.pdf_to_json(pdf), fi) with open(os.path.join(tmpdir, 'pdf.json'), 'rt') as fi: s = minkit.pdf_from_json(json.load(fi)) check_multi_pdfs(s, pdf)
def test_sweights(): ''' Test the "sweights" function. ''' pdf = helpers.default_add_pdfs(extended=True, yields=['ng', 'ne']) ng = pdf.args.get('ng') ne = pdf.args.get('ne') data = pdf.generate(int(ng.value + ne.value)) with helpers.fit_test(pdf) as test: with minkit.minimizer('ueml', pdf, data, minimizer='minuit') as minuit: test.result = minuit.migrad() # Now we fix the parameters that are not yields, and we re-run the fit for p in pdf.pdfs: for a in p.args: a.constant = True with helpers.fit_test(pdf) as test: with minkit.minimizer('ueml', pdf, data, minimizer='minuit') as minuit: test.result = minuit.migrad() result = pdf.args.copy() # Calculate the s-weights (first comes from the Gaussian, second from the exponential) sweights, V = minkit.sweights(pdf.pdfs, result.reduce(['ng', 'ne']), data, return_covariance=True) # The s-weights are normalized assert np.allclose(aop.sum(sweights[0]), result.get(ng.name).value) assert np.allclose(aop.sum(sweights[1]), result.get(ne.name).value) # The uncertainty on the yields is reflected in the s-weights assert np.allclose(aop.sum(sweights[0]**2), V[0][0]) assert np.allclose(aop.sum(sweights[1]**2), V[1][1]) # Check the calculation of the uncertainties of the s-weights minkit.sweights_u(data.values.as_ndarray(), sweights[0].as_ndarray())
def test_binned_chisquare(): ''' Test the "binned_chisquare" FCN. ''' # Single PDF m = minkit.Parameter('m', bounds=(0, 20)) c = minkit.Parameter('c', 10., bounds=(8, 12)) # all bins must be highly populated s = minkit.Parameter('s', 3., bounds=(2, 7)) g = minkit.Gaussian('gaussian', m, c, s) data = g.generate(10000) values, edges = np.histogram( data[m.name].as_ndarray(), range=m.bounds, bins=100) data = minkit.BinnedDataSet.from_ndarray(edges, m, values) with helpers.fit_test(g) as test: with minkit.minimizer('chi2', g, data) as minimizer: test.result = minimizer.migrad() # Many PDfs k = minkit.Parameter('k', -0.1, bounds=(-1, 0)) e = minkit.Exponential('exponential', m, k) ng = minkit.Parameter('ng', 10000, bounds=(0, 100000)) ne = minkit.Parameter('ne', 1000, bounds=(0, 100000)) pdf = minkit.AddPDFs.two_components('pdf', g, e, ng, ne) data = pdf.generate(int(ng.value + ne.value)) values, edges = np.histogram( data[m.name].as_ndarray(), range=m.bounds, bins=100) data = minkit.BinnedDataSet.from_ndarray(edges, m, values) with helpers.fit_test(pdf) as test: with minkit.minimizer('chi2', pdf, data) as minimizer: test.result = minimizer.migrad()
def test_scipyminimizer(): ''' Test the "SciPyMinimizer" class. ''' m = minkit.Parameter('m', bounds=(10, 20)) s = minkit.Parameter('s', 1, bounds=(0.5, 2)) c = minkit.Parameter('c', 15, bounds=(10, 20)) g = minkit.Gaussian('g', m, c, s) # Test the unbinned case data = g.generate(10000) values = [] with minkit.minimizer('uml', g, data, minimizer='scipy') as minimizer: for m in minkit.minimizers.SCIPY_CHOICES: values.append( minimizer.result_to_registry(minimizer.minimize(method=m))) with minkit.minimizer('uml', g, data, minimizer='minuit') as minimizer: reference = minkit.minuit_to_registry(minimizer.migrad().params) for reg in values: for p, r in zip(reg, reference): helpers.check_parameters(p, r, rtol=0.01) # Test the binned case data = data.make_binned(bins=100) values = [] with minkit.minimizer('bml', g, data, minimizer='scipy') as minimizer: for m in minkit.minimizers.SCIPY_CHOICES: values.append( minimizer.result_to_registry(minimizer.minimize(method=m))) with minkit.minimizer('bml', g, data, minimizer='minuit') as minimizer: reference = minkit.minuit_to_registry(minimizer.migrad().params) for reg in values: for p, r in zip(reg, reference): helpers.check_parameters(p, r, rtol=0.01)
def test_binned_extended_maximum_likelihood(): ''' Test the "binned_extended_maximum_likelihood" FCN. ''' pdf = helpers.default_add_pdfs(extended=True, yields=('ng', 'ne')) ntot = int(pdf.args.get('ng').value + pdf.args.get('ne').value) data = pdf.generate(ntot).make_binned(100) with helpers.fit_test(pdf) as test: with minkit.minimizer('beml', pdf, data) as minimizer: test.result = minimizer.migrad()
def test_restoring_state(): ''' Test that the state of the PDFs is treated correctly. ''' m = minkit.Parameter('m', bounds=(10, 20)) c = minkit.Parameter('c', 15, bounds=(10, 20)) s = minkit.Formula('s', '0.1 * {c}', [c]) g = minkit.Gaussian('g', m, c, s) data = g.generate(10000) with minkit.minimizer('uml', g, data) as minuit: minuit.migrad() result = g.args.copy() data = g.generate(10000) # new data set with g.restoring_state(), minkit.minimizer('uml', g, data) as minuit: minuit.migrad() # The values of the PDF must be those of the first minimization for f, s in zip(result, g.real_args): helpers.check_parameters(f, s)
def test_prodpdfs(tmpdir): ''' Test the "ProdPDFs" class. ''' # Create two Gaussians mx = minkit.Parameter('mx', bounds=(-5, +5)) cx = minkit.Parameter('cx', 0., bounds=(-2, +2)) sx = minkit.Parameter('sx', 1., bounds=(0.1, +3)) gx = minkit.Gaussian('gx', mx, cx, sx) my = minkit.Parameter('my', bounds=(-5, +5)) cy = minkit.Parameter('cy', 0., bounds=(-2, +2)) sy = minkit.Parameter('sy', 2., bounds=(0.5, +3)) gy = minkit.Gaussian('gy', my, cy, sy) pdf = minkit.ProdPDFs('pdf', [gx, gy]) # Test integration helpers.check_numerical_normalization(pdf) # Test consteness of the PDFs for p in gx.all_args: p.constant = True assert gx.constant and not pdf.constant for p in gy.all_args: p.constant = True assert pdf.constant # Test the JSON conversion with open(os.path.join(tmpdir, 'pdf.json'), 'wt') as fi: json.dump(minkit.pdf_to_json(pdf), fi) with open(os.path.join(tmpdir, 'pdf.json'), 'rt') as fi: s = minkit.pdf_from_json(json.load(fi)) check_multi_pdfs(s, pdf) # Check copying the PDF pdf.copy() # Do a simple fit for p in pdf.all_real_args: p.constant = False data = pdf.generate(10000) with fit_test(pdf) as test: with minkit.minimizer('uml', pdf, data) as minimizer: test.result = minimizer.migrad()
def fit(pdf, nevts, repetitions): ''' Generate data following the given model and fit it. ''' times = np.empty(repetitions, dtype=np.float64) initials = { p.name: np.random.uniform(*p.bounds) for p in pdf.all_real_args } for i in range(len(times)): data = pdf.generate(nevts) start = time.time() with minkit.minimizer('uml', pdf, data) as minimizer: minimizer.migrad() end = time.time() times[i] = end - start pdf.set_values(**initials) return times
def test_fcn_profile(): ''' Test the calculation of profiles by the minimizers. ''' pdf = helpers.default_gaussian('g', 'x', 'c', 's') args = pdf.args c = args.get('c') s = args.get('s') data = pdf.generate(1000) cv = np.linspace(*c.bounds, 10) sv = np.linspace(*s.bounds, 10) mp = tuple(a.flatten() for a in np.meshgrid(cv, sv)) with minkit.minimizer('uml', pdf, data) as minimizer: minimizer.fcn_profile('c', cv) minimizer.fcn_profile(['c', 's'], mp)
def test_formula(tmpdir): ''' Test the "Formula" class. ''' a = minkit.Parameter('a', 1) b = minkit.Parameter('b', 2) c = minkit.Formula('c', 'a * b', [a, b]) assert np.allclose(c.value, a.value * b.value) # Test its use on a PDF m = minkit.Parameter('m', bounds=(10, 20)) c = minkit.Parameter('c', 15, bounds=(10, 20)) s = minkit.Formula('s', '0.1 + c / 10', [c]) g = minkit.Gaussian('gaussian', m, c, s) data = g.generate(10000) nd = np.random.normal(c.value, s.value, 10000) compare_with_numpy(g, nd, m) with helpers.fit_test(g) as test: with minkit.minimizer('uml', g, data, minimizer='minuit') as minuit: test.result = minuit.migrad() # Test the JSON (only for formula) with open(os.path.join(tmpdir, 'r.json'), 'wt') as fi: json.dump(s.to_json_object(), fi) with open(os.path.join(tmpdir, 'r.json'), 'rt') as fi: s = minkit.Formula.from_json_object(json.load(fi), g.all_real_args) # Test the JSON (whole PDF) with open(os.path.join(tmpdir, 'pdf.json'), 'wt') as fi: json.dump(minkit.pdf_to_json(g), fi) with open(os.path.join(tmpdir, 'pdf.json'), 'rt') as fi: s = minkit.pdf_from_json(json.load(fi))
def test_constpdf(tmpdir): ''' Test a fit with a constant PDF. ''' m = minkit.Parameter('m', bounds=(0, 10)) # Create an Exponential PDF k = minkit.Parameter('k', -0.05) e = minkit.Exponential('exponential', m, k) # Create a Gaussian PDF c = minkit.Parameter('c', 5., bounds=(0, 10)) s = minkit.Parameter('s', 1., bounds=(0.5, 3)) g = minkit.Gaussian('gaussian', m, c, s) # Add them together g2e = minkit.Parameter('g2e', 0.5, bounds=(0, 1)) pdf = minkit.AddPDFs.two_components('model', g, e, g2e) # Check for "get_values" and "set_values" p = pdf.norm() pdf.set_values(**pdf.get_values()) assert np.allclose(p, pdf.norm()) # Test a simple fit data = pdf.generate(10000) with fit_test(pdf) as test: with minkit.minimizer('uml', pdf, data, minimizer='minuit') as minuit: test.result = minuit.migrad() # Test the JSON conversion with open(os.path.join(tmpdir, 'pdf.json'), 'wt') as fi: json.dump(minkit.pdf_to_json(pdf), fi) with open(os.path.join(tmpdir, 'pdf.json'), 'rt') as fi: s = minkit.pdf_from_json(json.load(fi)) check_multi_pdfs(s, pdf)
def test_formula(tmpdir): ''' Test the "Formula" class. ''' a = minkit.Parameter('a', 1) b = minkit.Parameter('b', 2) c = minkit.Formula('c', '{a} * {b}', [a, b]) assert np.allclose(c.value, a.value * b.value) # Test its use on a PDF m = minkit.Parameter('m', bounds=(10, 20)) c = minkit.Parameter('c', 15, bounds=(10, 20)) s = minkit.Formula('s', '0.1 + {c} / 10', [c]) g = minkit.Gaussian('gaussian', m, c, s) data = g.generate(10000) nd = rndm_gen.normal(c.value, s.value, 10000) compare_with_numpy(g, nd, m) with helpers.fit_test(g) as test: with minkit.minimizer('uml', g, data, minimizer='minuit') as minuit: test.result = minuit.migrad() # Test the JSON (only for formula) with open(os.path.join(tmpdir, 'r.json'), 'wt') as fi: json.dump(s.to_json_object(), fi) with open(os.path.join(tmpdir, 'r.json'), 'rt') as fi: s = minkit.Formula.from_json_object(json.load(fi), g.all_real_args) # Test the JSON (whole PDF) with open(os.path.join(tmpdir, 'pdf.json'), 'wt') as fi: json.dump(minkit.pdf_to_json(g), fi) with open(os.path.join(tmpdir, 'pdf.json'), 'rt') as fi: minkit.pdf_from_json(json.load(fi)) # Test the copy of a formula new_args = s.args.copy() assert all(not o is p for o, p in zip(s.args, s.copy(new_args).args)) # Test for a formula depending on another formula m = minkit.Parameter('m', bounds=(10, 20)) c = minkit.Parameter('c', 15, bounds=(10, 20)) d = minkit.Formula('d', '0.1 + {c} / 10', [c]) s = minkit.Formula('s', '2 * {d}', [d]) g = minkit.Gaussian('gaussian', m, c, s) assert s.value == 3.2 data = g.generate(10000) with helpers.fit_test(g) as test: with minkit.minimizer('uml', g, data, minimizer='minuit') as minuit: test.result = minuit.migrad() # Test the JSON (only for formula) with open(os.path.join(tmpdir, 'r.json'), 'wt') as fi: json.dump(s.to_json_object(), fi) with open(os.path.join(tmpdir, 'r.json'), 'rt') as fi: s = minkit.Formula.from_json_object(json.load(fi), g.all_args) # Test the copy of a formula depending on another formula new_args = s.args.copy() assert all(not o is p for o, p in zip(s.args, s.copy(new_args).args)) # Test the JSON (whole PDF) with open(os.path.join(tmpdir, 'pdf.json'), 'wt') as fi: json.dump(minkit.pdf_to_json(g), fi) with open(os.path.join(tmpdir, 'pdf.json'), 'rt') as fi: minkit.pdf_from_json(json.load(fi))
def test_blinding(tmpdir): ''' Test fits with blinded parameters. ''' iv, ib = 1., (0, 2) p = minkit.Parameter('p', value=iv, bounds=ib) p.set_blinding_configuration(scale=10, offset=2) assert not np.allclose(p.value, iv) # value is hidden assert not np.allclose(p.bounds, ib) # bounds are hidden with p.blind(status=False): assert np.allclose(p.value, iv) assert np.allclose(p.bounds, ib) hv = p.value # Test the blinding state in JSON files with open(os.path.join(tmpdir, 'p.json'), 'wt') as fi: json.dump(p.to_json_object(), fi) with open(os.path.join(tmpdir, 'p.json'), 'rt') as fi: pn = minkit.Parameter.from_json_object(json.load(fi)) assert not np.allclose(pn.value, iv) # value is still hidden assert np.allclose(pn.value, hv) # blinded value is the same as before assert not np.allclose(pn.bounds, ib) # bounds are still hidden with pn.blind(status=False): assert np.allclose(pn.value, iv) assert np.allclose(pn.bounds, ib) # Gaussian model with a blinded center pdf = helpers.default_gaussian(center='c') data = pdf.generate(10000) c = pdf.args.get('c') iv = c.value # initial value ib = c.bounds # initial bounds initial = pdf.get_values() c.set_blinding_configuration(scale=10, offset=2) for m in 'minuit', 'L-BFGS-B', 'COBYLA': # test all the minimizers with c.blind(status=False): pdf.set_values(**initial) helpers.randomize(pdf) with minkit.minimizer('uml', pdf, data) as minimizer: minimizer.minimize() assert not np.allclose(c.value, iv) with c.blind(status=False): assert np.allclose(c.value, iv, atol=2. * c.error) assert np.allclose(c.bounds, ib) # Model composed by a background and a signal component with unknown yield pdf = helpers.default_add_pdfs(extended=True, yields=('nsig', 'nbkg')) nsig = pdf.args.get('nsig') nbkg = pdf.args.get('nbkg') nsig.value = 1000 nbkg.value = 10000 data = pdf.generate(int(nsig.value + nbkg.value)) nsig.bounds = 0.8 * nsig.value, len(data) nbkg.bounds = 0.8 * nbkg.value, len(data) iv = nsig.value nsig.set_blinding_configuration(scale=10000, offset=100) helpers.randomize(pdf) with minkit.minimizer('ueml', pdf, data) as minimizer: minimizer.minimize() assert not np.allclose(nsig.value, iv) with nsig.blind(status=False): assert np.allclose(nsig.value, iv, atol=2. * nsig.error) # Blinding using a formula f = minkit.Formula('f', '10 * {nsig}', [nsig]) pdf.args[pdf.args.index('nsig')] = f with nsig.blind(status=False): iv = nsig.value data = pdf.generate(int(f.value + nbkg.value)) helpers.randomize(pdf) with minkit.minimizer('ueml', pdf, data) as minimizer: minimizer.minimize() assert not np.allclose(nsig.value, iv) with nsig.blind(status=False): assert np.allclose(nsig.value, iv, atol=2. * nsig.error) # Test the determination of asymmetric errors and profiles with minkit.minimizer('ueml', pdf, data) as minimizer: minimizer.minuit.print_level = 0 minimizer.minimize() # FCN profile (a linear transformation makes the shapes of the profile # be the same) v = np.linspace(*nsig.bounds, 20) fp = minimizer.fcn_profile('nsig', v) mp = minimizer.minimization_profile('nsig', v) with nsig.blind(status=False): v = np.linspace(*nsig.bounds, 20) ufp = minimizer.fcn_profile('nsig', v) ump = minimizer.minimization_profile('nsig', v) assert np.allclose(fp, ufp) assert np.allclose(mp, ump) # asymmetric errors minimizer.asymmetric_errors('nsig') errors = nsig.asym_errors with nsig.blind(status=False): assert not np.allclose(errors, nsig.asym_errors) # minos errors minimizer.minos('nsig') errors = nsig.asym_errors with nsig.blind(status=False): assert not np.allclose(errors, nsig.asym_errors) # Check that with an offset-based blinding the error of the true value # is the same to that of the blinded. pdf = helpers.default_gaussian(center='c') data = pdf.generate(10000) c = pdf.args.get('c') c.set_blinding_configuration(offset=2) helpers.randomize(pdf) with minkit.minimizer('uml', pdf, data) as minimizer: minimizer.minimize() blinded = c.error with c.blind(status=False): unblinded = c.error assert np.allclose(blinded, unblinded) # Check that with an scale-based blinding the relative error of the true # value is the same to that of the blinded c.set_blinding_configuration(scale=100) helpers.randomize(pdf) with minkit.minimizer('uml', pdf, data) as minimizer: minimizer.minimize() blinded = c.error / c.value with c.blind(status=False): unblinded = c.error / c.value assert np.allclose(blinded, unblinded)
def test_convpdfs(tmpdir): ''' Test the "ConvPDFs" class. ''' m = minkit.Parameter('m', bounds=(-20, +20)) # Create two Gaussians c1 = minkit.Parameter('c1', 0, bounds=(-2, +2)) s1 = minkit.Parameter('s1', 3, bounds=(0.5, +10)) g1 = minkit.Gaussian('g1', m, c1, s1) c2 = minkit.Parameter('c2', 0, bounds=(-2, +2)) s2 = minkit.Parameter('s2', 4, bounds=(0.5, +10)) g2 = minkit.Gaussian('g2', m, c2, s2) pdf = minkit.ConvPDFs('convolution', g1, g2) data = pdf.generate(10000) # Check that the output is another Gaussian with bigger standard deviation mean = aop.sum(data[m.name]) / len(data) var = aop.sum((data[m.name] - mean)**2) / len(data) assert np.allclose(var, s1.value**2 + s2.value**2, rtol=0.1) # Ordinary check for PDFs values, edges = np.histogram(data[m.name].as_ndarray(), bins=100, range=m.bounds) centers = minkit.DataSet.from_ndarray(0.5 * (edges[1:] + edges[:-1]), m) pdf_values = minkit.utils.core.scaled_pdf_values(pdf, centers, values, edges) assert np.allclose(np.sum(pdf_values), np.sum(values), rtol=0.01) # Test a fit s2.constant = True # otherwise the minimization is undefined with fit_test(pdf) as test: with minkit.minimizer('uml', pdf, data, minimizer='minuit') as minuit: test.result = minuit.migrad() # Test the JSON conversion with open(os.path.join(tmpdir, 'pdf.json'), 'wt') as fi: json.dump(minkit.pdf_to_json(pdf), fi) with open(os.path.join(tmpdir, 'pdf.json'), 'rt') as fi: s = minkit.pdf_from_json(json.load(fi)) check_multi_pdfs(s, pdf) # Check copying the PDF pdf.copy() # Test for binned data samples bdata = data.make_binned(20) with fit_test(pdf) as test: with minkit.minimizer('bml', pdf, bdata, minimizer='minuit') as minuit: test.result = minuit.migrad()
def test_binned_maximum_likelihood(): ''' Tets the "binned_maximum_likelihood" FCN. ''' # Simple fit to a Gaussian m = minkit.Parameter('m', bounds=(5, 15)) c = minkit.Parameter('c', 10., bounds=(8, 12)) s = minkit.Parameter('s', 1., bounds=(0.5, 2)) g = minkit.Gaussian('gaussian', m, c, s) values, edges = np.histogram(np.random.normal(c.value, s.value, 10000), bins=100) data = minkit.BinnedDataSet.from_array(edges, m, values) with helpers.fit_test(g) as test: with minkit.minimizer('bml', g, data, minimizer='minuit') as minuit: test.result = minuit.migrad() # Add constraints cc = minkit.Parameter('cc', 10) sc = minkit.Parameter('sc', 0.1) gc = minkit.Gaussian('constraint', c, cc, sc) with helpers.fit_test(g) as test: with minkit.minimizer('bml', g, data, minimizer='minuit', constraints=[gc]) as minuit: test.result = minuit.migrad() # Test for a composed PDF k = minkit.Parameter('k', -0.1, bounds=(-1, 0)) e = minkit.Exponential('e', m, k) y = minkit.Parameter('y', 0.5, bounds=(0, 1)) pdf = minkit.AddPDFs.two_components('pdf', g, e, y) data = pdf.generate(10000) values, edges = np.histogram(minkit.as_ndarray(data[m.name]), bins=100) data = minkit.BinnedDataSet.from_array(edges, m, values) with helpers.fit_test(pdf) as test: with minkit.minimizer('bml', pdf, data) as minimizer: test.result = minimizer.migrad() # Test for a PDF with no "evaluate_binned" function defined m = minkit.Parameter('m', bounds=(0, 10)) a = minkit.Parameter('a', 0) theta = minkit.Parameter('theta', 2, bounds=(0, 3)) alpha = minkit.Parameter('alpha', 0.5) beta = minkit.Parameter('beta', 2) pdf = minkit.Amoroso('amoroso', m, a, theta, alpha, beta) data = pdf.generate(1000) values, edges = np.histogram(minkit.as_ndarray(data[m.name]), range=m.bounds, bins=100) data = minkit.BinnedDataSet.from_array(edges, m, values) with helpers.fit_test(pdf) as test: with minkit.minimizer('bml', pdf, data) as minimizer: test.result = minimizer.migrad()