Skip to content

Commit

Permalink
Remove old 'marker' syntax for uncertainties.
Browse files Browse the repository at this point in the history
  • Loading branch information
riga committed Oct 11, 2023
1 parent d57b857 commit 2007424
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 76 deletions.
17 changes: 7 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,18 +94,15 @@ Use single values to denote symmetric uncertainties, and tuples for asymmetric o
Float values refer to absolute values whereas complex numbers (only their imaginary part) define relative effects.

```python
from scinum import Number, ABS, REL
from scinum import Number

num = Number(2.5, {
"sourceA": 0.5, # absolute 0.5, both up and down
"sourceB": (1.0, 1.5), # absolute 1.0 up, 1.5 down
"sourceC": 0.1j, # relative 10%, both up and down
"sourceD": (0.1j, 0.2j), # relative 10% up, relative 20% down
"sourceE": (1.0, 0.2j), # absolute 1.0 up, relative 20% down
"sourceF": (0.3j, 0.3), # relative 30% up, absolute 0.3 down
# the old 'marker' syntax
"sourceG": (REL, 0.1, 0.2), # relative 10% up, relative 20% down
"sourceH": (REL, 0.1, ABS, 0.2), # relative 10% up, absolute 0.2 down
"sourceA": 0.5, # absolute 0.5, both up and down
"sourceB": (1.0, 1.5), # absolute 1.0 up, 1.5 down
"sourceC": 0.1j, # relative 10%, both up and down
"sourceD": (0.1j, 0.2j), # relative 10% up, relative 20% down
"sourceE": (1.0, 0.2j), # absolute 1.0 up, relative 20% down
"sourceF": (0.3j, 0.3), # relative 30% up, absolute 0.3 down
})
```

Expand Down
11 changes: 0 additions & 11 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -211,17 +211,6 @@ Other attributes

Shorthand for :py:attr:`Number.DOWN`.

.. py:attribute:: REL
type: string

Shorthand for :py:attr:`Number.REL`.

.. py:attribute:: ABS
type: string

Shorthand for :py:attr:`Number.ABS`.


.. |colab| image:: https://colab.research.google.com/assets/colab-badge.svg
:target: https://colab.research.google.com/github/riga/scinum/blob/master/example.ipynb
:alt: Open in colab
Expand Down
72 changes: 23 additions & 49 deletions scinum/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
__all__ = [
"Number", "Correlation", "DeferredResult", "Operation",
"ops", "style_dict",
"REL", "ABS", "NOMINAL", "UP", "DOWN", "N", "U", "D",
"NOMINAL", "UP", "DOWN", "N", "U", "D",
]


Expand Down Expand Up @@ -162,36 +162,28 @@ class Number(object):
denote whether the passed value is relative or absolute, it should be noted that after some
initial parsing, they are always stored as absolute numbers represented by floats internally.
Uncertainty values can be normal floats to denote absolute, or a complex number to denote
Uncertainty values can be normal floats to denote absolute, or complex numbers to denote
relative values. In the latter case, only the imaginary part is used, meaning that one only
needs to append the complex ``j`` (e.g. ``0.3j`` for a 30% effect). Asymmetric uncertainties can
be defined by passing a 2-tuple of the above values, describing the up and down effect.
In previous versions of scinum, relative uncertainties could only be denoted using a marker-like
syntax, using the :py:attr:`REL` and :py:attr:`ABS` flags. This format is still supported as it
avoids copying values (e.g. large NumPy arrays) to make them complex. However, the complex
number syntax is recommended in all other scenarios.
Examples:
.. code-block:: python
from scinum import Number, REL, ABS, UP, DOWN
from scinum import Number, UP, DOWN
num = Number(2.5, {
"sourceA": 0.5, # absolute 0.5, both up and down
"sourceB": (1.0, 1.5), # absolute 1.0 up, 1.5 down
"sourceC": 0.1j, # relative 10%, both up and down
"sourceD": (0.1j, 0.2j), # relative 10% up, relative 20% down
"sourceE": (1.0, 0.2j), # absolute 1.0 up, relative 20% down
"sourceF": (0.3j, 0.3), # relative 30% up, absolute 0.3 down
# examples using the old 'marker' syntax
"sourceG": (REL, 0.1, 0.2), # relative 10% up, relative 20% down
"sourceH": (REL, 0.1, ABS, 0.2), # relative 10% up, absolute 0.2 down
"sourceA": 0.5, # absolute 0.5, both up and down
"sourceB": (1.0, 1.5), # absolute 1.0 up, 1.5 down
"sourceC": 0.1j, # relative 10%, both up and down
"sourceD": (0.1j, 0.2j), # relative 10% up, relative 20% down
"sourceE": (1.0, 0.2j), # absolute 1.0 up, relative 20% down
"sourceF": (0.3j, 0.3), # relative 30% up, absolute 0.3 down
})
# get the nominal value via direct access
num.nominal # => 2.5
num.nominal # => 2.5
# get the nominal value via __call__() (same as get())
num() # => 2.5
Expand Down Expand Up @@ -271,18 +263,6 @@ class Number(object):
Constant that denotes all uncertainties (``"all"``).
.. py:classattribute:: REL
type: string
Constant that denotes relative errors (``"rel"``).
.. py:classattribute:: ABS
type: string
Constant that denotes absolute errors (``"abs"``).
.. py:classattribute:: NOMINAL
type: string
Expand Down Expand Up @@ -361,10 +341,6 @@ class Number(object):
DEFAULT = "default"
ALL = "all"

