Coverage for src / mppy / scalar.py: 100%
55 statements
« prev ^ index » next coverage.py v7.14.0, created at 2026-05-13 09:54 +0200
« prev ^ index » next coverage.py v7.14.0, created at 2026-05-13 09:54 +0200
1from functools import total_ordering
3import numpy as np
5from .constants import eps,e
7"""
8Class used to represent the scalar.
9It used np.float64 to store the value, but does not inherit from np.float64
10"""
13@total_ordering
14class Scalar:
15 def __init__(self, other):
16 self.__value: np.float64 = np.float64(other)
18 @classmethod
19 def eps(cls) -> Scalar:
20 """
21 Directly returns a scalar with -np.inf as value
22 """
23 return Scalar(eps)
25 @classmethod
26 def e(cls) -> Scalar:
27 """
28 Directly returns a scalar with 0 as value
29 """
30 return Scalar(e)
32 def val(self) -> np.float64:
33 return self.__value
35 def _extract_value(self, other) -> np.float64:
36 """
37 Extracts value from other, if other is a Scalar then other.__value is used, otherwise other is
38 casted to np.float64
39 """
40 return other.__value if isinstance(other, Scalar) else np.float64(other)
42 def __add__(self, other) -> Scalar:
43 """
44 Returns the maximum of self and other
45 """
46 if isinstance(other, Scalar) or isinstance(other, (int, float, np.number)):
47 val = self._extract_value(other)
48 return Scalar(max(self.val(), val))
49 return NotImplemented
51 def __radd__(self, other) -> Scalar:
52 """
53 Returns the maximum of self and other
54 """
55 return self.__add__(other)
57 def __mul__(self, other) -> Scalar:
58 """
59 Returns the addition of self and other
60 """
61 # we need this check so scalar * matrix would not use this __mul__ but the __mul__ of the matrix
62 if isinstance(other, Scalar) or isinstance(other, (int, float, np.number)):
63 val = self._extract_value(other)
64 return Scalar(self.val() + val)
65 return NotImplemented
67 def __rmul__(self, other) -> Scalar:
68 """
69 Returns the addition of self and other
70 """
71 return self.__mul__(other)
73 def __pow__(self, other) -> Scalar:
74 """
75 Returns the product a * n for a^n
76 """
77 if not isinstance(other, (Scalar, np.number, int, float)):
78 raise ValueError("Exponent needs to be scalar or number")
79 exp = self._extract_value(other)
80 if exp == 0:
81 return Scalar.e()
82 return Scalar(self.val() * exp)
84 def __neg__(self) -> Scalar:
85 """
86 Negates the value of the scalar
87 """
88 return Scalar(-self.val())
90 # we only need __lt__ and __eq__, because the class is @total_ordering and any other ordering
91 # can be infered
92 def __lt__(self, other) -> bool:
93 if not isinstance(other, (Scalar, np.number, int, float)):
94 raise ValueError("Scalar can only be compared to other scalars or numbers")
95 val = self._extract_value(other)
96 return self.val() < val
98 def __eq__(self, other) -> bool:
99 if not isinstance(other, (Scalar, np.number, int, float)):
100 return False
101 val = self._extract_value(other)
102 return self.val() == val
104 def __str__(self) -> str:
105 if self.val() == -np.inf:
106 return "ε"
107 else:
108 return f"{self.val()}"