Source code for copul.family.frechet.rho_d_lower_boundary

# lower_boundary.py
import sympy

from copul.family.frechet.frechet import Frechet


[docs] class RhoDLowerBoundary(Frechet): r""" One-parameter family attaining the *lower* boundary of the (rho, D) region: C = (1 - |rho|) * Pi + |rho| * B_rho, where B_rho = M if rho >= 0 and B_rho = W if rho < 0. This can be encoded as the Frechet mixture with: alpha(rho) = max(rho, 0), beta(rho) = max(-rho, 0), independence weight = 1 - |rho|. Parameters ---------- rho : sympy symbol or float in [-1, 1] Target Spearman's rho. For this family, rho(C) = rho. Notes ----- We expose only the single parameter 'rho' and compute alpha, beta piecewise via sympy.Max to keep expressions symbolic when needed. """ _rho = sympy.symbols("rho", real=True) params = [_rho] intervals = { "rho": sympy.Interval(-1, 1, left_open=False, right_open=False), } def __init__(self, *args, **kwargs): # Allow positional or keyword initialization: RhoDLowerBoundary(rho=-0.3) or (-0.3) if args and len(args) == 1: kwargs["rho"] = args[0] if "rho" in kwargs: self._rho = kwargs["rho"] del kwargs["rho"] super().__init__(**kwargs) def __call__(self, *args, **kwargs): # Functional style: obj(rho=...) returns a cloned instance with the new parameter if args and len(args) == 1: kwargs["rho"] = args[0] if "rho" in kwargs: new = sympy.deepcopy(self) if hasattr(sympy, "deepcopy") else None if new is None: import copy as _copy new = _copy.deepcopy(self) new._rho = kwargs["rho"] del kwargs["rho"] return new.__call__(**kwargs) return super().__call__(**kwargs) @property def rho(self): return self._rho @property def alpha(self): # alpha = max(rho, 0) return sympy.Max(self._rho, 0) @property def beta(self): # beta = max(-rho, 0) return sympy.Max(-self._rho, 0) # Frechet.cdf already uses self._alpha/self._beta in the symbolic cdf, # so we override cdf to ensure it always uses the (piecewise) alpha/beta *properties*. @property def cdf(self): r""" C(u,v) = alpha * min(u,v) + (1 - alpha - beta) * u v + beta * max(u+v-1, 0), where 1 - alpha - beta = 1 - |rho|. """ frechet_upper = sympy.Min(self.u, self.v) frechet_lower = sympy.Max(self.u + self.v - 1, 0) a = self.alpha b = self.beta independence = self.u * self.v return self.CDFWrapper( a * frechet_upper + (1 - a - b) * independence + b * frechet_lower )