Hyperiso 1.0.3
Modular flavour-physics calculations, Wilson coefficients and statistical inference
Loading...
Searching...
No Matches
Scalar.py
Go to the documentation of this file.
1"""Scalar wrapper and elementary operations exposed by the native backend."""
2
3from pyhyperiso.phyperiso.pyhyperiso import math as ma
4from typing import Union
5
6
7class Scalar:
8 """Python wrapper for the C++ scalar_t class.
9
10 scalar_t is an enhanced complex number type that supports real projection,
11 full arithmetic, and compatibility with Python's numeric types.
12 """
13
14 def __init__(self, re: float = 0.0, im: float = 0.0):
15 """Initializes a Scalar from real and imaginary parts.
16
17 Args:
18 re (float): Real part. Defaults to 0.0.
19 im (float): Imaginary part. Defaults to 0.0.
20 """
21 self._cpp_obj = ma.scalar_t(re, im)
22
23 @classmethod
24 def from_complex(cls, z: complex) -> "Scalar":
25 """Creates a Scalar from a complex number.
26
27 Args:
28 z (complex): A Python complex.
29
30 Returns:
31 Scalar: A wrapped scalar_t.
32 """
33 instance = cls()
34 instance._cpp_obj = ma.scalar_t(z)
35 return instance
36
37 def real(self) -> float:
38 """Returns the real part.
39
40 ``Scalar.from_cpp`` can receive either a bound ``scalar_t`` object or a
41 native Python ``complex`` depending on the pybind overload that produced
42 the value. The C++ object exposes ``real()`` as a method, while Python
43 complex exposes ``real`` as a float attribute; both forms are supported.
44
45 Returns:
46 float: Real component.
47 """
48 real_attr = getattr(self._cpp_obj, "real")
49 return float(real_attr() if callable(real_attr) else real_attr)
50
51 def imag(self) -> float:
52 """Returns the imaginary part.
53
54 Supports both bound ``scalar_t.imag()`` and Python ``complex.imag``.
55
56 Returns:
57 float: Imaginary component.
58 """
59 imag_attr = getattr(self._cpp_obj, "imag")
60 return float(imag_attr() if callable(imag_attr) else imag_attr)
61
62 def to_double(self) -> float:
63 """Casts to float using the real part.
64
65 Bound ``scalar_t`` still uses its native ``to_double()`` implementation.
66 Native Python numbers/complex values use ``real()``.
67
68 Returns:
69 float: Real part.
70 """
71 to_double = getattr(self._cpp_obj, "to_double", None)
72 if callable(to_double):
73 return float(to_double())
74 return self.real()
75
76 def __float__(self) -> float:
77 """Casts to float, calling to_double.
78
79 Returns:
80 float: Real part.
81 """
82 return self.to_double()
83
84 def __complex__(self) -> complex:
85 """Casts to Python complex.
86
87 Returns:
88 complex: Native Python complex value.
89 """
90 return complex(self.real(), self.imag())
91
92 def __add__(self, other: "Scalar") -> "Scalar":
93 result = Scalar()
94 result._cpp_obj = self._cpp_obj + other._cpp_obj
95 return result
96
97 def __sub__(self, other: "Scalar") -> "Scalar":
98 result = Scalar()
99 result._cpp_obj = self._cpp_obj - other._cpp_obj
100 return result
101
102 def __mul__(self, other: "Scalar") -> "Scalar":
103 result = Scalar()
104 result._cpp_obj = self._cpp_obj * other._cpp_obj
105 return result
106
107 def __truediv__(self, other: "Scalar") -> "Scalar":
108 result = Scalar()
109 result._cpp_obj = self._cpp_obj / other._cpp_obj
110 return result
111
112 def __neg__(self) -> "Scalar":
113 result = Scalar()
114 result._cpp_obj = -self._cpp_obj
115 return result
116
117 def __eq__(self, other: object) -> bool:
118 if not isinstance(other, Scalar):
119 return False
120 return self.real() == other.real() and self.imag() == other.imag()
121
122 @classmethod
123 def from_cpp(cls, cpp_obj) -> "Scalar":
124 """Wraps an existing C++ scalar_t object."""
125 instance = cls()
126 instance._cpp_obj = cpp_obj
127 return instance
128
129 def __repr__(self) -> str:
130 return f"Scalar({self.real()}, {self.imag()})"
131
132
133def _to_scalar(value: Union[float, complex, Scalar]) -> Scalar:
134 """Helper to convert float/complex to Scalar."""
135 if isinstance(value, Scalar):
136 return value
137 elif isinstance(value, (float, int)):
138 return Scalar(value)
139 elif isinstance(value, complex):
140 return Scalar.from_complex(value)
141 else:
142 raise TypeError(f"Expected float, complex or Scalar, got {type(value)}")
143
144
145# -------- Math function wrappers -------- #
146
147
148def _wrap_math_func(cpp_func):
149 def wrapped(x: Scalar) -> Scalar:
150 result = Scalar()
151 result._cpp_obj = cpp_func(x._cpp_obj)
152 return result
153
154 return wrapped
155
156
157# Map to C++ functions
158sqrt = _wrap_math_func(ma.sqrt)
159sin = _wrap_math_func(ma.sin)
160cos = _wrap_math_func(ma.cos)
161tan = _wrap_math_func(ma.tan)
162asin = _wrap_math_func(ma.asin)
163acos = _wrap_math_func(ma.acos)
164atan = _wrap_math_func(ma.atan)
165exp = _wrap_math_func(ma.exp)
166log = _wrap_math_func(ma.log)
167sinh = _wrap_math_func(ma.sinh)
168cosh = _wrap_math_func(ma.cosh)
169tanh = _wrap_math_func(ma.tanh)
170abs_scalar = _wrap_math_func(ma.abs)
171arg = _wrap_math_func(ma.arg)
172norm = _wrap_math_func(ma.norm)
173
174
175def pow_scalar(base: Scalar, exponent: Union[Scalar, float, int]) -> Scalar:
176 """Raises a Scalar to a scalar/int/float exponent.
177
178 Args:
179 base (Scalar): The base.
180 exponent (Union[Scalar, float, int]): The exponent.
181
182 Returns:
183 Scalar: Result of exponentiation.
184 """
185 if isinstance(exponent, Scalar):
186 cpp = ma.pow(base._cpp_obj, exponent._cpp_obj)
187 elif isinstance(exponent, (float, int)):
188 cpp = ma.pow(base._cpp_obj, float(exponent))
189 else:
190 raise TypeError("Exponent must be Scalar, float, or int")
191 result = Scalar()
192 result._cpp_obj = cpp
193 return result
float imag(self)
Definition Scalar.py:51
float to_double(self)
Definition Scalar.py:62
__init__(self, float re=0.0, float im=0.0)
Definition Scalar.py:14
"Scalar" __sub__(self, "Scalar" other)
Definition Scalar.py:97
float real(self)
Definition Scalar.py:37
bool __eq__(self, object other)
Definition Scalar.py:117
"Scalar" __neg__(self)
Definition Scalar.py:112
"Scalar" __add__(self, "Scalar" other)
Definition Scalar.py:92
str __repr__(self)
Definition Scalar.py:129
float __float__(self)
Definition Scalar.py:76
"Scalar" from_cpp(cls, cpp_obj)
Definition Scalar.py:123
"Scalar" from_complex(cls, complex z)
Definition Scalar.py:24
"Scalar" __mul__(self, "Scalar" other)
Definition Scalar.py:102
"Scalar" __truediv__(self, "Scalar" other)
Definition Scalar.py:107
complex __complex__(self)
Definition Scalar.py:84
Scalar pow_scalar(Scalar base, Union[Scalar, float, int] exponent)
Definition Scalar.py:175
_wrap_math_func(cpp_func)
Definition Scalar.py:148