def __init__(self, *calc_inputs: Union[ProbabilityCalculationMixin, RVS1dMixin]): contexts: Set[CalculationContext] = set() for calc_input in calc_inputs: if isinstance(calc_input, ProbabilityCalculationMixin): contexts.add(calc_input.context) if len(contexts) == 0: context = CalculationContext() elif len(contexts) == 1: context = list(contexts)[0] else: raise ValueError( 'More than one context present in inputs to Minimum calculation' ) array_inputs = [] for calc_input in calc_inputs: if isinstance(calc_input, float): array_inputs.append( ValueCalculation(calc_input=calc_input, context=context)) elif isinstance(calc_input, RVS1dMixin): array_inputs.append( SampleCalculation(calc_input=calc_input, context=context)) else: raise TypeError('calc_input must be type Rvs1dMixin, float ' 'or ProbabilityCalculation') self.calc_inputs: List[ProbabilityCalculationMixin] = array_inputs self.context: CalculationContext = context
def __rmul__(self, other): from probability.calculations.calculation_types import SampleCalculation from probability.calculations.calculation_types import \ BinaryOperatorCalculation from probability.calculations.calculation_types.value_calculation import \ ValueCalculation if isinstance(other, ProbabilityCalculationMixin): context = other.context input_1 = other else: context = CalculationContext() if is_scalar(other): input_1 = ValueCalculation(calc_input=other, context=context) elif is_rvs(other): input_1 = SampleCalculation(calc_input=other, context=context) elif isinstance(other, Series) or isinstance(other, DataFrame): return other * self else: raise TypeError( 'other must be type Rvs1dMixin, RvsNdMixin float, ' 'Series or DataFrame') input_2 = SampleCalculation(calc_input=self, context=context) return BinaryOperatorCalculation(calc_input_1=input_1, calc_input_2=input_2, operator=MultiplyOperator, context=context)
def sync_context(*calculations: Union[ProbabilityCalculationMixin, Series, DataFrame]): """ Apply a new CalculationContext to Calculations, Series of Calculations, or DataFrames of Calculations. :param calculations: One or more Calculations, Series of Calculations, or DataFrames of Calculations. """ context = CalculationContext() for calculation in calculations: if isinstance(calculation, ProbabilityCalculationMixin): calculation.context = context for calc_input in calculation.input_calcs: calc_input.context = context elif isinstance(calculation, Series): for key, value in calculation.items(): if isinstance(value, ProbabilityCalculationMixin): value.context = context for calc_input in value.input_calcs: calc_input.context = context elif isinstance(calculation, DataFrame): for ix, col in product(calculation.index, calculation.columns): value = calculation.loc[ix, col] if isinstance(value, ProbabilityCalculationMixin): value.context = context for calc_input in value.input_calcs: calc_input.context = context else: raise TypeError( f'Cannot sync context for type {type(calculation)}')
def __truediv__(self, other): """ Multiply the Distribution by a float, distribution, Series or DataFrame. :param other: The divisor. N.B. if it is a Series or a DataFrame, the context of each value will not be synced. Use `sync_context` if syncing is needed. """ from probability.calculations.calculation_types import SampleCalculation from probability.calculations.calculation_types import \ BinaryOperatorCalculation from probability.calculations.calculation_types.value_calculation import \ ValueCalculation if isinstance(other, ProbabilityCalculationMixin): context = other.context input_2 = other else: context = CalculationContext() if is_scalar(other): input_2 = ValueCalculation(calc_input=other, context=context) elif is_rvs(other): input_2 = SampleCalculation(calc_input=other, context=context) elif isinstance(other, Series): return Series( {key: self / value for key, value in other.iteritems()}) elif isinstance(other, DataFrame): return DataFrame({ column: { key: self / value for key, value in other[column].iteritems() } for column in other.columns }) else: raise TypeError( 'other must be type Rvs1dMixin, RvsNdMixin float, ' 'Series or DataFrame') input_1 = SampleCalculation(calc_input=self, context=context) return BinaryOperatorCalculation(calc_input_1=input_1, calc_input_2=input_2, operator=DivideOperator, context=context)
def __rsub__(self, other) -> ProbabilityCalculationMixin: """ Used for returning the synced complement of a distribution. :param other: Must be 1 """ from probability.calculations.calculation_types import SampleCalculation from probability.calculations.calculation_types.unary_operator_calculation \ import UnaryOperatorCalculation if ((isinstance(other, int) or isinstance(other, float)) and other == 1): context = CalculationContext() return UnaryOperatorCalculation(calc_input=SampleCalculation( calc_input=self, context=context), operator=ComplementOperator, context=context) else: raise NotImplementedError
def reverse_binary_operation(item_1, item_2, builtin_operator, calc_operator_type): if isinstance(item_2, ProbabilityCalculationMixin): input_1 = item_2 input_1.set_context(item_1.context) else: context = CalculationContext() if is_scalar(item_2): input_1 = ValueCalculation(calc_input=item_2, context=context) elif is_rvs(item_2): input_1 = SampleCalculation(calc_input=item_2, context=context) elif isinstance(item_2, Series): return Series({ key: builtin_operator(value, item_1) for key, value in item_2.items() }) elif isinstance(item_2, DataFrame): return DataFrame({ column: { key: builtin_operator(value, item_1) for key, value in item_2[column].items() } for column in item_2.columns }) else: raise TypeError( 'item_2 must be type Rvs1dMixin, RvsNdMixin, int, float, ' 'Series or DataFrame') from \ probability.calculations.calculation_types.binary_operator_calculation \ import BinaryOperatorCalculation return BinaryOperatorCalculation(calc_input_1=input_1, calc_input_2=item_1, operator=calc_operator_type, context=item_1.context)