scinum¶
This page contains only API docs. For more info, visit scinum on GitHub or open the example.ipynb notebook on binder:
Contents
Scientific numbers with multiple uncertainties and correlationaware, gaussian propagation and numpy support.
Classes¶
Number
¶

class
Number
(nominal=0.0, uncertainties={})¶ Implementation of a scientific number, i.e., a nominal value with named uncertainties. uncertainties mist be a dict or convertable to a dict with strings as keys. If a value is an int or float, it is interpreted as an absolute, symmetric uncertainty. If it is a tuple, it is interpreted in different ways. Examples:
from scinum import Number, REL, ABS, 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": (REL, 0.1), # relative 10%, both up and down "sourceD": (REL, 0.1, 0.2), # relative 10% up, 20% down "sourceE": (1.0, REL, 0.2), # absolute 1.0 up, relative 20% down "sourceF": (REL, 0.3, ABS, 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) # get only the uncertainty (unsigned) num(DOWN, ("sourceE", "sourceF"), diff=True) # => 0.583... # get the uncertainty factor (unsigned) num(DOWN, ("sourceE", "sourceF"), factor=True) # => 1.233... # combined num(DOWN, ("sourceE", "sourceF"), diff=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 correlationaware 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
¶ The default format string (
"%s"
) that is used instr()
when no format string was passed.

classattribute
DEFAULT
¶ Constant that denotes the default uncertainty (
"default"
).

classattribute
ALL
¶ Constant that denotes all uncertainties (
"all"
).

classattribute
REL
¶ Constant that denotes relative errors (
"rel"
).

classattribute
ABS
¶ Constant that denotes absolute errors (
"abs"
).

classattribute
NOMINAL
¶ Constant that denotes the nominal value (
"nominal"
).

classattribute
UP
¶ Constant that denotes the up direction (
"up"
).

classattribute
DOWN
¶ Constant that denotes the down direction (
"down"
).

nominal
¶ 
type: float
The nominal value.

uncertainties
¶ 
type: dictionary
The uncertainty dictionary that maps names to 2tuples holding absolute up/down effects.

is_numpy
¶ 
type: bool

readonly
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='default', direction=None, default=None)¶ Returns the absolute up and down variaton in a 2tuple for an uncertainty name. When direction is set, the particular value is returned instead of a 2tuple. In case no uncertainty was found and default is not None, that value is returned.

u
(*args, **kwargs)¶ Shorthand for
get_uncertainty()
.

set_uncertainty
(name, value)¶ Sets the uncertainty value for an uncertainty name. value should have one of the formats as described in
uncertainties()
.

clear
(nominal=None, uncertainties=None)¶ 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=None, unit=None, scientific=False, si=False, labels=True, style='plain', styles=None, force_asymmetric=False, **kwargs)¶ Returns a readable string representiation of the number. format is used to format nonNumPy 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 nonNumPy values. In case of NumPy objects, kwargs are passed to numpy.array2string.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"
,"latex"
, or"root"
. 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 = Number(8848, 10) n.str(unit="m") # > "8848.0 + 10.0 m" n.str(unit="m", force_asymmetric=True) # > "8848.0 +10.010.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(unit="m", style="latex") # > "8848.0 \pm 10.0\,m" n.str(unit="m", style="latex", si=True) # > "8.848 \pm 0.01\,km" n.str(unit="m", style="root") # > "8848.0 #pm 10.0 m" n.str(unit="m", style="root", si=True) # > "8.848 #pm 0.01 km"

repr
(*args, **kwargs)¶ Returns the unique string representation of the number.

copy
(nominal=None, uncertainties=None)¶ Returns a deep copy of the number instance. When nominal or uncertainties are set, they overwrite the fields of the copied instance.

get
(direction=NOMINAL, names=ALL, diff=False, factor=False)¶ Returns different representations of the contained value(s). direction should be any of NOMINAL, UP or DOWN. When not NOMINAL, names decides which uncertainties to take into account for the combination. When diff 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, rho=1.0, inplace=True)¶ 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, rho=1.0, inplace=True)¶ 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, rho=1.0, inplace=True)¶ 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, rho=1.0, inplace=True)¶ 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, rho=1.0, inplace=True)¶ 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.

classattribute
Correlation
¶

class
Correlation
([default, ]**rhos)¶ 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.
get
(name, default=None)¶ Returns a correlation coefficient rho named name. When no coefficient with that name exists and default is set, which itself defaults to
default
, this value is returned instead. Otherwise, a KeyError is raised.

DeferredResult
¶

