Skip to content

Commit

Permalink
enh: upgrade to Python312
Browse files Browse the repository at this point in the history
  • Loading branch information
jonas-eschle committed Apr 16, 2024
1 parent db0a182 commit d22dbae
Show file tree
Hide file tree
Showing 11 changed files with 67 additions and 95 deletions.
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,10 @@ repos:
rev: 1.8.5
hooks:
- id: nbqa-isort
additional_dependencies: [ isort==5.6.4 ]
additional_dependencies: [ isort]

- id: nbqa-pyupgrade
additional_dependencies: [ pyupgrade==2.7.4 ]
additional_dependencies: [ pyupgrade]
args: [ --py38-plus ]


Expand Down
5 changes: 2 additions & 3 deletions environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,10 @@ dependencies:
- numpy
- scipy
- iminuit
- tensorflow>=2.4
- tensorflow-probability
#- zfit
#- zfit # todo: conda-forge is 0.18.1, we need 0.20.0
- asdf
- matplotlib
- pip:
- .
- zfit >=0.6.4
- zfit >=0.20.0
12 changes: 7 additions & 5 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ classifiers =
Programming Language :: Python
Programming Language :: Python :: 3
Programming Language :: Python :: 3 :: Only
Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9
Programming Language :: Python :: 3.10
Programming Language :: Python :: 3.11
Expand All @@ -43,7 +42,7 @@ install_requires =
scipy
tqdm
uhi
python_requires = >=3.8
python_requires = >=3.9
package_dir =
= src

Expand All @@ -52,8 +51,9 @@ where = src

[options.extras_require]
dev =
black
zfit
%(docs)s
%(test)s
pre-commit
docs =
matplotlib
pydata-sphinx-theme
Expand All @@ -65,7 +65,9 @@ test =
pytest
pytest-cov
pytest-runner
zfit
zfit>=0.20.0
zfit =
zfit>=0.20.0

[tool:pytest]
junit_family = xunit2
Expand Down
21 changes: 8 additions & 13 deletions src/hepstats/hypotests/hypotests_object.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import numpy as np

from .parameters import POI
from ..utils.fit import get_nevents
from ..utils.fit import get_nevents, set_values_once
from ..utils.fit.api_check import is_valid_data, is_valid_pdf
from ..utils.fit.api_check import is_valid_loss, is_valid_fitresult, is_valid_minimizer

Expand Down Expand Up @@ -117,8 +117,7 @@ def set_params_to_bestfit(self):
"""
Set the values of the parameters in the models to the best fit values
"""
for param in self.parameters:
param.set_value(self.bestfit.params[param]["value"])
set_values_once(self.parameters, self.bestfit)

