Hyperiso 1.0.3
Modular flavour-physics calculations, Wilson coefficients and statistical inference
Loading...
Searching...
No Matches
Copula.py
Go to the documentation of this file.
1"""Python wrappers around C++ copula objects.
2
3The classes in this module provide a small, Pythonic API over the C++ statistical
4copula implementations. Copulas operate on the unit hypercube: samples returned
5by :meth:`Copula.sample_u` are dependent uniforms, and :meth:`Copula.log_density`
6evaluates the copula density contribution ``log c(u)``.
7"""
8
9from pyhyperiso.core.Statistic.CopulaConfig import (
10 CopulaConfigPy,
11 CopulaKind,
12 _config_from_cpp,
13 GaussianCopulaConfigPy,
14 StudentTCopulaConfigPy,
15 MatrixLike,
16)
17from typing import Any, List, Optional, Sequence, Union, cast
18from pyhyperiso.phyperiso.pyhyperiso import statistic as st
19
20
21class Copula:
22 """Base Python wrapper for a bound C++ copula.
23
24 The wrapper intentionally stores the C++ object as an opaque implementation
25 detail. Use :class:`CopulaFactoryWrapper` to create instances from Python
26 configuration objects.
27
28 Args:
29 cpp_obj: Bound C++ copula instance.
30 """
31
32 __slots__ = ("_cpp_obj",)
33
34 def __init__(self, cpp_obj: Any):
35 """Store the bound C++ copula object."""
36 self._cpp_obj = cpp_obj
37
38 @classmethod
39 def from_cpp(cls, cpp_obj: Any) -> "Copula":
40 """Wrap a bound C++ copula with the most specific Python class.
41
42 Args:
43 cpp_obj: Bound C++ copula instance.
44
45 Returns:
46 ``GaussianCopula`` for Gaussian C++ objects,
47 ``StudentTCopula`` for Student-t C++ objects, otherwise the generic
48 ``Copula`` wrapper.
49 """
50 if isinstance(cpp_obj, st.GaussianCopula):
51 return GaussianCopula(cpp_obj)
52 if isinstance(cpp_obj, st.StudentTCopula):
53 return StudentTCopula(cpp_obj)
54 return cls(cpp_obj)
55
56 def sample_u(self, n: Optional[int] = None) -> Union[List[float], List[List[float]]]:
57 """Draw one or more dependent uniform samples.
58
59 Args:
60 n: Number of samples. When omitted, returns a single vector of
61 dependent uniforms. When provided, returns a list of ``n``
62 vectors.
63
64 Returns:
65 A single ``list[float]`` if ``n`` is ``None``; otherwise a
66 ``list[list[float]]`` with shape ``n x dim``.
67
68 Raises:
69 ValueError: If ``n`` is negative.
70
71 Examples:
72 >>> cop = CopulaFactoryWrapper.gaussian([[1.0, 0.5], [0.5, 1.0]], seed=123)
73 >>> u = cop.sample_u()
74 >>> len(u)
75 2
76 >>> U = cop.sample_u(3)
77 >>> len(U)
78 3
79 """
80 if n is None:
81 u = self._cpp_obj.sample_u()
82 return [float(x) for x in u]
83 if int(n) < 0:
84 raise ValueError("n must be >= 0")
85 U = self._cpp_obj.sample_u(int(n))
86 return [[float(x) for x in row] for row in U]
87
88 def log_density(self, u: Sequence[float]) -> float:
89 """Evaluate the copula log-density at a point in the unit hypercube.
90
91 Args:
92 u: Uniform coordinates. Each component is expected to lie in
93 ``[0, 1]`` and the length must match the copula dimension.
94
95 Returns:
96 The scalar value ``log c(u)``.
97 """
98 return float(self._cpp_obj.log_density([float(x) for x in u]))
99
100 def density(self, u: Sequence[float]) -> float:
101 """Evaluate the copula density at a point in the unit hypercube.
102
103 Args:
104 u: Uniform coordinates passed to :meth:`log_density`.
105
106 Returns:
107 The density value ``c(u)``.
108 """
109 return float(pow(2.718281828459045, self.log_density(u)))
110
111
113 """Wrapper for the Gaussian copula backend.
114
115 The underlying C++ implementation samples a correlated Gaussian latent
116 vector and maps it component-wise through the standard normal CDF.
117 """
118
119 pass
120
121
123 """Wrapper for the Student-t copula backend.
124
125 The Student-t copula follows the same interface as the Gaussian copula but
126 can model stronger tail dependence through its degrees of freedom.
127 """
128
129 pass
130
131
133 """Factory helpers for creating Python copula wrappers.
134
135 This class forwards to the C++ ``CopulaFactory`` and wraps the returned C++
136 object in the appropriate Python class.
137 """
138
139 @staticmethod
140 def create(kind: CopulaKind, config: CopulaConfigPy, seed: Optional[int] = None) -> Copula:
141 """Create a copula from an explicit family and configuration.
142
143 Args:
144 kind: Copula family to instantiate.
145 config: Python configuration object compatible with ``kind``.
146 seed: Optional random seed passed to the C++ RNG.
147
148 Returns:
149 A Python wrapper around the newly created C++ copula.
150 """
151 cpp_kind = kind.to_cpp()
152 cpp_cfg = config.to_cpp()
153 cpp_obj = st.CopulaFactory.create(cpp_kind, cpp_cfg, seed)
154 return Copula.from_cpp(cpp_obj)
155
156 @staticmethod
157 def gaussian(R: MatrixLike, seed: Optional[int] = None) -> GaussianCopula:
158 """Create a Gaussian copula from a correlation matrix.
159
160 Args:
161 R: Square correlation matrix.
162 seed: Optional random seed.
163
164 Returns:
165 A ``GaussianCopula`` instance.
166
167 Examples:
168 >>> cop = CopulaFactoryWrapper.gaussian([[1.0, 0.3], [0.3, 1.0]], seed=7)
169 >>> isinstance(cop.sample_u(), list)
170 True
171 """
172 cop = CopulaFactoryWrapper.create(
173 CopulaKind.GAUSSIAN, GaussianCopulaConfigPy(R=R), seed=seed
174 )
175 return cast(GaussianCopula, cop)
176
177 @staticmethod
178 def student_t(R: MatrixLike, nu: int = 4, seed: Optional[int] = None) -> StudentTCopula:
179 """Create a Student-t copula from a correlation matrix.
180
181 Args:
182 R: Square correlation matrix.
183 nu: Degrees of freedom of the latent Student-t vector.
184 seed: Optional random seed.
185
186 Returns:
187 A ``StudentTCopula`` instance.
188 """
189 cop = CopulaFactoryWrapper.create(
190 CopulaKind.STUDENT_T, StudentTCopulaConfigPy(R=R, nu=nu), seed=seed
191 )
192 return cast(StudentTCopula, cop)
193
194
195__all__ = [
196 "CopulaKind",
197 "GaussianCopulaConfigPy",
198 "StudentTCopulaConfigPy",
199 "CopulaConfigPy",
200 "Copula",
201 "GaussianCopula",
202 "StudentTCopula",
203 "CopulaFactoryWrapper",
204 "_config_from_cpp",
205]
StudentTCopula student_t(MatrixLike R, int nu=4, Optional[int] seed=None)
Definition Copula.py:178
Copula create(CopulaKind kind, CopulaConfigPy config, Optional[int] seed=None)
Definition Copula.py:140
GaussianCopula gaussian(MatrixLike R, Optional[int] seed=None)
Definition Copula.py:157
float density(self, Sequence[float] u)
Definition Copula.py:100
__init__(self, Any cpp_obj)
Definition Copula.py:34
float log_density(self, Sequence[float] u)
Definition Copula.py:88
"Copula" from_cpp(cls, Any cpp_obj)
Definition Copula.py:39
Union[List[float], List[List[float]]] sample_u(self, Optional[int] n=None)
Definition Copula.py:56
Student-t copula with correlation matrix and degrees of freedom.