class
DeferredResult
(number, correlation)¶ 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
¶ Numberaware 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=None, name=None, ufunc=None)¶ 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.
To comply with numpy’s ufuncs (https://numpy.org/neps/nep0013ufuncoverrides.html) that are dispatched by
Number.__array_ufunc__()
, an operation might register the ufunc object that it handles. When ufunc is a string, it is interpreted as a name of a numpy function. It can also be a list to signalize that it handles more than one function.

classmethod
get_operation
(name)¶ Returns an operation that was previously registered with name.

classmethod
op
(*args, **kwargs)¶ Shorthand for
get_operation()
.

classmethod
get_ufunc_operation
(ufunc)¶ Returns an operation that was previously registered to handle a NumPy ufunc, which can be a string or the function itself. None is returned when no operation was found to handle the function.

classmethod
rebuilt_ufunc_cache
()¶ Rebuilts the internal cache of ufuncs.

classmethod
Operation
¶

class
Operation
(function, derivative=None, name=None, ufuncs=None)¶ Wrapper around a function and its derivative.

function
¶ 
type: function
The wrapped function.

derivative
¶ 
type: function
The wrapped derivative.

name
¶ 
type: string

readonly
The name of the operation.

ufuncs
¶ 
type: list

readonly
List of ufunc objects that this operation handles.

typed
¶

class
typed
(fparse=None, setter=True, deleter=True, name=None)¶ 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, unc1, unc2, nom1=None, nom2=None, rho=0.0)¶ 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, rho=0.0)¶ Generically calculates the uncertainty of a quantity that depends on multiple terms. Each term is expected to be a 2tuple 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 2tuple, 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_numpy
(x)¶ Returns True when numpy is available on your system and x is a numpy type.
is_ufloat
¶

is_ufloat
(x)¶ Returns True when the “uncertainties” package is available on your system and x is a
ufloat
.
parse_ufloat
¶

parse_ufloat
(x, default_tag='default')¶ 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)¶ Returns the numpy module when
is_numpy()
for x is True, and the math module otherwise.
make_list
¶

make_list
(obj, cast=True)¶ Converts an object obj to a list and returns it. Objects of types tuple and set are converted if cast is True. Otherwise, and for all other types, obj is put in a new list.
split_value
¶

split_value
(val)¶ Splits a value val into its significand and decimal exponent (magnitude) and returns them in a 2tuple. 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., 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, *args, **kwargs)¶ Returns a string version of a value val matching the significant digits as given in ref. val might also be a numpy array. All remaining args and kwargs are forwarded to
Decimal.quantize
. Example:match_precision(1.234, ".1") # > "1.2" match_precision(1.234, "1.") # > "1" match_precision(1.234, ".1", decimal.ROUND_UP) # > "1.3" a = np.array([1.234, 5.678, 9.101]) match_precision(a, ".1") # > ["1.2", "5.7", "9.1"]
round_uncertainty
¶

round_uncertainty
(unc, method='publication')¶ Rounds an uncertainty unc following a specific method and returns a 2tuple containing the significant digits as a string, and the decimal magnitude that is required to recover the uncertainty. unc might also be a numpy array. Rounding methods:
"pdg"
: Rounding rules as defined by the PDG."publication"
,"pub
: Like"pdg"
with an extra significant digit for results that need to be combined later."onedigit"
,"one"
: Forces one single significant digit. This is useful when there are multiple uncertainties that vary by more than a factor 10 among themselves.
Example:
round_uncertainty(0.123, "pub") # > ("123", 3) round_uncertainty(0.123, "pdg") # > ("12", 2) round_uncertainty(0.123, "one") # > ("1", 1) round_uncertainty(0.456, "pub") # > ("46", 2) round_uncertainty(0.456, "pdg") # > ("5", 1) round_uncertainty(0.456, "one") # > ("5", 1) round_uncertainty(0.987, "pub") # > ("987", 3) round_uncertainty(0.987, "pdg") # > ("10", 1) round_uncertainty(0.987, "one") # > ("10", 1) a = np.array([0.123, 0.456, 0.987]) round_uncertainty(a, "pub") # > (["123", "46", "987"], [3, 2, 3])
round_value
¶

round_value
(val, unc=None, unc_down=None, method='publication')¶ Rounds a number val with a single symmetric uncertainty unc or asymmetric uncertainties unc (interpreted as the up variation) and unc_down, and calculates the orders of their magnitudes. They both can be a float or a list of floats for simultaneous evaluation. When val is a
Number
instance, its combined uncertainty is used instead. Returns a 3tuple containing:The string representation of the central value.
The string representations of the uncertainties in a list. For the symmetric case, this list contains only one element.
The decimal magnitude.
Examples:
round_value(1.23, 0.456) # > ("123", ["46"], 2) round_value(1.23, 0.456, 0.987) # > ("123", ["46", "99"], 2) round_value(1.23, [0.456, 0.312]) # > ("123", [["456", "312"]], 3) vals = np.array([1.23, 4.56]) uncs = np.array([0.45678, 0.078]) round_value(vals, uncs) # > (["1230", "4560"], [["457", "78"]], 3)
infer_si_prefix
¶

infer_si_prefix
(f)¶ Infers the SI prefix of a value f and returns the string label and decimal magnitude in a 2tuple. Example:
infer_si_prefix(1) # > ("", 0) infer_si_prefix(25) # > ("", 0) infer_si_prefix(4320) # > ("k", 3)
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.

NOMINAL
¶ 
type: string
Shorthand for
Number.NOMINAL
.

DOWN
¶ 
type: string
Shorthand for
Number.DOWN
.

REL
¶ 
type: string
Shorthand for
Number.REL
.

ABS
¶ 
type: string
Shorthand for
Number.ABS
.