Skip to content

27 arithmetic operations for parameters #43

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 72 commits into from
Aug 14, 2024
Merged
Changes from all commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
a296410
__add__ method in Parameter and DescriptorNumber
damskii9992 Jul 18, 2024
5f0c8a4
__sub__ methods added to Parameter and DescriptorNumber
damskii9992 Jul 18, 2024
0245578
__mul__ added to Parameter and DescriptorNumber
damskii9992 Jul 18, 2024
076c800
Allow additions between similar dimensions
damskii9992 Jul 22, 2024
f26644d
Allow addition with scalars
damskii9992 Jul 22, 2024
ac3c935
add tests for additions
damskii9992 Jul 23, 2024
67d6011
subtraction with scalars
damskii9992 Jul 23, 2024
85449b4
tests for subtraction
damskii9992 Jul 23, 2024
f6763ef
multiplication with scalars
damskii9992 Jul 24, 2024
f543f71
tests for multiplication plus cleanup
damskii9992 Jul 25, 2024
4b8c0af
Divion methods added
damskii9992 Jul 26, 2024
587f653
account for unit cancellation in base_unit method
damskii9992 Jul 26, 2024
ffae7df
account for multiplication with 0
damskii9992 Jul 29, 2024
0a96a87
Add unittests for divisions
damskii9992 Jul 30, 2024
dc617bf
raise ZeroDivisionError
damskii9992 Jul 30, 2024
f553ce7
add __pow__ methods
damskii9992 Jul 31, 2024
8e1a111
Test __pow__ methods
damskii9992 Aug 1, 2024
76bd956
add __neg__ and __abs__ methods
damskii9992 Aug 1, 2024
9394974
Add tests for __neg__ and __abs__
damskii9992 Aug 1, 2024
10e8ab4
ruff
damskii9992 Aug 1, 2024
c0e4110
Merge branch 'develop' into 27-Arithmetic-operations-for-Parameters
damskii9992 Aug 2, 2024
32e47c8
Updated ruff fix
damskii9992 Aug 2, 2024
73ba052
Merge branch '27-Arithmetic-operations-for-Parameters' of https://git…
damskii9992 Aug 2, 2024
a0ff7dc
Fix unit prefixes with "e" numbers
damskii9992 Aug 2, 2024
6f3ee8e
minor code consistency, updated test
henrikjacobsenfys Aug 6, 2024
180a6ee
Change name of new_value
henrikjacobsenfys Aug 6, 2024
ccfaa2c
Add comments about DescriptorNumber
henrikjacobsenfys Aug 6, 2024
817fae2
Changed == to np.isclose
henrikjacobsenfys Aug 6, 2024
0cd009a
Added calls to convert_unit in initialize to ensure unit consistency
henrikjacobsenfys Aug 6, 2024
219d93e
Minor consistency fixes
henrikjacobsenfys Aug 7, 2024
3c972f7
Changed names to be unique_name
henrikjacobsenfys Aug 7, 2024
7edbadb
Auto generate names as unique_name for arithmetic operations
henrikjacobsenfys Aug 7, 2024
182983e
Updated tests
henrikjacobsenfys Aug 7, 2024
6a7a69f
remove unused import
henrikjacobsenfys Aug 8, 2024
e050e0e
Fix commit mistakes and clean tests
damskii9992 Aug 12, 2024
ffbe575
Fix mistakes from Henrik
damskii9992 Aug 14, 2024
ba50aa0
Merge branch 'develop' into 27-Arithmetic-operations-for-Parameters
damskii9992 Aug 14, 2024
b3ba8ae
__add__ method in Parameter and DescriptorNumber
damskii9992 Jul 18, 2024
e6ce024
__sub__ methods added to Parameter and DescriptorNumber
damskii9992 Jul 18, 2024
723cf41
__mul__ added to Parameter and DescriptorNumber
damskii9992 Jul 18, 2024
781fd1d
Allow additions between similar dimensions
damskii9992 Jul 22, 2024
3c29e7b
Allow addition with scalars
damskii9992 Jul 22, 2024
4803432
add tests for additions
damskii9992 Jul 23, 2024
c91732b
subtraction with scalars
damskii9992 Jul 23, 2024
549b9a2
tests for subtraction
damskii9992 Jul 23, 2024
23b275b
multiplication with scalars
damskii9992 Jul 24, 2024
d6bb54c
tests for multiplication plus cleanup
damskii9992 Jul 25, 2024
e2d59eb
Divion methods added
damskii9992 Jul 26, 2024
9bb730a
account for unit cancellation in base_unit method
damskii9992 Jul 26, 2024
e0c4017
account for multiplication with 0
damskii9992 Jul 29, 2024
e3751db
Add unittests for divisions
damskii9992 Jul 30, 2024
0b73c24
raise ZeroDivisionError
damskii9992 Jul 30, 2024
e28732b
add __pow__ methods
damskii9992 Jul 31, 2024
128e6c0
Test __pow__ methods
damskii9992 Aug 1, 2024
871d153
add __neg__ and __abs__ methods
damskii9992 Aug 1, 2024
4b5d6d5
Add tests for __neg__ and __abs__
damskii9992 Aug 1, 2024
1fe5625
Updated ruff fix
damskii9992 Aug 2, 2024
d5aab7c
Fix unit prefixes with "e" numbers
damskii9992 Aug 2, 2024
8f88319
minor code consistency, updated test
henrikjacobsenfys Aug 6, 2024
8eebe74
Change name of new_value
henrikjacobsenfys Aug 6, 2024
02b0b3f
Add comments about DescriptorNumber
henrikjacobsenfys Aug 6, 2024
9c88ed7
Changed == to np.isclose
henrikjacobsenfys Aug 6, 2024
0e3dba3
Added calls to convert_unit in initialize to ensure unit consistency
henrikjacobsenfys Aug 6, 2024
872aea3
Minor consistency fixes
henrikjacobsenfys Aug 7, 2024
a99be72
Changed names to be unique_name
henrikjacobsenfys Aug 7, 2024
a093af0
Auto generate names as unique_name for arithmetic operations
henrikjacobsenfys Aug 7, 2024
b701d45
Updated tests
henrikjacobsenfys Aug 7, 2024
5a11067
remove unused import
henrikjacobsenfys Aug 8, 2024
212da63
Fix commit mistakes and clean tests
damskii9992 Aug 12, 2024
7571f7f
Fix mistakes from Henrik
damskii9992 Aug 14, 2024
c567df8
Merge branch '27-Arithmetic-operations-for-Parameters' of https://git…
damskii9992 Aug 14, 2024
512b03a
Fix rebase error
damskii9992 Aug 14, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
178 changes: 175 additions & 3 deletions src/easyscience/Objects/new_variable/descriptor_number.py
Original file line number Diff line number Diff line change
@@ -8,6 +8,7 @@

