jelli 0.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- jelli-0.0.1/LICENSE +21 -0
- jelli-0.0.1/PKG-INFO +20 -0
- jelli-0.0.1/README.md +1 -0
- jelli-0.0.1/pyproject.toml +32 -0
- jelli-0.0.1/setup.cfg +4 -0
- jelli-0.0.1/setup.py +3 -0
- jelli-0.0.1/src/jelli/__init__.py +5 -0
- jelli-0.0.1/src/jelli/_version.py +1 -0
- jelli-0.0.1/src/jelli/core/__init__.py +0 -0
- jelli-0.0.1/src/jelli/core/custom_basis.py +177 -0
- jelli-0.0.1/src/jelli/core/experimental_correlations.py +100 -0
- jelli-0.0.1/src/jelli/core/global_likelihood.py +923 -0
- jelli-0.0.1/src/jelli/core/global_likelihood_point.py +34 -0
- jelli-0.0.1/src/jelli/core/measurement.py +489 -0
- jelli-0.0.1/src/jelli/core/observable_sector.py +1063 -0
- jelli-0.0.1/src/jelli/core/theory_correlations.py +93 -0
- jelli-0.0.1/src/jelli/utils/__init__.py +0 -0
- jelli-0.0.1/src/jelli/utils/data_io.py +53 -0
- jelli-0.0.1/src/jelli/utils/distributions.py +197 -0
- jelli-0.0.1/src/jelli/utils/jax_helpers.py +17 -0
- jelli-0.0.1/src/jelli/utils/par_helpers.py +103 -0
- jelli-0.0.1/src/jelli/utils/probability.py +439 -0
- jelli-0.0.1/src/jelli.egg-info/PKG-INFO +20 -0
- jelli-0.0.1/src/jelli.egg-info/SOURCES.txt +26 -0
- jelli-0.0.1/src/jelli.egg-info/dependency_links.txt +1 -0
- jelli-0.0.1/src/jelli.egg-info/requires.txt +8 -0
- jelli-0.0.1/src/jelli.egg-info/top_level.txt +1 -0
- jelli-0.0.1/tests/test_package.py +11 -0
jelli-0.0.1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Aleks Smolkovič & Peter Stangl
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
jelli-0.0.1/PKG-INFO
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: jelli
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: A JAX-based EFT likelihood.
|
|
5
|
+
Author-email: Aleks Smolkovič <aleks.smolkovic@ijs.si>, Peter Stangl <peter.stangl@cern.ch>
|
|
6
|
+
License: MIT
|
|
7
|
+
Requires-Python: >=3.8
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Requires-Dist: numpy
|
|
11
|
+
Requires-Dist: scipy
|
|
12
|
+
Requires-Dist: jax
|
|
13
|
+
Requires-Dist: wilson
|
|
14
|
+
Requires-Dist: rgevolve
|
|
15
|
+
Requires-Dist: multipledispatch
|
|
16
|
+
Requires-Dist: networkx
|
|
17
|
+
Requires-Dist: h5py
|
|
18
|
+
Dynamic: license-file
|
|
19
|
+
|
|
20
|
+
# jelli - a JAX-based EFT Likelihood
|
jelli-0.0.1/README.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# jelli - a JAX-based EFT Likelihood
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools >= 61.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "jelli"
|
|
7
|
+
authors = [
|
|
8
|
+
{name = "Aleks Smolkovič", email = "aleks.smolkovic@ijs.si"},
|
|
9
|
+
{name = "Peter Stangl", email = "peter.stangl@cern.ch"},
|
|
10
|
+
]
|
|
11
|
+
description = "A JAX-based EFT likelihood."
|
|
12
|
+
readme = "README.md"
|
|
13
|
+
requires-python = ">=3.8"
|
|
14
|
+
license = {text = "MIT"}
|
|
15
|
+
dependencies = [
|
|
16
|
+
"numpy",
|
|
17
|
+
"scipy",
|
|
18
|
+
"jax",
|
|
19
|
+
"wilson",
|
|
20
|
+
"rgevolve",
|
|
21
|
+
"multipledispatch",
|
|
22
|
+
"networkx",
|
|
23
|
+
"h5py",
|
|
24
|
+
]
|
|
25
|
+
dynamic = ["version"]
|
|
26
|
+
|
|
27
|
+
[tool.setuptools.packages.find]
|
|
28
|
+
where = ["src/"]
|
|
29
|
+
|
|
30
|
+
[tool.setuptools.dynamic]
|
|
31
|
+
version = {attr = "jelli._version.__version__"}
|
|
32
|
+
|
jelli-0.0.1/setup.cfg
ADDED
jelli-0.0.1/setup.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = '0.0.1'
|
|
File without changes
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
from typing import List, Dict, Union
|
|
2
|
+
|
|
3
|
+
class CustomBasis:
|
|
4
|
+
'''
|
|
5
|
+
A class to represent a custom parameter basis.
|
|
6
|
+
|
|
7
|
+
Parameters
|
|
8
|
+
----------
|
|
9
|
+
name : str
|
|
10
|
+
The name of the custom basis.
|
|
11
|
+
parameters : list or dict
|
|
12
|
+
The parameters in the custom basis. If a list is provided, all parameters are assumed to be real. If a dict is provided, the keys are the parameter names and the values are the types (e.g., 'R' for real, 'C' for complex).
|
|
13
|
+
|
|
14
|
+
Attributes
|
|
15
|
+
----------
|
|
16
|
+
name : str
|
|
17
|
+
The name of the custom basis.
|
|
18
|
+
parameters : dict
|
|
19
|
+
The parameters in the custom basis. The keys are the parameter names and the values are the types (e.g., 'R' for real, 'C' for complex).
|
|
20
|
+
|
|
21
|
+
Methods
|
|
22
|
+
-------
|
|
23
|
+
get_all_names() -> List[str]
|
|
24
|
+
Get all custom basis names.
|
|
25
|
+
get(name: str) -> 'CustomBasis'
|
|
26
|
+
Get a custom basis by name.
|
|
27
|
+
get_all() -> List['CustomBasis']
|
|
28
|
+
Get all custom basis objects.
|
|
29
|
+
get_parameter_basis() -> List
|
|
30
|
+
Get the parameter basis.
|
|
31
|
+
|
|
32
|
+
Examples
|
|
33
|
+
--------
|
|
34
|
+
Initialize a custom basis with real parameters:
|
|
35
|
+
|
|
36
|
+
>>> custom_basis = CustomBasis('example_basis', ['param1', 'param2'])
|
|
37
|
+
|
|
38
|
+
Initialize a custom basis with mixed parameters:
|
|
39
|
+
|
|
40
|
+
>>> custom_basis = CustomBasis('example_basis', {'param1': 'R', 'param2': 'C'})
|
|
41
|
+
|
|
42
|
+
Get all custom basis names:
|
|
43
|
+
|
|
44
|
+
>>> CustomBasis.get_all_names()
|
|
45
|
+
|
|
46
|
+
Get a custom basis by name:
|
|
47
|
+
|
|
48
|
+
>>> custom_basis = CustomBasis.get('example_basis')
|
|
49
|
+
|
|
50
|
+
Get all custom basis objects:
|
|
51
|
+
|
|
52
|
+
>>> custom_bases = CustomBasis.get_all()
|
|
53
|
+
|
|
54
|
+
Get the parameter basis:
|
|
55
|
+
|
|
56
|
+
>>> parameter_basis = custom_basis.get_parameter_basis()
|
|
57
|
+
|
|
58
|
+
'''
|
|
59
|
+
|
|
60
|
+
_custom_bases: Dict[str, 'CustomBasis'] = {} # Class attribute to store all custom bases
|
|
61
|
+
|
|
62
|
+
def __init__(self, name: str, parameters: Union[List[str], Dict[str, str]]):
|
|
63
|
+
"""
|
|
64
|
+
Initialize the CustomBasis class.
|
|
65
|
+
|
|
66
|
+
Parameters
|
|
67
|
+
----------
|
|
68
|
+
name : str
|
|
69
|
+
The name of the custom basis.
|
|
70
|
+
parameters : list or dict
|
|
71
|
+
The parameters in the custom basis. If a list is provided, all parameters are assumed to be real. If a dict is provided, the keys are the parameter names and the values are the types (e.g., 'R' for real, 'C' for complex).
|
|
72
|
+
|
|
73
|
+
Returns
|
|
74
|
+
--------
|
|
75
|
+
None
|
|
76
|
+
|
|
77
|
+
Examples
|
|
78
|
+
--------
|
|
79
|
+
Initialize a custom basis with real parameters:
|
|
80
|
+
|
|
81
|
+
>>> custom_basis = CustomBasis('example_basis', ['param1', 'param2'])
|
|
82
|
+
|
|
83
|
+
Initialize a custom basis with mixed parameters:
|
|
84
|
+
|
|
85
|
+
>>> custom_basis = CustomBasis('example_basis', {'param1': 'R', 'param2': 'C'})
|
|
86
|
+
"""
|
|
87
|
+
self.name = name
|
|
88
|
+
if isinstance(parameters, list):
|
|
89
|
+
self.parameters = {param: 'R' for param in parameters}
|
|
90
|
+
elif isinstance(parameters, dict):
|
|
91
|
+
if not all(value in ['R', 'C'] for value in parameters.values()):
|
|
92
|
+
raise ValueError("All parameter types must be either 'R' or 'C'.")
|
|
93
|
+
self.parameters = parameters
|
|
94
|
+
else:
|
|
95
|
+
raise ValueError("Parameters must be a list or a dictionary.")
|
|
96
|
+
self._custom_bases[self.name] = self
|
|
97
|
+
|
|
98
|
+
@classmethod
|
|
99
|
+
def get_all_names(cls) -> List[str]:
|
|
100
|
+
"""
|
|
101
|
+
Get all custom basis names.
|
|
102
|
+
|
|
103
|
+
Returns
|
|
104
|
+
--------
|
|
105
|
+
list
|
|
106
|
+
A list of all custom basis names.
|
|
107
|
+
|
|
108
|
+
Examples
|
|
109
|
+
--------
|
|
110
|
+
>>> CustomBasis.get_all_names()
|
|
111
|
+
"""
|
|
112
|
+
return sorted(cls._custom_bases.keys())
|
|
113
|
+
|
|
114
|
+
@classmethod
|
|
115
|
+
def get(cls, name: str) -> 'CustomBasis':
|
|
116
|
+
"""
|
|
117
|
+
Get a custom basis by name.
|
|
118
|
+
|
|
119
|
+
Parameters
|
|
120
|
+
----------
|
|
121
|
+
name : str
|
|
122
|
+
The name of the custom basis.
|
|
123
|
+
Returns
|
|
124
|
+
--------
|
|
125
|
+
CustomBasis
|
|
126
|
+
The custom basis object.
|
|
127
|
+
|
|
128
|
+
Examples
|
|
129
|
+
--------
|
|
130
|
+
>>> CustomBasis.get('example_basis')
|
|
131
|
+
"""
|
|
132
|
+
return cls._custom_bases.get(name)
|
|
133
|
+
|
|
134
|
+
@classmethod
|
|
135
|
+
def get_all(cls) -> List['CustomBasis']:
|
|
136
|
+
"""
|
|
137
|
+
Get all custom basis objects.
|
|
138
|
+
|
|
139
|
+
Returns
|
|
140
|
+
--------
|
|
141
|
+
list
|
|
142
|
+
A list of all custom basis objects.
|
|
143
|
+
|
|
144
|
+
Examples
|
|
145
|
+
--------
|
|
146
|
+
>>> CustomBasis.get_all()
|
|
147
|
+
"""
|
|
148
|
+
return list(cls._custom_bases.values())
|
|
149
|
+
|
|
150
|
+
def get_parameter_basis(self, split_re_im=True) -> List:
|
|
151
|
+
"""
|
|
152
|
+
Get the parameter basis.
|
|
153
|
+
|
|
154
|
+
Parameters
|
|
155
|
+
----------
|
|
156
|
+
split_re_im : bool, optional
|
|
157
|
+
If True, split parameters into real and imaginary parts, otherwise return the parameters directly. Default is True.
|
|
158
|
+
|
|
159
|
+
Returns
|
|
160
|
+
--------
|
|
161
|
+
list
|
|
162
|
+
A list containing the parameter basis.
|
|
163
|
+
|
|
164
|
+
Examples
|
|
165
|
+
--------
|
|
166
|
+
>>> custom_basis = CustomBasis('example_basis', ['param1', 'param2'])
|
|
167
|
+
>>> custom_basis.get_parameter_basis('example_basis')
|
|
168
|
+
"""
|
|
169
|
+
if split_re_im:
|
|
170
|
+
parameter_basis = []
|
|
171
|
+
for parameter, parameter_type in self.parameters.items():
|
|
172
|
+
parameter_basis.append((parameter, 'R'))
|
|
173
|
+
if parameter_type == 'C':
|
|
174
|
+
parameter_basis.append((parameter, 'I'))
|
|
175
|
+
else:
|
|
176
|
+
parameter_basis = self.parameters.keys()
|
|
177
|
+
return sorted(parameter_basis)
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
from typing import Dict, Optional, Iterable
|
|
2
|
+
import h5py
|
|
3
|
+
import numpy as np
|
|
4
|
+
from jax import numpy as jnp
|
|
5
|
+
import os
|
|
6
|
+
from ..utils.data_io import get_json_schema, hash_observable_names
|
|
7
|
+
|
|
8
|
+
class ExperimentalCorrelations:
|
|
9
|
+
|
|
10
|
+
_instances: Dict[str, Dict[str, 'ExperimentalCorrelations']] = {
|
|
11
|
+
'correlations': {},
|
|
12
|
+
'central': {},
|
|
13
|
+
'uncertainties': {}
|
|
14
|
+
} # Dictionary to hold instances of ExperimentalCorrelations
|
|
15
|
+
_covariance_scaled: Dict[str, jnp.ndarray] = {}
|
|
16
|
+
_pdfxf_h5_versions = {'1.0'} # Set of supported versions of the pdfxf-h5 JSON schema
|
|
17
|
+
|
|
18
|
+
def __init__(
|
|
19
|
+
self,
|
|
20
|
+
hash_val: str,
|
|
21
|
+
data_type: str,
|
|
22
|
+
data: np.ndarray,
|
|
23
|
+
row_names: Dict[str, int],
|
|
24
|
+
col_names: Dict[str, int]
|
|
25
|
+
) -> None:
|
|
26
|
+
self.hash_val = hash_val
|
|
27
|
+
self.data_type = data_type
|
|
28
|
+
self.data = data
|
|
29
|
+
self.row_names = row_names
|
|
30
|
+
self.col_names = col_names
|
|
31
|
+
self._instances[data_type][hash_val] = self
|
|
32
|
+
|
|
33
|
+
@classmethod
|
|
34
|
+
def _load_file(cls, path: str) -> None:
|
|
35
|
+
with h5py.File(path, 'r') as f:
|
|
36
|
+
schema_name, schema_version = get_json_schema(dict(f.attrs))
|
|
37
|
+
if schema_name == 'pdfxf-h5' and schema_version in cls._pdfxf_h5_versions:
|
|
38
|
+
for hash_val in f['correlations']:
|
|
39
|
+
cls.from_hdf5_group(hash_val, 'correlations', f['correlations'][hash_val])
|
|
40
|
+
for hash_val in f['central']:
|
|
41
|
+
cls.from_hdf5_group(hash_val, 'central', f['central'][hash_val])
|
|
42
|
+
for hash_val in f['uncertainties']:
|
|
43
|
+
cls.from_hdf5_group(hash_val, 'uncertainties', f['uncertainties'][hash_val])
|
|
44
|
+
|
|
45
|
+
@classmethod
|
|
46
|
+
def load(cls, path: str) -> None:
|
|
47
|
+
# load all hdf5 files in the directory
|
|
48
|
+
if os.path.isdir(path):
|
|
49
|
+
for file in os.listdir(path):
|
|
50
|
+
if file.endswith('.hdf5'):
|
|
51
|
+
cls._load_file(os.path.join(path, file))
|
|
52
|
+
# load single hdf5 file
|
|
53
|
+
else:
|
|
54
|
+
cls._load_file(path)
|
|
55
|
+
|
|
56
|
+
@classmethod
|
|
57
|
+
def from_hdf5_group(cls, hash_val: str, data_type: str, hdf5_group: h5py.Group) -> None:
|
|
58
|
+
data = hdf5_group['data']
|
|
59
|
+
data = np.array(data[()], dtype=np.float64) * data.attrs.get('scale', 1.0)
|
|
60
|
+
row_names = {name: i for i, name in enumerate(hdf5_group['row_names'][()].astype(str))}
|
|
61
|
+
col_names = {name: i for i, name in enumerate(hdf5_group.get('col_names', np.array([]))[()].astype(str))}
|
|
62
|
+
cls(hash_val, data_type, data, row_names, col_names)
|
|
63
|
+
|
|
64
|
+
@classmethod
|
|
65
|
+
def get_data(
|
|
66
|
+
cls,
|
|
67
|
+
data_type: str,
|
|
68
|
+
row_names: Iterable[str],
|
|
69
|
+
col_names: Optional[Iterable[str]] = []
|
|
70
|
+
):
|
|
71
|
+
hash_val = hash_observable_names(row_names, col_names)
|
|
72
|
+
if hash_val in cls._instances[data_type]:
|
|
73
|
+
data = cls._instances[data_type][hash_val].data
|
|
74
|
+
else:
|
|
75
|
+
hash_val = hash_observable_names(col_names, row_names)
|
|
76
|
+
if hash_val in cls._instances[data_type]:
|
|
77
|
+
data = cls._instances[data_type][hash_val].data.T
|
|
78
|
+
else:
|
|
79
|
+
data = None
|
|
80
|
+
return data
|
|
81
|
+
|
|
82
|
+
@classmethod
|
|
83
|
+
def get_cov_scaled(
|
|
84
|
+
cls,
|
|
85
|
+
row_names: Iterable[str],
|
|
86
|
+
col_names: Iterable[str],
|
|
87
|
+
std_exp_scaled_row: np.ndarray,
|
|
88
|
+
std_exp_scaled_col: np.ndarray,
|
|
89
|
+
):
|
|
90
|
+
hash_val = hash_observable_names(row_names, col_names)
|
|
91
|
+
if hash_val in cls._covariance_scaled:
|
|
92
|
+
cov_scaled = cls._covariance_scaled[hash_val]
|
|
93
|
+
else:
|
|
94
|
+
corr = cls.get_data('correlations', row_names, col_names)
|
|
95
|
+
if corr is None:
|
|
96
|
+
raise ValueError(f"Correlation data for {row_names} and {col_names} not found.")
|
|
97
|
+
cov_scaled = corr * np.outer(std_exp_scaled_row, std_exp_scaled_col)
|
|
98
|
+
cov_scaled = jnp.array(cov_scaled, dtype=jnp.float64)
|
|
99
|
+
cls._covariance_scaled[hash_val] = cov_scaled
|
|
100
|
+
return cov_scaled
|