Uncertainty propagation

Installation

Install the pyuncertainnumber library from PyPI.

pip install pyuncertainnumber

Important

A virtual enviroment is recommended for installation.

Follow the instructions for additional details to install pyuncertainnumber.

from pyuncertainnumber import UN
import pyuncertainnumber as pun
import numpy as np
import matplotlib.pyplot as plt

Arithmetic of uncertain numbers

Probability bounds analysis combines both interval analysis and probability theory, allowing rigorous bounds of (arithmetic) functions of random variables to be computed even with partial information.

X = pun.uniform(1, [2,3])
Y = X
fig, axes = plt.subplots(nrows=2, ncols=4, sharey=True, figsize=(12, 6), layout="constrained")

X.plot(ax=axes[0, 0], title='$X, Y \sim U(1, [2,3])$', nuance='curve')

# add Perfect
Z_add_p = X.mul(Y, dependency='p')
Z_add_p.plot(ax=axes[0, 1], title='X+Y Perfect', fill_color='lightblue', nuance='curve')

# mul Opposite
Z_mul_o = X.mul(Y, dependency='o')
Z_mul_f = X.mul(Y, dependency='f')
Z_mul_f.plot(ax=axes[1, 0], title="X × Y Fréchet", fill_color='red', nuance='curve')

# div Independence
Z_div_i = X.div(Y, dependency='i')
Z_div_f = X.div(Y, dependency='f')
Z_div_i.plot(ax=axes[1, 1], title='X/Y Independence', fill_color='orange', nuance='curve')

### unary ops ###
# squared
(X**0.5).plot(ax=axes[0,2], title='$\sqrt{X}$', nuance='curve')

# exponential
X.exp().plot(ax=axes[0,3], title='$e^{X}$', nuance='curve')

# sin
X.sin().plot(ax=axes[1,2], title='$\sin(X)$', nuance='curve')

# tanh
X.tanh().plot(ax=axes[1,3], title=r"$\tanh (X)$", nuance='curve')

plt.show()
../_images/f96e7c7be1dedd82e472c7c5f9c4fde03438b205afe8eb1b61f40be567ca97be.png

Note

beyond arithmetic

Beyond arithmetics, various advanced methods have been proposed for propagation of different types of uncertainties, intrusive or nonintrusive, depending on the characteristic of the performance function such as linearity, monotonicity, or the accessibility to gradients. See additional details in the documentation.

A high-level API has been provided for delpoying these various methods under various uncertainty situations with a consistent signature.

Generic propagation of uncertain numbers

from pyuncertainnumber import Propagation
a = pun.I(2, 3)
b = pun.normal(10, 1)
c = pun.normal([6, 9], 3)
# specify a response function
def foo(x):  
    if isinstance(x, np.ndarray):
        if x.ndim == 1:
            x = x[None, :]
        return x[:, 0] ** 3 + x[:, 1] + x[:, 2]# vectorised signature
    else:
        return x[0] ** 3 + x[1] + x[2]  # iterable signature
# intrusive call signature as drop-in replacements
response = foo([a, b, c])
response.display()
../_images/1a0a0097f1ff69a24d3fba2817b468d523ab74219fa94dc612b9c8b1d955d854.png
# a generic call signature
p = Propagation(vars=[a, b, c], func=foo, method='slicing', interval_strategy='subinterval')
response = p.run(n_slices=50, n_sub=2, style='endpoints')
INFO: mixed uncertainty propagation

Warning

exponentially growing computational load The computational cost increases exponentially with the number of input variables and the number of slices. Be cautious with the choice of number of slices n_slices given the number of input variables of the response function.

response.display()
../_images/b84bfe89767d5e56987c7ba19e57a1b565785287958402be20744a00d88fbe74.png