import numpy as np
import scipp as sc
from scipp import UnitError
from scipp import Variable

from easyscience.global_object.undo_redo import property_stack_deco
@@ -58,7 +59,7 @@ def __init__(
try:
self._scalar = sc.scalar(float(value), unit=unit, variance=variance)
except Exception as message:
raise ValueError(message)
raise UnitError(message)
super().__init__(
name=name,
unique_name=unique_name,
@@ -68,6 +69,10 @@ def __init__(
parent=parent,
)

# Call convert_unit during initialization to ensure that the unit has no numbers in it, and to ensure unit consistency.
if self.unit is not None:
self.convert_unit(self._base_unit())

@classmethod
def from_scipp(cls, name: str, full_value: Variable, **kwargs) -> DescriptorNumber:
"""
@@ -193,8 +198,8 @@ def convert_unit(self, unit_str: str):
raise TypeError(f'{unit_str=} must be a string representing a valid scipp unit')
try:
new_unit = sc.Unit(unit_str)
except Exception as message:
raise ValueError(message)
except UnitError as message:
raise UnitError(message) from None
self._scalar = self._scalar.to(unit=new_unit)

# Just to get return type right
@@ -225,3 +230,170 @@ def as_dict(self) -> Dict[str, Any]:
raw_dict['unit'] = str(self._scalar.unit)
raw_dict['variance'] = self._scalar.variance
return raw_dict

def __add__(self, other: Union[DescriptorNumber, numbers.Number]) -> DescriptorNumber:
if isinstance(other, numbers.Number):
if self.unit != 'dimensionless':
raise UnitError("Numbers can only be added to dimensionless values")
new_value = self.full_value + other
elif type(other) is DescriptorNumber:
original_unit = other.unit
try:
other.convert_unit(self.unit)
except UnitError:
raise UnitError(f"Values with units {self.unit} and {other.unit} cannot be added") from None
new_value = self.full_value + other.full_value
other.convert_unit(original_unit)
else:
return NotImplemented
descriptor_number= DescriptorNumber.from_scipp(name=self.name, full_value=new_value)
descriptor_number.name=descriptor_number.unique_name
return descriptor_number



def __radd__(self, other: numbers.Number) -> DescriptorNumber:
if isinstance(other, numbers.Number):
if self.unit != 'dimensionless':
raise UnitError("Numbers can only be added to dimensionless values")
new_value = other + self.full_value
else:
return NotImplemented
descriptor_number= DescriptorNumber.from_scipp(name=self.name, full_value=new_value)
descriptor_number.name=descriptor_number.unique_name
return descriptor_number

def __sub__(self, other: Union[DescriptorNumber, numbers.Number]) -> DescriptorNumber:
if isinstance(other, numbers.Number):
if self.unit != 'dimensionless':
raise UnitError("Numbers can only be subtracted from dimensionless values")
new_value = self.full_value - other
elif type(other) is DescriptorNumber:
original_unit = other.unit
try:
other.convert_unit(self.unit)
except UnitError:
raise UnitError(f"Values with units {self.unit} and {other.unit} cannot be subtracted") from None
new_value = self.full_value - other.full_value
other.convert_unit(original_unit)
else:
return NotImplemented
descriptor_number= DescriptorNumber.from_scipp(name=self.name, full_value=new_value)
descriptor_number.name=descriptor_number.unique_name
return descriptor_number

def __rsub__(self, other: numbers.Number) -> DescriptorNumber:
if isinstance(other, numbers.Number):
if self.unit != 'dimensionless':
raise UnitError("Numbers can only be subtracted from dimensionless values")
new_value = other - self.full_value
else:
return NotImplemented
descriptor= DescriptorNumber.from_scipp(name=self.name, full_value=new_value)
descriptor.name=descriptor.unique_name
return descriptor

def __mul__(self, other: Union[DescriptorNumber, numbers.Number]) -> DescriptorNumber:
if isinstance(other, numbers.Number):
new_value = self.full_value * other
elif type(other) is DescriptorNumber:
new_value = self.full_value * other.full_value
else:
return NotImplemented
descriptor_number = DescriptorNumber.from_scipp(name=self.name, full_value=new_value)
descriptor_number.convert_unit(descriptor_number._base_unit())
descriptor_number.name=descriptor_number.unique_name
return descriptor_number

def __rmul__(self, other: numbers.Number) -> DescriptorNumber:
if isinstance(other, numbers.Number):
new_value = other * self.full_value
else:
return NotImplemented
descriptor_number= DescriptorNumber.from_scipp(name=self.name, full_value=new_value)
descriptor_number.name=descriptor_number.unique_name
return descriptor_number

def __truediv__(self, other: Union[DescriptorNumber, numbers.Number]) -> DescriptorNumber:
if isinstance(other, numbers.Number):
original_other = other
if other == 0:
raise ZeroDivisionError("Cannot divide by zero")
new_value = self.full_value / other
elif type(other) is DescriptorNumber:
original_other = other.value
if original_other == 0:
raise ZeroDivisionError("Cannot divide by zero")
new_value = self.full_value / other.full_value
other.value = original_other
else:
return NotImplemented
descriptor_number = DescriptorNumber.from_scipp(name=self.name, full_value=new_value)
descriptor_number.convert_unit(descriptor_number._base_unit())
descriptor_number.name=descriptor_number.unique_name
return descriptor_number

def __rtruediv__(self, other: numbers.Number) -> DescriptorNumber:
if isinstance(other, numbers.Number):
if self.value == 0:
raise ZeroDivisionError("Cannot divide by zero")
new_value = other / self.full_value
else:
return NotImplemented
descriptor_number= DescriptorNumber.from_scipp(name=self.name, full_value=new_value)
descriptor_number.name=descriptor_number.unique_name
return descriptor_number

def __pow__(self, other: Union[DescriptorNumber, numbers.Number]) -> DescriptorNumber:
if isinstance(other, numbers.Number):
exponent = other
elif type(other) is DescriptorNumber:
if other.unit != 'dimensionless':
raise UnitError("Exponents must be dimensionless")
if other.variance is not None:
raise ValueError("Exponents must not have variance")
exponent = other.value
else:
return NotImplemented
try:
new_value = self.full_value ** exponent
except Exception as message:
raise message from None
if np.isnan(new_value.value):
raise ValueError("The result of the exponentiation is not a number")
descriptor_number= DescriptorNumber.from_scipp(name=self.name, full_value=new_value)
descriptor_number.name=descriptor_number.unique_name
return descriptor_number

def __rpow__(self, other: numbers.Number) -> numbers.Number:
if isinstance(other, numbers.Number):
if self.unit != 'dimensionless':
raise UnitError("Exponents must be dimensionless")
if self.variance is not None:
raise ValueError("Exponents must not have variance")
new_value = other ** self.value
else:
return NotImplemented
return new_value

def __neg__(self) -> DescriptorNumber:
new_value = -self.full_value
descriptor_number= DescriptorNumber.from_scipp(name=self.name, full_value=new_value)
descriptor_number.name=descriptor_number.unique_name
return descriptor_number

def __abs__(self) -> DescriptorNumber:
new_value = abs(self.full_value)
descriptor_number= DescriptorNumber.from_scipp(name=self.name, full_value=new_value)
descriptor_number.name=descriptor_number.unique_name
return descriptor_number

def _base_unit(self) -> str:
string = str(self._scalar.unit)
for i, letter in enumerate(string):
if letter == "e":
if string[i:i+2] not in ["e+", "e-"]:
return string[i:]
elif letter not in ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ".", "+", "-"]:
return string[i:]
return ""
Loading
Loading