<jupyter_start><jupyter_text>The Cholesky Decomposition exists when a matrix is hermitian and positive-definite. It expresses the matrix $\mathbf{A}$ as:\begin{equation}\mathbf{A} = \mathbf{L}\mathbf{L^\dagger}\end{equation}Where $\mathbf{L}$ is a lower-triangular matrix with positive, real diagonal entries. When $\mathbf{A}$ is real, then so is $\mathbf{L}$. The Cholesky decomposition enables fast solution of a linear system, but it can also be used to create correlated random variables in Monte Carlo simulations.  Creating Correlated Random VariablesLet $\mathbf{u}_t$ be a vector of uncorrelated samples with unit standard deviation. If the covariance matrix of the system to be simulated is  $\mathbf{\Sigma}$ with Cholesky decomposition $\mathbf{\Sigma} = \mathbf{LL}^\dagger$, then the vector $\mathbf{v}_t = \mathbf{Lu}_t$ has the desired covariance.<jupyter_code>import numpy as np
import matplotlib.pyplot as plt

np.random.seed = 42

T = 10000
n = 5

M = np.random.randn(*(n,n))
Covar = np.matmul(M.T,M) # random symmetric matrix

L = np.linalg.cholesky(Covar)

print('covar:\n',Covar)
print('L:\n',L)
print('L*L^T:\n',np.matmul(L,L.T))
print('covar - L*L^T = 0',np.allclose(np.matmul(L,L.T)-Covar,0))
u = np.random.randn(*(n,T))
v = np.matmul(L,u)
fig, ax = plt.subplots(2,1,figsize=(12,8)) 
for i in range(n):
    ax[0].plot(np.cumsum(u[i],axis=0))
    ax[1].plot(np.cumsum(v[i],axis=0))
    
ax[0].set_title('Uncorrelated Gaussian Random Walk (mu=0,std=1)')
ax[1].set_title('Correlated')

plt.savefig('img/cholesky1.png')
fig, ax = plt.subplots(2,2,figsize=(8,8))


ax[0][0].imshow(Covar,vmin=np.min(Covar),vmax=np.max(Covar))
ax[0][0].set_title('Covariance: Target')
ax[0][1].imshow(np.cov(u))
ax[0][1].set_title('Covariance: Uncorrelated u')
ax[1][0].imshow(np.cov(v),vmin=np.min(Covar),vmax=np.max(Covar))
ax[1][0].set_title('Covariance: Cholesky Constructed v=Lu')
ax[1][1].imshow(np.log10(np.abs(Covar-np.cov(v))),vmin=np.min(Covar),vmax=np.max(Covar))
ax[1][1].set_title('Error (log10)')

plt.savefig('img/cholesky2.png')<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.1825626204238921, 'fraction_numerical': 0.023603082851637765, 'mean_word_length': 6.088737201365188, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '1', 'dir': 'jupyter-structured-clean-dedup', 'id': '159408', 'license': 'MIT', 'n_tokens_mistral': 852, 'n_tokens_neox': 819, 'n_words': 169, 'path': 'Simulation - Cholesky Decomposition, Correlated Random Variables.ipynb', 'repo_name': 'jpbm/probabilism', 'size': '2076'}