scinum#
This page contains only API docs. For more info, visit scinum on GitHub or open the example.ipynb notebook on colab or binder:
Scientific numbers with multiple uncertainties and correlation-aware, gaussian propagation and numpy support.
Classes#
Number
#
- class Number(nominal=0.0, uncertainties={})[source]#
Implementation of a scientific number, i.e., a nominal value with named uncertainties. uncertainties should be a dict or convertable to a dict with strings as keys, and the corresponding uncertainties as values. Whereas different formats are accepted for values to 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 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.Examples:
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 }) # get the nominal value via direct access num.nominal # => 2.5 # get the nominal value via __call__() (same as get()) num() # => 2.5 num(direction="nominal") # => 2.5 # get uncertainties num.get_uncertainty("sourceA") # => (0.5, 0.5) num.get_uncertainty("sourceB") # => (1.0, 1.5) num.get_uncertainty("sourceC") # => (0.25, 0.25) num.get_uncertainty("sourceD") # => (0.25, 0.5) num.get_uncertainty("sourceE") # => (1.0, 0.5) num.get_uncertainty("sourceF") # => (0.75, 0.3) # get shifted values via __call__() (same as get()) num(UP, "sourceA") # => 3.0 num(DOWN, "sourceB") # => 1.0 num(UP, ("sourceC", "sourceD")) # => 2.854... num(UP) # => 4.214... (all uncertainties) num((UP, DOWN), "sourceA") # => (3.0, 2.0) # get only the uncertainty (unsigned) num(DOWN, ("sourceE", "sourceF"), unc=True) # => 0.583... # get the uncertainty factor (unsigned) num(DOWN, ("sourceE", "sourceF"), factor=True) # => 1.233... # combined num(DOWN, ("sourceE", "sourceF"), unc=True, factor=True) # => 0.233...
When uncertainties is not a dictionary, it is interpreted as the default uncertainty, named
Number.DEFAULT
.This class redefines most of Python’s magic functions to allow transparent use in standard operations like
+
,*
, etc. Gaussian uncertainty propagation is applied automatically. When operations connect two number instances, their uncertainties are combined assuming there is no correlation. For correlation-aware operations, please refer to methods such asadd()
ormul()
below. Examples:num = Number(5, 1) print(num + 2) # -> '7.0 +-1.0' print(num * 3) # -> '15.0 +-3.0' num2 = Number(2.5, 1.5) print(num + num2) # -> '7.5 +-1.80277563773' print(num * num2) # -> '12.5 +-7.90569415042' num.add(num2, rho=1) print(num) # -> '7.5 +-2.5'
See
str()
for information on string formatting.- classattribute default_format#
type: string
The default format string (
"%s"
) that is used instr()
when no format string was passed.
- classattribute default_style#
type: string
The default style name (
"plain"
) that is used instr()
when no style argument was passed.
- uncertainties[source]#
type: dictionary
The uncertainty dictionary that maps names to 2-tuples holding absolute up/down effects.
- is_numpy#
type: bool (read-only)
Whether or not a NumPy array is wrapped.
- shape#
type: tuple
The shape of the wrapped NumPy array or None, depending on what type is wrapped.
- dtype#
type: type
The default dtype to use when a NumPy array is wrapped. The initial value is
numpy.float32
when NumPy is available, None otherwise.
- get_uncertainty(name: UncertaintyFlag | str = UncertaintyFlag.DEFAULT, direction: UncertaintyDirection | str = UncertaintyDirection.NOMINAL, *, default: T | None = None) float | ndarray[Any, dtype[_ScalarType_co]] | Tuple[float, float] | Tuple[ndarray[Any, dtype[_ScalarType_co]], ndarray[Any, dtype[_ScalarType_co]]] | T [source]#
Returns the absolute up and down variaton in a 2-tuple for an uncertainty name. When direction is set, the particular value is returned instead of a 2-tuple. In case no uncertainty was found and default is not None, that value is returned.
- u(name: UncertaintyFlag | str = UncertaintyFlag.DEFAULT, direction: UncertaintyDirection | str = UncertaintyDirection.NOMINAL, *, default: T | None = None) float | ndarray[Any, dtype[_ScalarType_co]] | Tuple[float, float] | Tuple[ndarray[Any, dtype[_ScalarType_co]], ndarray[Any, dtype[_ScalarType_co]]] | T [source]#
Shorthand for
get_uncertainty()
.
- set_uncertainty(name: UncertaintyFlag | str, value: float | int | ndarray[Any, dtype[_ScalarType_co]] | Tuple[float | int, float | int] | Tuple[ndarray[Any, dtype[_ScalarType_co]], ndarray[Any, dtype[_ScalarType_co]]]) None [source]#
Sets the uncertainty value for an uncertainty name. value should have one of the formats as described in
uncertainties()
.
- combine_uncertaintes(combine_uncs=ALL)[source]#
Returns a copy of this number with certain uncertainties combined. combine can be a dictionary of keys mapping to strings denoting uncertainties that should be combined with keys refering to new names of the combined uncertainties.
When
ALL
, all uncertainties are combined.
- clear(nominal: float | int | ndarray[Any, dtype[_ScalarType_co]] | None = None, uncertainties: float | int | ndarray[Any, dtype[_ScalarType_co]] | Tuple[float | int, float | int] | Tuple[ndarray[Any, dtype[_ScalarType_co]], ndarray[Any, dtype[_ScalarType_co]]] | Dict[str, Tuple[float | int, float | int] | Tuple[ndarray[Any, dtype[_ScalarType_co]], ndarray[Any, dtype[_ScalarType_co]]]] | None = None) None [source]#
Removes all uncertainties and sets the nominal value to zero (float). When nominal and uncertainties are given, these new values are set on this instance.
- str(format: str | int | None = None, combine_uncs: UncertaintyFlag | str | dict[str, Sequence[str]] | None = None, unit: str | None = None, scientific: bool = False, si: bool = False, labels: bool = True, style: str | None = None, styles: dict[str, str] | None = None, force_asymmetric: bool = False, **kwargs) str [source]#
Returns a readable string representiation of the number. format is used to format non-NumPy nominal and uncertainty values. It can be a string such as
"%d"
, a function that is called with the value to format, or a rounding function as accepted byround_value()
. When None (the default),default_format
is used. All keyword arguments except wildcard kwargs are only used to format non-NumPy values. In case of NumPy objects, kwargs are passed to numpy.array2string.When combine_uncs is set, uncertainties are reduced via
combine_uncertaintes()
. When unit is set, it is appended to the end of the string. When scientific is True, all values are represented by their scientific notation. When scientific is False and si is True, the appropriate SI prefix is used.labels controls whether uncertainty labels are shown in the string. When True, uncertainty names are used, but it can also be a list of labels whose order should match the uncertainty dict traversal order. style can be
"plain"
,"fancy"
,"latex"
, or"root"
. When None (the default),default_style
is used.styles can be a dict with fields
"space"
,"label"
,"unit"
,"sym"
,"asym"
,"sci"
to customize every aspect of the format style on top ofstyle_dict
. Unless force_asymmetric is True, an uncertainty is quoted symmetric if it yields identical values in both directions.Examples:
n = Number(17.321, {"a": 1.158, "b": 0.453}) n.str() # -> '17.321 +-1.158 (a) +-0.453 (b)' n.str("%.1f") # -> '17.3 +-1.2 (a) +-0.5 (b)' n.str("publication") # -> '17.32 +-1.16 (a) +-0.45 (b)' n.str("pdg") # -> '17.3 +-1.2 (a) +-0.5 (b)' n.str(combine_uncs="all") # -> '17.321 +-1.2434520497389514' n = Number(8848, 10) n.str(unit="m") # -> "8848.0 +-10.0 m" n.str(unit="m", force_asymmetric=True) # -> "8848.0 +10.0-10.0 m" n.str(unit="m", scientific=True) # -> "8.848 +-0.01 x 1E3 m" n.str("%.2f", unit="m", scientific=True) # -> "8.85 +-0.01 x 1E3 m" n.str(unit="m", si=True) # -> "8.848 +-0.01 km" n.str("%.2f", unit="m", si=True) # -> "8.85 +-0.01 km" n.str(style="fancy") # -> "8848.0 ±10.0" n.str(unit="m", style="fancy") # -> "8848.0 ±10.0 m" n.str(unit="m", style="latex") # -> "8848.0 \pm10.0\,m" n.str(unit="m", style="latex", si=True) # -> "8.848 \pm0.01\,km" n.str(unit="m", style="root") # -> "8848.0 #pm10.0 m" n.str(unit="m", style="root", si=True) # -> "8.848 #pm0.01 km"
- repr(*args, **kwargs) str [source]#
Returns the unique string representation of the number, forwarding all args and kwargs to
str()
.
- copy(nominal: float | int | ndarray[Any, dtype[_ScalarType_co]] | None = None, uncertainties: float | int | ndarray[Any, dtype[_ScalarType_co]] | Tuple[float | int, float | int] | Tuple[ndarray[Any, dtype[_ScalarType_co]], ndarray[Any, dtype[_ScalarType_co]]] | Dict[str, Tuple[float | int, float | int] | Tuple[ndarray[Any, dtype[_ScalarType_co]], ndarray[Any, dtype[_ScalarType_co]]]] | None = None) Number [source]#
Returns a deep copy of the number instance. When nominal or uncertainties are set, they overwrite the fields of the copied instance.
- get(direction: UncertaintyDirection | str | tuple[scinum.UncertaintyDirection | str, scinum.UncertaintyDirection | str] = UncertaintyDirection.NOMINAL, names: UncertaintyFlag | str | Sequence[str] = UncertaintyFlag.ALL, unc: bool = False, factor: bool = False) float | ndarray[Any, dtype[_ScalarType_co]] | Tuple[float, float] | Tuple[ndarray[Any, dtype[_ScalarType_co]], ndarray[Any, dtype[_ScalarType_co]]] [source]#
Returns different representations of the contained value(s). direction should be any of NOMINAL, UP or DOWN, or a tuple containing a combination of them. When not NOMINAL, names decides which uncertainties to take into account for the combination. When unc is True, only the unsigned, combined uncertainty is returned. When False, the nominal value plus or minus the uncertainty is returned. When factor is True, the ratio w.r.t. the nominal value is returned.
- add(other: Number | DeferredResult | float | int | ndarray[Any, dtype[_ScalarType_co]], *, rho: float | int | Correlation | Dict[str, float | int] = 1.0, inplace: bool = True) Number | DeferredResult [source]#
Adds an other
Number
orDeferredResult
instance, propagating all uncertainties. Uncertainties with the same name are combined with the correlation rho, which can either be aCorrelation
instance, a dict with correlations defined per uncertainty, or a plain float. When inplace is False, a new instance is returned.
- sub(other: Number | DeferredResult | float | int | ndarray[Any, dtype[_ScalarType_co]], *, rho: float | int | Correlation | Dict[str, float | int] = 1.0, inplace: bool = True) Number | DeferredResult [source]#
Subtracts an other
Number
orDeferredResult
instance, propagating all uncertainties. Uncertainties with the same name are combined with the correlation rho, which can either be aCorrelation
instance, a dict with correlations defined per uncertainty, or a plain float. When inplace is False, a new instance is returned.
- mul(other: Number | DeferredResult | Correlation | float | int | ndarray[Any, dtype[_ScalarType_co]], *, rho: float | int | Correlation | Dict[str, float | int] = 1.0, inplace: bool = True) Number | DeferredResult [source]#
Multiplies by an other
Number
orDeferredResult
instance, propagating all uncertainties. Uncertainties with the same name are combined with the correlation rho, which can either be aCorrelation
instance, a dict with correlations defined per uncertainty, or a plain float. When inplace is False, a new instance is returned.Unlike the other operations, other can also be a
Correlation
instance, in which case aDeferredResult
is returned to resolve the combination of uncertainties later on.
- div(other: Number | DeferredResult | float | int | ndarray[Any, dtype[_ScalarType_co]], *, rho: float | int | Correlation | Dict[str, float | int] = 1.0, inplace: bool = True) Number | DeferredResult [source]#
Divides by an other
Number
orDeferredResult
instance, propagating all uncertainties. Uncertainties with the same name are combined with the correlation rho, which can either be aCorrelation
instance, a dict with correlations defined per uncertainty, or a plain float. When inplace is False, a new instance is returned.
- pow(other: Number | DeferredResult | float | int | ndarray[Any, dtype[_ScalarType_co]], *, rho: float | int | Correlation | Dict[str, float | int] = 1.0, inplace: bool = True) Number | DeferredResult [source]#
Raises by the power of an other
Number
orDeferredResult
instance, propagating all uncertainties. Uncertainties with the same name are combined with the correlation rho, which can either be aCorrelation
instance, a dict with correlations defined per uncertainty, or a plain float. When inplace is False, a new instance is returned.
UncertaintyDirection
#
UncertaintyFlag
#
Correlation
#
- class Correlation([default, ]**rhos)[source]#
Container class describing correlations to be applied to equally named uncertainties when combining two
Number
instances through an operator.A correlation object is therefore applied to a number by means of multiplication or matrix multiplication (i.e.
*
or@
), resulting in aDeferredResult
object which is used subsequently by the actual combination operation with an other number. SeeDeferredResult
for more examples.Correlation coefficients can be defined per named source of uncertainty via rhos. When a coefficient is retrieved (by
get()
) with a name that was not defined before, a default value is used, which itself defaults to one.
DeferredResult
#
- class DeferredResult(number: Number, correlation: Correlation)[source]#
Class that wraps a
Number
instance number and aCorrelation
instance correlation that is automatically produced as a result of a multiplication or matrix multiplication between the two. Internally, this is used for the deferred resolution of uncertainty correlations when combined with an otherNumber
. Example:n = Number(2, 5) n * Correlation(1) * n # -> '25.0 +-20.0' (the default) n * Correlation(0) * n # -> '25.00 +-14.14' # note the multiplication n * c, which creates the DeferredResult n**(n * c) # -> '3125.00 +-11842.54'
- number#
type: Number
The wrapped number object.
- correlation#
type: Correlation
The wrapped correlation object.
ops
#
- class ops[source]#
Number-aware replacement for the global math (or numpy) module. The purpose of the class is to provide operations (e.g. pow, cos, sin, etc.) that automatically propagate the uncertainties of a
Number
instance through the derivative of the operation. Example:num = ops.pow(Number(5, 1), 2) print(num) # -> 25.00 (+10.00, -10.00)
- classmethod register(function: Callable | None = None, name: str | None = None, py_op: str | None = None, ufuncs: str | Sequence[str] | None = None) Callable[[Callable], Operation] | Operation [source]#
Registers a new math function function with name and returns an
Operation
instance. A math function expects aNumber
as its first argument, followed by optional (keyword) arguments. When name is None, the name of the function is used. The returned object can be used to set the derivative (similar to property). Example:@ops.register def my_op(x): return x * 2 + 1 @my_op.derive def my_op(x): return 2 num = Number(5, 2) print(num) # -> 5.00 (+2.00, -2.00) num = ops.my_op(num) print(num) # -> 11.00 (+4.00, -4.00)
Please note that there is no need to register simple functions as in the particular example above as most of them are just composite operations whose derivatives are already known.
When the registered operation is a member of
operators
and thus capable of propagating uncertainties with two operands, py_op should be set to the symbol of the operation (e.g."*"
, see_py_ops
).To comply with NumPy’s ufuncs (https://numpy.org/neps/nep-0013-ufunc-overrides.html) that are dispatched by
Number.__array_ufunc__()
, an operation might register the ufuncs objects that it handles. When strings, they are interpreted as a name of a NumPy function.
- classmethod get_operation(name: str) Operation [source]#
Returns an operation that was previously registered with name.
- classmethod op(name: str) Operation [source]#
Shorthand for
get_operation()
.
Operation
#
- class Operation(function: Callable, derivative: Callable | None = None, name: str | None = None, py_op: str | Callable | None = None, ufuncs: list[Callable] | None = None)[source]#
Wrapper around a function and its derivative.
- function#
type: function
The wrapped function.
- derivative#
type: function
The wrapped derivative.
- name#
type: string (read-only)
The name of the operation.
- py_op#
type: None, string (read-only)
The symbol referring to an operation that implements uncertainty propagation combining two operands.
- ufuncs#
type: list (read-only)
List of ufunc objects that this operation handles.
typed
#
- class typed(fparse: Callable[[T], T | None] | None = None, *, setter: bool = True, deleter: bool = True, name: str | None = None)[source]#
Shorthand for the most common property definition. Can be used as a decorator to wrap around a single function. Example:
class MyClass(object): def __init__(self): self._foo = None @typed def foo(self, foo): if not isinstance(foo, str): raise TypeError("not a string: {}".format(foo)) return foo myInstance = MyClass() myInstance.foo = 123 # -> TypeError myInstance.foo = "bar" # -> ok print(myInstance.foo) # -> prints "bar"
In the exampe above, set/get calls target the instance member
_foo
, i.e. “_<function_name>”. The member name can be configured by setting name. If setter (deleter) is True (the default), a setter (deleter) method is booked as well. Prior to updating the member when the setter is called, fparse is invoked which may implement sanity checks.
Functions#
combine_uncertainties
#
- combine_uncertainties(op: Callable | Operation | str, unc1: float | ndarray[Any, dtype[_ScalarType_co]], unc2: float | ndarray[Any, dtype[_ScalarType_co]], nom1: float | ndarray[Any, dtype[_ScalarType_co]] | None = None, nom2: float | ndarray[Any, dtype[_ScalarType_co]] | None = None, rho: float = 0.0) float | ndarray[Any, dtype[_ScalarType_co]] [source]#
Combines two uncertainties unc1 and unc2 according to an operator op which must be either
"+"
,"-"
,"*"
,"/"
, or"**"
. The three latter operators require that you also pass the nominal values nom1 and nom2, respectively. The correlation can be configured via rho.
calculate_uncertainty
#
- calculate_uncertainty(terms: dtype[+_ScalarType_co]]]], rho: float | dict[str, float] = 0.0) float | ndarray[Any, dtype[_ScalarType_co]] [source]#
Generically calculates the uncertainty of a quantity that depends on multiple terms. Each term is expected to be a 2-tuple containing the derivative and the uncertainty of the term. Correlations can be defined via rho. When rho is a numner, all correlations are set to this value. It can also be a mapping of a 2-tuple, the two indices of the terms to describe, to their correlation coefficient. In case the indices of two terms are not included in this mapping, they are assumed to be uncorrelated. Example:
calculate_uncertainty([(3, 0.5), (4, 0.5)]) # uncorrelated # -> 2.5 calculate_uncertainty([(3, 0.5), (4, 0.5)], rho=1) # fully correlated # -> 3.5 calculate_uncertainty([(3, 0.5), (4, 0.5)], rho={(0, 1): 1}) # fully correlated # -> 3.5 calculate_uncertainty([(3, 0.5), (4, 0.5)], rho={(1, 2): 1}) # no rho value defined for pair (0, 1), assumes zero correlation # -> 2.5
ensure_number
#
ensure_nominal
#
is_numpy
#
is_ufloat
#
parse_ufloat
#
- parse_ufloat(x: Variable, default_tag: UncertaintyFlag | str = UncertaintyFlag.DEFAULT) tuple[float, dict[str, float | numpy.ndarray[typing.Any, numpy.dtype[+_ScalarType_co]]]] [source]#
Takes a
ufloat
object x from the “uncertainties” package and returns a tuple with two elements containing its nominal value and a dictionary with its uncertainties. When the error components of x contain multiple uncertainties with the same name, they are combined under the assumption of full correlation. When an error component is not tagged, default_tag is used.
infer_math
#
- infer_math(x: Any) module [source]#
Returns the numpy module when
is_numpy()
for x is True, and the math module otherwise.
make_list
#
split_value
#
- split_value(val: float | ndarray[Any, dtype[_ScalarType_co]]) tuple[float, float] | tuple[numpy.ndarray[typing.Any, numpy.dtype[+_ScalarType_co]], numpy.ndarray[typing.Any, numpy.dtype[+_ScalarType_co]]] [source]#
Splits a value val into its significand and decimal exponent (magnitude) and returns them in a 2-tuple. val might also be a numpy array. Example:
split_value(1) # -> (1.0, 0) split_value(0.123) # -> (1.23, -1) split_value(-42.5) # -> (-4.25, 1) a = np.array([1, 0.123, -42.5]) split_value(a) # -> ([1.0, 1.23, -4.25], [0, -1, 1])
The significand will be a float while magnitude will be an integer. val can be reconstructed via
significand * 10**magnitude
.
match_precision
#
- match_precision(val, ref, force_float=False, **kwargs)[source]#
Returns a string version of a value val matching the significant digits as given in ref. val might also be a numpy array. Unless force_float is True, the returned string might represent an integer in case the decimal digits are removed. All remaining kwargs are forwarded to
Decimal.quantize
. Example:match_precision(1.234, "0.1") # -> "1.2" match_precision(1.234, "1.0") # -> "1" match_precision(1.234, "0.1", decimal.ROUND_UP) # -> "1.3" a = np.array([1.234, 5.678, -9.101]) match_precision(a, "0.1") # -> ["1.2", "5.7", "-9.1"]
round_uncertainty
#
- round_uncertainty(unc: float | ndarray[Any, dtype[_ScalarType_co]], method: int | str = 1, precision: int | ndarray[Any, dtype[_ScalarType_co]] | None = None, **kwargs) tuple[float, int, int] | tuple[numpy.ndarray[typing.Any, numpy.dtype[+_ScalarType_co]], numpy.ndarray[typing.Any, numpy.dtype[+_ScalarType_co]], numpy.ndarray[typing.Any, numpy.dtype[+_ScalarType_co]]] [source]#
Rounds an uncertainty unc following a specific method and returns a 3-tuple containing the significant digits as a string, the decimal magnitude that is required to recover the uncertainty, and the precision (== number of significant digits). unc might also be a numpy array. Possible values for the rounding method are:
"pdg"
: Rounding rules as defined by the `PDG<https://pdg.lbl.gov/2021/reviews/rpp2021-rev-rpp-intro.pdf#page=18>`_.
"pdg+1"
: Same rules as for"pdg"
with an additional significant digit."publication"
,"pub"
: Same rules as for``”pdg+1”`` but without the rounding of thefirst three significant digits above 949 to 1000.
positive integer: Enforces a fixed number of significant digits.
By default, the target precision is derived from the rounding method itself. However, a value can be defined to enfore a certain number of significant digits after the rounding took place. This is only useful for methods that include fixed rounding thresholds (
"pdg"
). All remaining kwargs are forwarded tomatch_precision()
which is performing the rounding internally.Example:
round_uncertainty(0.123, 1) # -> ("1", -1, 1) round_uncertainty(0.123, "pub") # -> ("123", -3, 3) round_uncertainty(0.123, "pdg") # -> ("12", -2, 2) round_uncertainty(0.456, 1) # -> ("5", -1, 1) round_uncertainty(0.456, "pub") # -> ("46", -2, 2) round_uncertainty(0.456, "pdg") # -> ("5", -1, 1) round_uncertainty(9.87, 1) # -> ("1", 1, 1) round_uncertainty(9.87, "pub") # -> ("99", -1, 2) round_uncertainty(9.87, "pdg") # -> ("10", 0, 2) # enfore higher precision round_uncertainty(0.987, "pub", precision=3) # -> ("990", -3, 3) round_uncertainty(0.987, "pdg", precision=3) # -> ("100", -2, 3) # numpy array support a = np.array([0.123, 0.456, 0.987]) round_uncertainty(a, "pub") # -> (["123", "46", "987"], [-3, -2, -3], [3, 2, 2])
round_value
#
- round_value(val: Number | float | ndarray[Any, dtype[_ScalarType_co]], unc: float | ~numpy.ndarray[~typing.Any, ~numpy.dtype[~numpy._typing._array_like._ScalarType_co]] | tuple[float | numpy.ndarray[typing.Any, numpy.dtype[+_ScalarType_co]]] | None = None, method: str | int | None = 0, align_precision: bool = True, **kwargs) tuple[str, str | list | tuple | None, int] | tuple[numpy.ndarray[typing.Any, numpy.dtype[+_ScalarType_co]], numpy.ndarray[typing.Any, numpy.dtype[+_ScalarType_co]] | None, numpy.ndarray[typing.Any, numpy.dtype[+_ScalarType_co]]] [source]#
Rounds a number val with an uncertainty unc which can be a single float or array (symmetric) or a 2-tuple (asymmetric up / down) of floats or arrays. It also supports a list of these values for simultaneous evaluation. When val is a
Number
instance, its uncertainties are used in their default iteration order. Returns a 3-tuple containing:The string representation of the central value.
The string representation(s) of uncertainties. The structure is identical to the one passed on unc.
The decimal magnitude.
method controls the behavior of the rounding:
When
"pdg"
,"pdg+1"
,"publication"
, or"pub"
, uncertainties are required and internallyround_uncertainty()
is used to infer the precision based on the smallest uncertainty.When a formatting string is passed, it should have the (default) pattern
"%*.<N>f"
, and N is interpreted as the number of digits after the decimal point.When a negative integer or zero (the default) is passed, the value is interpreted as the number of digits after the decimal point (similar to passing a format string).
When a positive number is passed, it is interpreted as the amount of significant digits to keep, evaluated on the smallest number among either the nominal or uncertainty values.
In case multiple uncertainties are given and the rounding method is uncertainty-based (1. above), the precision is derived based on the smallest uncertainty as a reference and then enforced to the nominal value and all other uncertainties when align_precision is True. Otherwise, values are allowed to have different precisions. All remaining kwargs are forwarded to
match_precision()
which is performing the rounding internally.Examples:
# differnt uncertainty structures round_value(1.23, 0.456, 1) # -> ("12", "5", -1) round_value(1.23, [0.456], 1) # -> ("12", ["5"], -1) round_value(1.23, (0.456, 0.987), 1) # -> ("12", ("5", "10"), -1) round_value(1.23, [(0.456, 0.987)], 1) # -> ("12", [("5", "10")], -1) round_value(1.23, [0.456, 0.987], 1) # -> ("12", ["5", "10"], -1) # different rounding methods round_value(125.09, (0.56, 0.97)) # -> ("125", ("1", "1"), 0) round_value(125.09, (0.56, 0.97), "pub") # -> ("12509", ("56", "97"), -2) round_value(125.09, (0.56, 0.97), "%.2f") # -> ("12509", ("56", "97"), -2) round_value(125.09, (0.56, 0.97), -2) # -> ("12509", ("56", "97"), -2) round_value(125.09, (0.56, 0.97), 3) # -> ("125090", ("560", "970"), -3) # without uncertainties round_value(125.09, method=2) # -> ("13", None, 1) round_value(125.09, method=-2) # -> ("12509", None, -2) round_value(125.09, method="%.2f") # -> ("12509", None, -2) round_value(125.09, method="pdg") # -> Exception, "pdg" is uncertainty based # array support vals = np.array([1.23, 4.56]) uncs = np.array([0.45678, 0.078]) round_value(vals, uncs, 2) # -> (["123", "4560"], ["46", "78"], [-2, -3])
format_multiplicative_uncertainty
#
- format_multiplicative_uncertainty(num: Number, unc: UncertaintyFlag | str | Sequence[UncertaintyFlag | str] = UncertaintyFlag.DEFAULT, digits: int = 3, asym_threshold: float = 0.2) str [source]#
Creates an inline representation of an uncertainty named unc of a
Number
num and returns it. The representation makes use of the mulitiplicative factors that would scale the nominal to the up/down varied values. Example:format_uncertainty_inline(Number(1.4, 0.15j)) # 15% relative uncertainty # -> "1.150" # symmetric format_uncertainty_inline(Number(1.4, (0.15j, 0.1j))) # +15%/-10% relative uncertainty # -> "1.150/0.900" # asymmetric
When the uncertainty is either symmetric within a certain number of digits and the smallest effect is below asym_threshold, the symmetric representation is used (first example). In any other case, the asymmetric version us returned.
infer_si_prefix
#
create_hep_data_representer
#
- create_hep_data_representer(method: str | int | None = None, force_asymmetric: bool = False, force_float: bool = False, **kwargs) Callable [source]#
Creates a PyYAML representer function that encodes a
Number
as a data structure that is compatible to the HEPData format for values in data files.import yaml import scinum as sn yaml.add_representer(sn.Number, sn.create_hep_data_representer())
For documentation of the rounding method, see
round_uncertainty()
. When None, the default_format of the number instance is used in case it is not a python format string. Otherwise3
is assumed, i.e., 3 significant digits. When the up and down variations of an uncertainty are identical after rounding, they are encoded as a symmetric uncertainty unless force_asymmetric is True. Also, when all decimal digits are removed during rounding, the final value is encoded as an integer value unless force_float is True.All remaining kwargs are forwarded to
match_precision()
which is performing the rounding internally.
Other attributes#
- style_dict#
- type: dict
Dictionaly containing formatting styles for
"plain"
,"latex"
and"root"
styles which are used inNumber.str()
. Each style dictionary contains 6 fields:"space"
,"label"
,"unit"
,"sym"
,"asym"
, and"sci"
. As an example, the plain style is configured as{ "space": " ", "label": "({label})", "unit": " {unit}", "sym": "+- {unc}", "asym": "+{up}-{down}", "sci": "x 1E{mag}", }
- HAS_NUMPY#
- type: bool
A flag that is True when NumPy is available on your system, False otherwise.
- HAS_UNCERTAINTIES#
- type: bool
A flag that is True when the uncertainties package is available on your system, False otherwise.
- HAS_YAML#
- type: bool
A flag that is True when PyYAML is available on your system, False otherwise.