INPUT MODULE: BLOCK-INDEPENDENT MARGINALS¶

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.

Package imports¶

In [1]:
from uqpylab import sessions
import numpy as np
import pandas as pd
import plotly.express as px
from plotly.subplots import make_subplots

Start a remote UQCloud session¶

In [2]:
# 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.

Probabilistic input model¶

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:

In [3]:
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:

  1. $(X_1,X_4,X_6)$: Vine copula
  2. $(X_3,X_7)$: Gaussian copula
  3. $(X_2,X_8)$: t-pair copula
  4. $X_5$: stand-alone

Specify these three copulas:

In [4]:
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:

In [5]:
myInput = uq.createInput(InputOpts)

Print a report on the INPUT object:

In [6]:
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:

In [7]:
fig = uq.display(myInput)
fig.show()

Validation of block independence¶

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:

In [8]:
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:

In [9]:
X = uq.getSample(myInput,1000)

Calculate the correlation matrix $\mathbf{R}$ on the sample X obtained above

In [10]:
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

In [11]:
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()

Statistical test of block independence¶

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:

In [12]:
(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]

Terminate the remote UQCloud session¶

In [13]:
mySession.quit()
 uqpylab.sessions :: INFO     :: Session 2b2289b7af294e659cc917572c259701 terminated.
Out[13]:
True