def lossbuilder(self, model, data, weights=None, oldloss=None):
"""Method to build a new loss function.
Expand Down Expand Up @@ -156,7 +155,7 @@ def lossbuilder(self, model, data, weights=None, oldloss=None):

if weights is not None:
for d, w in zip(data, weights):
d.set_weights(w)
d = d.with_weights(w)

if hasattr(oldloss, "create_new"):
loss = oldloss.create_new(
Expand Down Expand Up @@ -193,15 +192,11 @@ def __init__(self, input, minimizer, sampler, sample):
self._sample = sample
self._toys_loss = {}

def sampler(self, floating_params=None):
def sampler(self):
"""
Create sampler with models.
Args:
floating_params: floating parameters in the sampler
Example with `zfit`:
>>> sampler = calc.sampler(floating_params=[zfit.Parameter("mean")])
>>> sampler = calc.sampler()
"""
self.set_params_to_bestfit()
nevents = []
Expand All @@ -214,7 +209,7 @@ def sampler(self, floating_params=None):
else:
nevents.append(nevents_data)

return self._sampler(self.loss.model, nevents, floating_params)
return self._sampler(self.loss.model, nevents)

def sample(self, sampler, ntoys, poi: POI, constraints=None):
"""
Expand All @@ -229,7 +224,7 @@ def sample(self, sampler, ntoys, poi: POI, constraints=None):
Example with `zfit`:
>>> mean = zfit.Parameter("mean")
>>> sampler = calc.sampler(floating_params=[mean])
>>> sampler = calc.sampler()
>>> sample = calc.sample(sampler, 1000, POI(mean, 1.2))
Returns:
Expand Down Expand Up @@ -257,6 +252,6 @@ def toys_loss(self, parameter_name: str):
"""
if parameter_name not in self._toys_loss:
parameter = self.get_parameter(parameter_name)
sampler = self.sampler(floating_params=[parameter])
sampler = self.sampler()
self._toys_loss[parameter.name] = self.lossbuilder(self.model, sampler)
return self._toys_loss[parameter_name]
15 changes: 9 additions & 6 deletions src/hepstats/hypotests/toyutils.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import asdf
import numpy as np
import zfit.param
from tqdm.auto import tqdm

from .exceptions import ParameterNotFound, FormatError
Expand Down Expand Up @@ -219,7 +220,7 @@ def ntoys(self, poigen: POI, poieval: POIarray) -> int:
except KeyError:
return 0

def generate_and_fit_toys(
def generate_and_fit_toys( # TODO PROFILE THIS
self,
ntoys: int,
poigen: POI,
Expand Down Expand Up @@ -265,6 +266,7 @@ def generate_and_fit_toys(
ntrials = 0

progressbar = tqdm(total=ntoys)
minimum = None

for i in range(ntoys):
ntrials += 1
Expand All @@ -282,13 +284,13 @@ def generate_and_fit_toys(
)
param_dict = next(samples)

with ExitStack() as stack:
for param, value in param_dict.items():
stack.enter_context(param.set_value(value))
with zfit.param.set_values(param_dict):

for _ in range(2):
try:
minimum = minimizer.minimize(loss=toys_loss)
minimum = minimizer.minimize(
loss=toys_loss
) # TODO: , init=minimum use previous minimum as starting point for parameter uncertainties
converged = minimum.converged
if converged:
break
Expand All @@ -303,7 +305,8 @@ def generate_and_fit_toys(
msg = f"{nfailures} out of {ntrials} fits failed or didn't converge."
warnings.warn(msg, FitFailuresWarning)
continue

if minimum is None:
raise RuntimeError("No minimum found.")
bestfit[i] = minimum.params[param]["value"]
nll_bestfit[i] = pll(minimizer, toys_loss, POI(param, bestfit[i]))

Expand Down
10 changes: 9 additions & 1 deletion src/hepstats/utils/fit/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,10 @@
from .diverse import get_value, eval_pdf, pll, array2dataset, get_nevents, set_values
from .diverse import (
get_value,
eval_pdf,
pll,
array2dataset,
get_nevents,
set_values,
set_values_once,
)
from .sampling import base_sampler, base_sample
16 changes: 13 additions & 3 deletions src/hepstats/utils/fit/diverse.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from contextlib import ExitStack, contextmanager
from contextlib import ExitStack, contextmanager, suppress

import numpy as np

Expand All @@ -12,6 +12,16 @@ def get_value(value):
return np.array(value)


def set_values_once(params, values):
with suppress(ImportError):
import zfit

return zfit.param.set_values(params, values) # more efficient

for p, v in zip(params, values):
p.set_value(v)


def eval_pdf(model, x, params=None, allow_extended=False):
"""Compute pdf of model at a given point x and for given parameters values"""

Expand All @@ -34,7 +44,7 @@ def pdf(model, x):
return pdf(model, x)


def pll(minimizer, loss, pois) -> float:
def pll(minimizer, loss, pois, init=None) -> float:
"""Compute minimum profile likelihood for fixed given parameters values."""

with ExitStack() as stack:
Expand All @@ -44,7 +54,7 @@ def pll(minimizer, loss, pois) -> float:
param.floating = False

if any(param_loss.floating for param_loss in loss.get_params()):
minimum = minimizer.minimize(loss=loss)
minimum = minimizer.minimize(loss=loss) # TODO: add init?
value = minimum.fmin
else:
value = get_value(loss.value())
Expand Down
33 changes: 9 additions & 24 deletions src/hepstats/utils/fit/sampling.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,13 @@
from .diverse import get_value


def base_sampler(models, nevents, floating_params=None):
def base_sampler(models, nevents):
"""
Creates samplers from models.
Args:
models (list(model)): models to sample
nevents (list(int)): number of in each sampler
floating_params (list(parameter), optionnal): floating parameter in the samplers
Returns:
Samplers
Expand All @@ -22,24 +21,10 @@ def base_sampler(models, nevents, floating_params=None):
assert all(is_valid_pdf(m) for m in models)
assert len(nevents) == len(models)

