[docs]classConditionalSum(Expression):"""This expression returns the sum of a selected list of expressions. An expression is considered in the sum only if the corresponding key is True (that is, return a non-zero value). """def__init__(self,list_of_terms:Iterable[ConditionalTermTuple]):"""Constructor :param list_of_terms: list containing the terms and the associated conditions :raise BiogemeError: if one of the expressions is invalid, that is neither a numeric value nor a biogeme.expressions.Expression object. :raise BiogemeError: if the dict of expressions is empty :raise BiogemeError: if the dict of expressions is not a dict """ifnotlist_of_terms:raiseBiogemeError('The argument of ConditionalSum cannot be empty')super().__init__()self.list_of_terms=[the_term._replace(condition=validate_and_convert(the_term.condition),term=validate_and_convert(the_term.term),)forthe_terminlist_of_terms]forthe_terminself.list_of_terms:self.children.append(the_term.condition)self.children.append(the_term.term)
[docs]defdeep_flat_copy(self)->ConditionalSum:"""Provides a copy of the expression. It is deep in the sense that it generates copies of the children. It is flat in the sense that any `MultipleExpression` is transformed into the currently selected expression. The flat part is irrelevant for this expression. """copy_list_of_terms:list[ConditionalTermTuple]=[ConditionalTermTuple(condition=the_term.condition.deep_flat_copy(),term=the_term.term.deep_flat_copy(),)forthe_terminself.list_of_terms]returntype(self)(list_of_terms=copy_list_of_terms)
[docs]defget_value(self)->float:"""Evaluates the value of the expression :return: value of the expression :rtype: float """result=0.0forthe_terminself.list_of_terms:condition=the_term.condition.get_value()ifcondition!=0:result+=the_term.term.get_value()returnresult
[docs]defrecursive_construct_pymc_model_builder(self)->PymcModelBuilderType:""" Generates recursively a function to be used by PyMc. Must be overloaded by each expression :return: the expression in TensorVariable format, suitable for PyMc """pymc_terms=[(cond.recursive_construct_pymc_model_builder(),term.recursive_construct_pymc_model_builder(),)forcond,terminself.list_of_terms]defbuilder(dataframe:pd.DataFrame)->pt.TensorVariable:# Build all (condition, term) oncebuilt=[(c_fn(dataframe),t_fn(dataframe))forc_fn,t_fninpymc_terms]# Stack conditions as booleans and terms with a single zeros_likeconds=pt.stack([pt.neq(c,0)forc,_inbuilt],axis=0)terms=pt.stack([tfor_,tinbuilt],axis=0)masked=pt.where(conds,terms,pt.zeros_like(terms))returnmasked.sum(axis=0)returnbuilder