Source code for copul.family.elliptical.multivar_elliptical_copula

import sympy as sp
from abc import abstractmethod

from copul.family.core.copula import Copula


[docs] class MultivariateEllipticalCopula(Copula): """ Abstract base class for multivariate elliptical copulas. Elliptical copulas are derived from elliptical distributions and are characterized by a correlation structure. In the multivariate case, they are defined by a correlation matrix R. """ t = sp.symbols("t", positive=True) # symbols rho_ij for off-diagonal elements of the correlation matrix rho = sp.symbols("rho") params = [rho] generator = None def __init__(self, dimension, *args, corr_matrix=None, **kwargs): """ Initialize a multivariate elliptical copula. Parameters ---------- dimension : int, optional Dimension of the copula. If None, it will use the dimension from kwargs. corr_matrix : array_like or sympy.Matrix, optional Correlation matrix. If None, an identity matrix is used. *args, **kwargs Additional arguments passed to the superclass constructor. """ # Initialize correlation matrix attribute self._corr_matrix = None if "dimension" in kwargs: dimension = kwargs["dimension"] del kwargs["dimension"] Copula.__init__(self, dimension, *args, **kwargs) # Set up correlation matrix (identity if not provided) if corr_matrix is not None: # Convert to SymPy matrix if needed if not isinstance(corr_matrix, sp.Matrix): corr_matrix = sp.Matrix(corr_matrix) # Validate correlation matrix if corr_matrix.shape != (self.dim, self.dim): raise ValueError(f"Correlation matrix must be {self.dim}x{self.dim}") # Check if matrix is symmetric and has ones on diagonal if not all(corr_matrix[i, i] == 1 for i in range(self.dim)): raise ValueError("Correlation matrix must have ones on the diagonal") if not all( corr_matrix[i, j] == corr_matrix[j, i] for i in range(self.dim) for j in range(self.dim) ): raise ValueError("Correlation matrix must be symmetric") self.corr_matrix = corr_matrix @property def params_from_matrix(self): """ Get the parameters of the copula from the correlation matrix. For a multivariate elliptical copula, these are the off-diagonal elements of the correlation matrix. Returns ------- list List of parameters (correlation values). """ params_list = [] n = self.corr_matrix.shape[0] for i in range(n): for j in range(i + 1, n): params_list.append(self.corr_matrix[i, j]) return params_list
[docs] def characteristic_function(self, t_vector): """ Compute the characteristic function of the elliptical copula. Parameters ---------- t_vector : array_like Vector of arguments for the characteristic function. Returns ------- sympy.Expr Value of the characteristic function. Raises ------ NotImplementedError If generator is not defined in the subclass. """ if self.generator is None: raise NotImplementedError("Generator function must be defined in subclass") # Convert to SymPy matrix if needed if not isinstance(t_vector, sp.Matrix): t_vector = sp.Matrix(t_vector) # Compute quadratic form t' * corr_matrix * t arg = (t_vector.T * self.corr_matrix * t_vector)[0] # Make a proper substitution with a dictionary t = self.t # Get the symbol return self.generator.subs({t: arg})
@property @abstractmethod def is_absolutely_continuous(self): """ Check if the copula is absolutely continuous. Returns ------- bool True if the copula is absolutely continuous, False otherwise. """ pass @property @abstractmethod def is_symmetric(self): """ Check if the copula is symmetric. Returns ------- bool True if the copula is symmetric, False otherwise. """ pass @property def corr_matrix(self): """ Get the correlation matrix. Returns ------- sympy.Matrix Correlation matrix. """ return self._corr_matrix @corr_matrix.setter def corr_matrix(self, matrix): """ Set the correlation matrix. Parameters ---------- matrix : sympy.Matrix Correlation matrix. """ self._corr_matrix = matrix @property @abstractmethod def cdf(self): """ Abstract method to compute the cumulative distribution function. Must be implemented by subclasses. Returns ------- SymPyFuncWrapper Wrapped CDF function. """ pass