"""Composite distribution implementations.Provides classes for handling composite probability distributions that combinemultiple other distributions, including mixtures and products of distributions."""from__future__importannotationsfromtypingimportLiteral,castimportpytensor.tensorasptfrompyhs3.contextimportContextfrompyhs3.distributions.coreimportDistributionfrompyhs3.typing.aliasesimportTensorVar
[docs]classMixtureDist(Distribution):r""" Mixture of probability distributions. Implements a weighted combination of multiple distributions: .. math:: f(x) = \sum_{i=1}^{n-1} c_i \cdot f_i(x) + (1 - \sum_{i=1}^{n-1} c_i) \cdot f_n(x) The last component is automatically normalized to ensure the coefficients sum to 1. Parameters: coefficients (list[str]): Names of coefficient parameters. summands (list[str]): Names of component distributions. extended (bool): Whether the mixture is extended (affects normalization). """type:Literal["mixture_dist"]="mixture_dist"summands:list[str]coefficients:list[str]extended:bool=Falsedefexpression(self,context:Context)->TensorVar:""" Builds a symbolic expression for the mixture distribution. Args: context (dict): Mapping of names to pytensor variables. Returns: pytensor.tensor.variable.TensorVariable: Symbolic representation of the mixture PDF. """mixturesum=pt.constant(0.0)coeffsum=pt.constant(0.0)fori,coeffinenumerate(self.coefficients):coeffsum+=context[coeff]mixturesum+=context[coeff]*context[self.summands[i]]last_index=len(self.summands)-1f_last=context[self.summands[last_index]]mixturesum=mixturesum+(1-coeffsum)*f_lastreturncast(TensorVar,mixturesum)
[docs]classProductDist(Distribution):r""" Product distribution implementation. Implements a product of PDFs as defined in ROOT's RooProdPdf. The probability density function is defined as: .. math:: f(x, \ldots) = \prod_{i=1}^{N} \text{PDF}_i(x, \ldots) where each PDF_i is a component distribution that may share observables. Parameters: factors: List of component distribution names to multiply together Note: In the context of pytensor variables/tensors, this is implemented as an elementwise product of all factor distributions. """type:Literal["product_dist"]="product_dist"factors:list[str]defexpression(self,context:Context)->TensorVar:""" Evaluate the product distribution. Args: context: Mapping of names to pytensor variables Returns: Symbolic representation of the product PDF """ifnotself.factors:returncast(TensorVar,pt.constant(1.0))pt_factors=pt.stack([context[factor]forfactorinself.factors])returncast(TensorVar,pt.prod(pt_factors,axis=0))# type: ignore[no-untyped-call]
# Registry of composite distributionsdistributions:dict[str,type[Distribution]]={"mixture_dist":MixtureDist,"product_dist":ProductDist,}# Define what should be exported from this module__all__=["MixtureDist","ProductDist","distributions",]