if floating_params:
floating_params_names = [f.name for f in floating_params]

samplers = []
fixed_params = []
for m in models:

def to_fix(p):
if floating_params:
return p.name in floating_params_names
else:
return False

fixed = [p for p in m.get_params() if not to_fix(p)]
fixed_params.append(fixed)

for i, (m, p) in enumerate(zip(models, fixed_params)):
sampler = m.create_sampler(n=nevents[i], fixed_params=p)
for i, m in enumerate(models):
sampler = m.create_sampler(n=nevents[i])
samplers.append(sampler)

return samplers
Expand Down Expand Up @@ -72,13 +57,13 @@ def base_sample(samplers, ntoys, parameter=None, value=None, constraints=None):
continue

for i in range(ntoys):
if not (parameter is None or value is None):
with parameter.set_value(value):
for s in samplers:
s.resample()
if parameter is None or value is None:
params = None
else:
for s in samplers:
s.resample()
params = {parameter: value}

for s in samplers:
s.resample(params=params)

if constraints is not None:
yield {param: value[i] for param, value in sampled_constraints.items()}
Expand Down
2 changes: 1 addition & 1 deletion tests/hypotests/test_calculators.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ def test_frequentist_calculator_one_poi(constraint):
assert calc.ntoysnull == 100
assert calc.ntoysalt == 100

samplers = calc.sampler(floating_params=[mean])
samplers = calc.sampler()
assert all(is_valid_data(s) for s in samplers)
loss = calc.toys_loss(mean.name)
assert is_valid_loss(loss)
42 changes: 6 additions & 36 deletions tests/hypotests/test_discovery.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,15 @@
import os
import pytest

import numpy as np
import tqdm
import pytest
import zfit
from zfit.loss import ExtendedUnbinnedNLL, UnbinnedNLL
from zfit.loss import UnbinnedNLL
from zfit.minimize import Minuit

from zfit.models.dist_tfp import WrapDistribution
import tensorflow_probability as tfp
from zfit.util import ztyping
from collections import OrderedDict

import hepstats
from hepstats.hypotests.calculators.basecalculator import BaseCalculator
from hepstats.hypotests.calculators import AsymptoticCalculator, FrequentistCalculator
from hepstats.hypotests import Discovery
from hepstats.hypotests.calculators import AsymptoticCalculator, FrequentistCalculator
from hepstats.hypotests.calculators.basecalculator import BaseCalculator
from hepstats.hypotests.parameters import POI

notebooks_dir = f"{os.path.dirname(hepstats.__file__)}/../../notebooks/hypotests"
Expand Down Expand Up @@ -101,31 +96,6 @@ def test_with_frequentist_calculator(create_loss, nbins):
assert significance >= 3


class Poisson(WrapDistribution):
_N_OBS = 1

def __init__(
self,
lamb: ztyping.ParamTypeInput,
obs: ztyping.ObsTypeInput,
name: str = "Poisson",
):
"""
Temporary class
"""
(lamb,) = self._check_input_params(lamb)
params = OrderedDict((("lamb", lamb),))
dist_params = lambda: dict(rate=lamb.value())
distribution = tfp.distributions.Poisson
super().__init__(
distribution=distribution,
dist_params=dist_params,
obs=obs,
params=params,
name=name,
)


def create_loss_counting():
n = 370
nbkg = 340
Expand All @@ -135,7 +105,7 @@ def create_loss_counting():
Nobs = zfit.ComposedParameter("Nobs", lambda a, b: a + b, params=[Nsig, Nbkg])

obs = zfit.Space("N", limits=(0, 800))
model = Poisson(obs=obs, lamb=Nobs)
model = zfit.pdf.Poisson(obs=obs, lamb=Nobs)

data = zfit.data.Data.from_numpy(obs=obs, array=np.array([n]))

Expand Down
2 changes: 1 addition & 1 deletion tests/hypotests/test_toysutils.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ def test_toymanager_attributes():
== tmc.get_toyresult(poigen, poieval).ntoys
)

samplers = tm.sampler(floating_params=[poigen.parameter])
samplers = tm.sampler()
assert all(is_valid_data(s) for s in samplers)
loss = tm.toys_loss(poigen.name)
assert is_valid_loss(loss)
Expand Down

0 comments on commit d22dbae

Please sign in to comment.