jelli 0.0.1__py3-none-any.whl

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/__init__.py ADDED
@@ -0,0 +1,5 @@
1
+ from ._version import __version__
2
+ from .core.global_likelihood import GlobalLikelihood
3
+ from .core.observable_sector import ObservableSector
4
+ from .core.measurement import Measurement
5
+ from .core.custom_basis import CustomBasis
jelli/_version.py ADDED
@@ -0,0 +1 @@
1
+ __version__ = '0.0.1'
jelli/core/__init__.py ADDED
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