This example showcases how to define a probabilistic input model with several inter-independent sets (blocks) of random variables. Each block is identified by its own copula, and the copula of the full random vector is given by the tensor product of the copulas of the individual blocks.
from uqpylab import sessions
import numpy as np
import pandas as pd
import plotly.express as px
from plotly.subplots import make_subplots
# Start the session
mySession = sessions.cloud()
# (Optional) Get a convenient handle to the command line interface
uq = mySession.cli
# Reset the session
mySession.reset()
uqpylab.sessions :: INFO :: A new session (2b2289b7af294e659cc917572c259701) started. uqpylab.sessions :: INFO :: Reset successful.
The probabilistic input model consists of eight random variables:
$X_i \sim \mathcal{N}(0, 1) \quad i=1,\ldots,8$
Specify the marginals of these variables:
InputOpts = {
'Marginals': [{'Type':'Gaussian', 'Parameters': [0,1]} for i in np.arange(8)]
}
The random variables are grouped into four independent blocks, each characterized by its own copula:
Specify these three copulas:
InputOpts['Copula'] = [
uq.VineCopula(
'CVine',
[1,2,3],
['Clayton', 'Gumbel', 'Gaussian'],
[1.4, 2.0, 0.3],
[0, 0, 0] ),
uq.GaussianCopula([[1, -.5],[ -.5, 1]]),
uq.PairCopula('t', [.5, 2], 0)
]
InputOpts['Copula'][0]['Variables'] = [[1, 4, 6]]
InputOpts['Copula'][1]['Variables'] = [[3, 7]]
InputOpts['Copula'][2]['Variables'] = [[2, 8]]
Create an INPUT object based on the specified marginals and copulas:
myInput = uq.createInput(InputOpts)
Print a report on the INPUT object:
uq.print(myInput)
============================================================== Input object name: Input 1 Dimension(M): 8 Marginals: Index | Name | Type | Parameters | Moments -------------------------------------------------------------------------- 1 | X1 | Gaussian | 0.000e+00, 1.000e+00 | 0.000e+00, 1.000e+00 2 | X2 | Gaussian | 0.000e+00, 1.000e+00 | 0.000e+00, 1.000e+00 3 | X3 | Gaussian | 0.000e+00, 1.000e+00 | 0.000e+00, 1.000e+00 4 | X4 | Gaussian | 0.000e+00, 1.000e+00 | 0.000e+00, 1.000e+00 5 | X5 | Gaussian | 0.000e+00, 1.000e+00 | 0.000e+00, 1.000e+00 6 | X6 | Gaussian | 0.000e+00, 1.000e+00 | 0.000e+00, 1.000e+00 7 | X7 | Gaussian | 0.000e+00, 1.000e+00 | 0.000e+00, 1.000e+00 8 | X8 | Gaussian | 0.000e+00, 1.000e+00 | 0.000e+00, 1.000e+00 Copula: Tensor product of 4 copulas between the random vectors X_[1 4 6], X_[3 7], X_[2 8], X_5 Copula 1, of X_[1 4 6]: Type: CVine Dimension: 3 Variables coupled: [1 4 6] Structure: [1;2;3] Truncation: 3 (none) Pair copulas: Index | Pair Copula | Family | Rot | Parameters 1 | C_1,4 | Clayton | 0 | 1.4000e+00 2 | C_1,6 | Gumbel | 0 | 2.0000e+00 3 | C_4,6|1 | Gaussian | 0 | 3.0000e-01 Copula 2, of X_[3 7]: Type: Gaussian Dimension: 2 Variables coupled: [3 7] Parameters: [+1.0000 -0.5000 ; -0.5000 +1.0000 ] Copula 3, of X_[2 8]: Type: Pair Variables coupled: [2 8] Family: t Rotation: 0 Parameters: [0.5;2] Copula 4, of X_5: Type: Independent Dimension: 1 Variables coupled: 5 ==============================================================
Display a visualization of the input model:
fig = uq.display(myInput)
fig.show()
The four blocks specified above can be numerically validated that they are mutually independent.
First, get the independent blocks as the sets of variables coupled by each copula:
Blocks = [myInput['Copula'][i]['Variables'] for i in np.arange(len(myInput['Copula']))]
NrBlocks = len(Blocks)
VarNames = [myInput['Marginals'][i]['Name'] for i in np.arange(len(myInput['Marginals']))]
Draw a sample from the input model:
X = uq.getSample(myInput,1000)
Calculate the correlation matrix $\mathbf{R}$ on the sample X
obtained above
df = pd.DataFrame(X, columns=[f'X{var}' for var in range(1,X.shape[1]+1)])
R = round(df.corr(), 3)
fig = px.imshow(R, text_auto='.2f', color_continuous_scale='Blues', title='Full correlation matrix', width=800)
fig.show()
Extract the correlation submatrices corresponding to different blocks and check that they contain values close to 0
fig = make_subplots(rows=3, cols=4, start_cell="top-left")
for idx_i in np.arange(NrBlocks):
for idx_j in np.arange(idx_i+1, NrBlocks):
blk_i = [k-1 for k in Blocks[idx_i]] if isinstance(Blocks[idx_i], list) else [Blocks[idx_i]]
blk_j = [k-1 for k in Blocks[idx_j]] if isinstance(Blocks[idx_j], list) else [Blocks[idx_j]]
fig.add_trace(px.imshow(
R.iloc[blk_i, blk_j],
text_auto='.2f',
color_continuous_scale='Blues',
title=f'Correlation matrix of blocks {Blocks[idx_i]}, {Blocks[idx_j]}:',
width=400).data[0], row=idx_i+1, col=idx_j+1)
fig.update_coloraxes(showscale=False)
fig.update_layout(autosize=False,width=800,height=600,)
fig.show()
UQ[py]Lab also provides the possibility to determine independent blocks of random variables given a multivariate sample set. In this way, the blocks defined above can be tested:
(BlocksHat, PVs, History, Message) = uq.test_block_independence(X.tolist(), 0.05)
print(Message)
Perform block independence test -------------------------------------------------------- [1 4 6] indep [2 3 5 7 8] because all pairs indep -> indep. groups: [1 4 6], [2 3 5 7 8]
mySession.quit()
uqpylab.sessions :: INFO :: Session 2b2289b7af294e659cc917572c259701 terminated.
True