# uncertainty types
REL = "rel"
ABS = "abs"

# uncertainty directions
NOMINAL = "nominal"
UP = "up"
Expand Down Expand Up @@ -480,20 +456,21 @@ def uncertainties(
elif not isinstance(val, tuple):
raise TypeError(f"invalid uncertainty type: {val}")

# check the length
if len(val) == 0:
continue
if len(val) == 1:
val = 2 * val
if len(val) != 2:
raise ValueError(f"invalid uncertainty format: {val}")

# parse the value itself
utype, up, down = self.ABS, None, None
utype, up, down = "abs", None, None
for v in val:
# check if v changes the uncertainty type for subsequent values
if isinstance(v, str):
if v not in (self.ABS, self.REL):
raise ValueError(f"unknown uncertainty type: {v}")
utype = v
continue

# interpret complex numbers as relative uncertainties
_utype = utype
if isinstance(v, complex):
_utype = self.REL
_utype = "rel"
v = v.imag

# parse the value
Expand All @@ -511,7 +488,7 @@ def uncertainties(
raise TypeError(f"invalid uncertainty value: {v}")

# convert to abs
if _utype == self.REL:
if _utype == "rel":
v *= self.nominal

# store the value
Expand Down Expand Up @@ -720,8 +697,7 @@ def str(
style=style,
styles=styles,
force_asymmetric=force_asymmetric,
**kwargs # noqa

**kwargs,
)

if not self.is_numpy:
Expand Down Expand Up @@ -1282,8 +1258,6 @@ def __ipow__(self: Number, other: Number | float | np_array) -> Number:


# module-wide shorthands for Number flags
REL = Number.REL
ABS = Number.ABS
NOMINAL = Number.NOMINAL
UP = Number.UP
DOWN = Number.DOWN
Expand Down Expand Up @@ -2768,7 +2742,7 @@ def fmt(x, sign=1.0):
sign * float(x) * 10.0**mag,
10.0**mag,
force_float=force_float,
**kwargs # noqa
**kwargs,
)

# build error nodes
Expand Down
12 changes: 6 additions & 6 deletions tests/test_number.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,10 @@ def __init__(self: TestCase, *args, **kwargs) -> None:
("A", 0.5),
("B", (1.0,)),
("C", (1.0, 1.5)),
("D", (Number.REL, 0.1)),
("E", (Number.REL, 0.1, 0.2)),
("F", (1.0, Number.REL, 0.2)),
("G", (Number.REL, 0.3, Number.ABS, 0.3)),
("D", (0.1j)),
("E", (0.1j, 0.2j)),
("F", (1.0, 0.2j)),
("G", (0.3j, 0.3)),
("H", (0.3j, 0.3)),
]))

Expand Down Expand Up @@ -189,7 +189,7 @@ def test_string_formats(self: TestCase) -> None:

def test_string_flags(self: TestCase) -> None:
n = Number(8848, {"stat": (30, 20)})
n.set_uncertainty("syst", (Number.REL, 0.5))
n.set_uncertainty("syst", (0.5j))

self.assertEqual(n.str(), "8848.0 +30.0-20.0 (stat) +-4424.0 (syst)")
self.assertEqual(n.str(scientific=True), "8.848 +0.03-0.02 (stat) +-4.424 (syst) x 1E3")
Expand Down Expand Up @@ -224,7 +224,7 @@ def test_uncertainty_parsing(self: TestCase) -> None:
self.assertEqual(uncs["H"], (0.75, 0.3))

num = self.num.copy()
num.set_uncertainty("I", (Number.REL, 0.5, Number.ABS, 0.5))
num.set_uncertainty("I", (0.5j, 0.5))
self.assertEqual(num.get_uncertainty("I"), (1.25, 0.5))
num.set_uncertainty("J", (0.5j, 0.5))
self.assertEqual(num.get_uncertainty("J"), (1.25, 0.5))
Expand Down

0 comments on commit 2007424

Please sign in to comment.