Mix uncertainty propagation¶
Different uncertainty models exist to represent uncertainty. It is suggested that aleatory and epistemic uncertainties should have been characterised and propagated distinctly due to their nature and implication. P-box manifests both uncertainties in one structure. In practice, engineering anlyses typically involve uncertainties in various kinds, and therefore deal with mix uncertainty propagation which is typically seen in two forms: pbox propagation or propagation of a mixure of variables of different uncertainty types.
uncertain numbers are most suitable for working with mixed uncertainty problems since the they allow a consistent interface to handle various uncertainties. This notebook will demonstrate two implementations: (i) a low-level one for extra controls; and (ii) a high-level one for simplicity.
You will discover that calling signature is the same.
See also
There is an increasing awareness, among the scientific computation community, of the differentiation of aleatory and epistemic uncertainty and that different methods are needed for characterisation and propagation. See Propagation of epistemic uncertainty for the propagation of epistemic uncertainty and Propagation of aleatory uncertainty for propagation of aleatory uncertainty.
import numpy as np
import matplotlib.pyplot as plt
import pyuncertainnumber as pun
from pyuncertainnumber import pba
P-box propagation¶
low-level implementation¶
def f(x):
"""a universal signature that takes both iterable (1d) and matrix (2d) inputs """
if isinstance(x, np.ndarray): # foo_vectorised signature
if x.ndim == 1:
x = x[None, :]
return x[:, 0] ** 3 + x[:, 1] + x[:, 2]
else:
return x[0] ** 3 + x[1] + x[2] # foo_iterable signature
Note
the importance of inter-variable dependency
a = pba.normal([2,3], [1])
b = pba.normal([10,14], [1])
c = pba.uniform([4,5], [10,11])
with pba.dependency('p'): # perfect dependency
z_p = f([a,b,c])
with pba.dependency('f'): # Frechet dependency
z_f = f([a,b,c])
fig, ax = plt.subplots()
z_p.plot(nuance='curve', ax=ax, fill_color='salmon', label='perfect')
z_f.plot(nuance='curve', ax=ax, label='Frechet')
plt.show()
Tip
intrusive signature: using interval Monte Carlo, consider Gaussian copula.
''' interval Monte Carlo '''
corre_matrix = np.array([[1, 0.5, 0.3], [0.5, 1, 0.4], [0.3, 0.4, 1]])
de = pba.Dependency(family='gaussian', corr=corre_matrix)
t_gau_copula = pun.interval_monte_carlo(
vars=[a,b,c],
func=f,
dependency=de,
interval_strategy='direct',
n_sam=30_000
)
pba.inspect_pbox(t_gau_copula)
Pbox ~ (range=[11.129, 252.204], mean=[34.942, 60.992], var=[457.970, 1668.588])
''' slicing '''
a = pba.normal([2,3], [1])
b = pba.normal([10,14], [1])
c = pba.uniform([4,5], [10,11])
test_ = pun.slicing(
vars=[a,b,c],
func=f,
interval_strategy='direct',
dependency = de,
outer_discretisation=True,
n_slices=100
)
pba.inspect_pbox(test_)
Pbox ~ (range=[12.995, 172.590], mean=[32.912, 58.935], var=[224.453, 1333.884])
A mixture of uncertainties¶
pyuncertainnumber allows you to compute with uncertainty without worrying about the type. This makes the calculation involving a mixture of uncertainty kinds very easy. Below illustrate the example when one has an interval, a probability distribution and also a p-box.
Tip
In terms of a non-intrusive context, one can also use the double Monte Carlo (a.k.a nested Monte Carlo).
# the example in the readme.
a = pba.I(1, 5) # interval
b = pba.normal([10,14], [1]) # pbox
c = pba.uniform(4, 11) # distribution
f([a, b, c]).display()
high-level implementation with uncertain numbers¶
As described in What is an uncertain number, the concept of uncertain numbers encompass intervals, distributions, p-boxes, Dempster Shafer structures, and real numbers. Therefore, the framework of uncertain numbers can natively handle mixed uncertainty problem, and it is no longer mixed any more.
a = pun.I(1, 5) # interval
b = pun.normal([10,14], [1]) # pbox
c = pun.uniform(4, 11) # distribution
p = pun.Propagation(
vars = [a,b,c],
func = f,
method = "slicing",
interval_strategy='endpoints'
)
INFO: mixed uncertainty propagation
un_p = p.run(n_slices=50)
un_p.display()
un_p
UncertainNumber(essence='pbox', _construct=Pbox ~ (range=[13.062, 151.938], mean=[20.587, 147.927], var=[1.280, 4356.734]), nominal_value=84.257)
# surroaget to propagte pbox is udnerway