Hyperiso 1.0.3
Modular flavour-physics calculations, Wilson coefficients and statistical inference
Loading...
Searching...
No Matches
WilsonInterface.py
Go to the documentation of this file.
1"""Python wrapper for Wilson coefficients, including dynamic lambda groups.
2
3The C++ ``WilsonInterface`` computes builtin Wilson groups and now also accepts
4runtime groups/coefficient ids. This module keeps the old enum-based API working
5while exposing the new ``WGroupId``/``WCoefId`` and custom-lambda workflow.
6"""
7
8from __future__ import annotations
9
10from typing import Dict, Mapping, Sequence, Set
11
12from pyhyperiso.phyperiso.pyhyperiso.wilson.wilson_interface import (
13 WilsonInterface as _CppWilsonInterface,
14 CustomWilsonCoefficientConfig as _CppCustomWilsonCoefficientConfig,
15 CustomWilsonGroupConfig as _CppCustomWilsonGroupConfig,
16)
18 WilsonBuildConfig,
19 WilsonRequest,
20 WilsonGroupLike,
21 WilsonCoefLike,
22 _cpp_group_id,
23 _cpp_coef_id,
24)
26 QCDOrder,
27 WCoeff,
28 WGroup,
29 ContributionType,
30 WilsonBasis,
31 ParameterType,
32)
33from pyhyperiso.core.Common.ParamId import ParamId
34from pyhyperiso.core.Common.SymbolId import WCoefId
35from pyhyperiso.core.Math.Scalar import Scalar
36
37
38def _cpp_order(order: QCDOrder):
39 return order.value if isinstance(order, QCDOrder) else order
40
41
42def _cpp_contribution(contribution: ContributionType):
43 return contribution.value if isinstance(contribution, ContributionType) else contribution
44
45
46def _cpp_basis(basis: WilsonBasis):
47 return basis.value if isinstance(basis, WilsonBasis) else basis
48
49
50def _cpp_sources(sources: Sequence[ParamId] | Set[ParamId]):
51 return {p.to_cpp() if isinstance(p, ParamId) else p for p in sources}
52
53
54def _to_cpp_scalar(value):
55 """Convert float/complex/Scalar to what the binding can pass as scalar_t."""
56 if isinstance(value, Scalar):
57 return value._cpp_obj
58 return value
59
60
62 """Python view over the C++ ``ParamSrc`` callback object.
63
64 Users should receive this wrapper in custom Wilson matching callbacks instead
65 of the raw pybind object.
66 """
67
68 def __init__(self, cpp_obj):
69 self._cpp_obj = cpp_obj
70
71 def has(self, pid: ParamId) -> bool:
72 """Return whether a parameter is available."""
73 return bool(self._cpp_obj.has(pid.to_cpp() if isinstance(pid, ParamId) else pid))
74
75 def get_val(self, pid: ParamId) -> Scalar:
76 """Return a parameter value as a ``Scalar`` wrapper."""
77 return Scalar.from_cpp(
78 self._cpp_obj.get_val(pid.to_cpp() if isinstance(pid, ParamId) else pid)
79 )
80
81 def size(self) -> int:
82 """Return the number of parameters in this view."""
83 return int(self._cpp_obj.size())
84
85
87 """Python view over the C++ ``BlockSrc`` callback object."""
88
89 def __init__(self, cpp_obj):
90 self._cpp_obj = cpp_obj
91
92 def has_block(self, block: str) -> bool:
93 """Return whether a block exists in the view."""
94 return bool(self._cpp_obj.has_block(str(block)))
95
96 def get_val(self, block: str, code) -> Scalar:
97 """Return a block value as a ``Scalar`` wrapper."""
98 if hasattr(code, "to_cpp"):
99 code = code.to_cpp()
100 return Scalar.from_cpp(self._cpp_obj.get_val(str(block), code))
101
102 def size(self) -> int:
103 """Return the number of blocks in this view."""
104 return int(self._cpp_obj.size())
105
106
108 """Python wrapper for one lambda-backed Wilson coefficient.
109
110 Args:
111 coefficient: Dynamic coefficient id, builtin enum, or name/alias.
112
113 A matching lambda receives a C++ ``ParamSrc`` object. Use
114 ``src.get_val(pid.to_cpp())`` or ``src.get_val(ParameterType.SM.value,
115 "SMINPUTS", 6)`` inside the callback.
116 """
117
118 def __init__(self, coefficient: WilsonCoefLike):
119 self._cpp_obj = _CppCustomWilsonCoefficientConfig(_cpp_coef_id(coefficient))
120
122 self,
123 order: QCDOrder,
124 sources: Sequence[ParamId] | Set[ParamId],
125 compute,
126 contribution: ContributionType = ContributionType.SM,
127 ) -> "CustomWilsonCoefficientConfig":
128 """Attach a matching lambda for one QCD order.
129
130 Args:
131 order: QCD order of the matching contribution.
132 sources: Parameter dependencies required by ``compute``.
133 compute: Callable ``compute(src) -> float | complex``.
134 contribution: SM/BSM component represented by this lambda.
135 """
136
137 def wrapped_compute(src):
138 return _to_cpp_scalar(compute(ParamSrcView(src)))
139
141 _cpp_order(order),
142 _cpp_sources(sources),
143 wrapped_compute,
144 _cpp_contribution(contribution),
145 )
146 return self
147
148 def to_cpp(self):
149 """Return the bound C++ config object."""
150 return self._cpp_obj
151
152
154 """Python wrapper for a lambda-backed Wilson group.
155
156 Args:
157 group: Dynamic group id, builtin enum, or group name/alias.
158 matching_scale: Matching scale in GeV.
159 hadronic_scale: Hadronic/running scale in GeV.
160 order: Maximum QCD order supplied by the group.
161 contribution: Contribution component for the group.
162 """
163
165 self,
166 group: WilsonGroupLike,
167 matching_scale: float = 81.0,
168 hadronic_scale: float = 4.8,
169 order: QCDOrder = QCDOrder.LO,
170 contribution: ContributionType = ContributionType.SM,
171 display_name: str = "",
172 ):
173 self._cpp_obj = _CppCustomWilsonGroupConfig(_cpp_group_id(group))
174 self._cpp_obj.matching_scale = float(matching_scale)
175 self._cpp_obj.hadronic_scale = float(hadronic_scale)
176 self._cpp_obj.order = _cpp_order(order)
177 self._cpp_obj.contribution = _cpp_contribution(contribution)
178 self._cpp_obj.display_name = display_name
179
181 self, coefficient: CustomWilsonCoefficientConfig
182 ) -> "CustomWilsonGroupConfig":
183 """Append a coefficient config to this group."""
184 if isinstance(coefficient, CustomWilsonCoefficientConfig):
185 coefficient = coefficient.to_cpp()
186 self._cpp_obj.add_coefficient(coefficient)
187 return self
188
190 self,
191 basis: WilsonBasis,
192 order: QCDOrder,
193 sources: Mapping[ParameterType, Sequence[str]],
194 compute,
195 ) -> "CustomWilsonGroupConfig":
196 """Attach a running lambda for one basis/order.
197
198 The callable receives ``(matching, block_src)`` and must return a mapping
199 ``{WCoefId_cpp: scalar}``. For simple dev use cases, keep
200 ``install_identity_running_if_empty=True`` and skip this method.
201 """
202 cpp_sources = {
203 (k.value if isinstance(k, ParameterType) else k): list(v)
204 for k, v in dict(sources).items()
205 }
206
207 def wrapped_running(matching, block_src):
208 py_matching = {
209 QCDOrder(o): {WCoefId(str(k)): Scalar.from_cpp(v) for k, v in vals.items()}
210 for o, vals in matching.items()
211 }
212 result = compute(py_matching, BlockSrcView(block_src))
213 return {
214 (k._to_cpp() if isinstance(k, WCoefId) else _cpp_coef_id(k)): _to_cpp_scalar(v)
215 for k, v in dict(result).items()
216 }
217
219 _cpp_basis(basis), _cpp_order(order), cpp_sources, wrapped_running
220 )
221 return self
222
223 @property
225 """Whether C++ installs identity running if no running lambda is given."""
226 return bool(self._cpp_obj.install_identity_running_if_empty)
227
228 @install_identity_running_if_empty.setter
229 def install_identity_running_if_empty(self, value: bool) -> None:
230 """Enable or disable automatic identity running for an empty group."""
231 self._cpp_obj.install_identity_running_if_empty = bool(value)
232
233 def to_cpp(self):
234 """Return the bound C++ config object."""
235 return self._cpp_obj
236
237
239 """User-facing wrapper for the C++ Wilson-coefficient interface."""
240
241 def __init__(self) -> None:
242 """Create an unbuilt Wilson interface."""
243 self._cpp_obj = _CppWilsonInterface()
244
245 def build(self, config: WilsonBuildConfig) -> None:
246 """Build the C++ Wilson pipeline from a ``WilsonBuildConfig``."""
247 self._cpp_obj.build(config.to_cpp())
248
249 def add_wilson_group(self, config: WilsonBuildConfig) -> None:
250 """Add builtin or already-registered dynamic Wilson groups."""
251 self._cpp_obj.add_wilson_group(config.to_cpp())
252
253 def add_custom_group(self, config: CustomWilsonGroupConfig) -> "WilsonInterface":
254 """Add a lambda-backed custom Wilson group."""
255 if isinstance(config, CustomWilsonGroupConfig):
256 config = config.to_cpp()
257 self._cpp_obj.add_custom_group(config)
258 return self
259
260 def set_matching_scale(self, mu_W: float) -> None:
261 """Set the matching scale ``mu_W``."""
263
264 def set_hadronic_scale(self, mu_h: float) -> None:
265 """Set the hadronic running scale ``mu_h``."""
267
268 def _req(
269 self, req_or_group, coeff=None, order=None, contribution=None, basis=None
270 ) -> WilsonRequest:
271 if isinstance(req_or_group, WilsonRequest):
272 return req_or_group
273 return WilsonRequest(
274 req_or_group,
275 coeff,
276 order or QCDOrder.LO,
277 contribution or ContributionType.TOTAL,
278 wilson_basis=basis or WilsonBasis.STANDARD,
279 )
280
281 def get_M(self, req_or_group, coeff=None, order=None, contribution=None) -> Scalar:
282 """Return one matching coefficient at the requested QCD order."""
283 req = self._req(req_or_group, coeff, order, contribution)
284 return Scalar.from_cpp(
285 self._cpp_obj.get_M(
286 _cpp_group_id(req.group),
287 _cpp_coef_id(req.coefficient),
288 _cpp_order(req.order),
289 _cpp_contribution(req.contribution),
290 )
291 )
292
293 def get_FM(self, req_or_group, coeff=None, order=None, contribution=None) -> Scalar:
294 """Return one full matching coefficient summed up to ``order``."""
295 req = self._req(req_or_group, coeff, order, contribution)
296 return Scalar.from_cpp(
297 self._cpp_obj.get_FM(
298 _cpp_group_id(req.group),
299 _cpp_coef_id(req.coefficient),
300 _cpp_order(req.order),
301 _cpp_contribution(req.contribution),
302 )
303 )
304
305 def get_R(
306 self, req_or_group, coeff=None, order=None, contribution=None, basis=WilsonBasis.STANDARD
307 ) -> Scalar:
308 """Return one running coefficient at the requested QCD order."""
309 req = self._req(req_or_group, coeff, order, contribution, basis)
310 return Scalar.from_cpp(
311 self._cpp_obj.get_R(
312 _cpp_group_id(req.group),
313 _cpp_coef_id(req.coefficient),
314 _cpp_order(req.order),
315 _cpp_contribution(req.contribution),
316 _cpp_basis(req.wilson_basis),
317 )
318 )
319
321 self, req_or_group, coeff=None, order=None, contribution=None, basis=WilsonBasis.STANDARD
322 ) -> Scalar:
323 """Return one full running coefficient summed up to ``order``."""
324 req = self._req(req_or_group, coeff, order, contribution, basis)
325 return Scalar.from_cpp(
326 self._cpp_obj.get_FR(
327 _cpp_group_id(req.group),
328 _cpp_coef_id(req.coefficient),
329 _cpp_order(req.order),
330 _cpp_contribution(req.contribution),
331 _cpp_basis(req.wilson_basis),
332 )
333 )
334
336 self, group: WilsonGroupLike, coeff: WilsonCoefLike, contribution: ContributionType
337 ) -> Dict[QCDOrder, Scalar]:
338 """Return matching coefficients separated by QCD order."""
339 cpp_map = self._cpp_obj.get_sep_order_matching_coefficient(
340 _cpp_group_id(group), _cpp_coef_id(coeff), _cpp_contribution(contribution)
341 )
342 return {QCDOrder(order): Scalar.from_cpp(val) for order, val in cpp_map.items()}
343
345 self,
346 group: WilsonGroupLike,
347 coeff: WilsonCoefLike,
348 contribution: ContributionType,
349 basis: WilsonBasis = WilsonBasis.STANDARD,
350 ) -> Dict[QCDOrder, Scalar]:
351 """Return running coefficients separated by QCD order."""
352 cpp_map = self._cpp_obj.get_sep_order_run_coefficient(
353 _cpp_group_id(group),
354 _cpp_coef_id(coeff),
355 _cpp_contribution(contribution),
356 _cpp_basis(basis),
357 )
358 return {QCDOrder(order): Scalar.from_cpp(val) for order, val in cpp_map.items()}
359
360 # Builtin-group map helpers remain enum-only because the C++ return key is WCoeff.
362 self, group: WGroup, order: QCDOrder, contribution: ContributionType
363 ) -> Dict[WCoeff, Scalar]:
364 """Return all builtin matching coefficients in one static group."""
365 cpp_map = self._cpp_obj.get_all_matching_coefficient(
366 group.value, order.value, contribution.value
367 )
368 return {WCoeff(k): Scalar.from_cpp(v) for k, v in cpp_map.items()}
369
371 self,
372 group: WGroup,
373 order: QCDOrder,
374 contribution: ContributionType,
375 basis: WilsonBasis = WilsonBasis.STANDARD,
376 ) -> Dict[WCoeff, Scalar]:
377 """Return all builtin running coefficients in one static group."""
378 cpp_map = self._cpp_obj.get_all_run_coefficient(
379 group.value, order.value, contribution.value, basis.value
380 )
381 return {WCoeff(k): Scalar.from_cpp(v) for k, v in cpp_map.items()}
382
383
384__all__ = [
385 "WilsonInterface",
386 "CustomWilsonCoefficientConfig",
387 "CustomWilsonGroupConfig",
388 "ParamSrcView",
389 "BlockSrcView",
390]
"CustomWilsonCoefficientConfig" set_matching(self, QCDOrder order, Sequence[ParamId]|Set[ParamId] sources, compute, ContributionType contribution=ContributionType.SM)
__init__(self, WilsonGroupLike group, float matching_scale=81.0, float hadronic_scale=4.8, QCDOrder order=QCDOrder.LO, ContributionType contribution=ContributionType.SM, str display_name="")
"CustomWilsonGroupConfig" add_coefficient(self, CustomWilsonCoefficientConfig coefficient)
"CustomWilsonGroupConfig" set_running(self, WilsonBasis basis, QCDOrder order, Mapping[ParameterType, Sequence[str]] sources, compute)
Scalar get_FR(self, req_or_group, coeff=None, order=None, contribution=None, basis=WilsonBasis.STANDARD)
Scalar get_FM(self, req_or_group, coeff=None, order=None, contribution=None)
Dict[QCDOrder, Scalar] get_sep_order_running(self, WilsonGroupLike group, WilsonCoefLike coeff, ContributionType contribution, WilsonBasis basis=WilsonBasis.STANDARD)
Dict[QCDOrder, Scalar] get_sep_order_matching(self, WilsonGroupLike group, WilsonCoefLike coeff, ContributionType contribution)
WilsonRequest _req(self, req_or_group, coeff=None, order=None, contribution=None, basis=None)
Scalar get_R(self, req_or_group, coeff=None, order=None, contribution=None, basis=WilsonBasis.STANDARD)
Dict[WCoeff, Scalar] get_all_running(self, WGroup group, QCDOrder order, ContributionType contribution, WilsonBasis basis=WilsonBasis.STANDARD)
Dict[WCoeff, Scalar] get_all_matching(self, WGroup group, QCDOrder order, ContributionType contribution)
"WilsonInterface" add_custom_group(self, CustomWilsonGroupConfig config)
Scalar get_M(self, req_or_group, coeff=None, order=None, contribution=None)
_cpp_contribution(ContributionType contribution)
_cpp_sources(Sequence[ParamId]|Set[ParamId] sources)