Source code for biogeme.expressions.multiple_expressions
"""Defines the interface for a catalog of expressions that may beconsidered in a specificationMichel Bierlaire13.04.2025 17:02"""importabcimportloggingfromtypingimportIterator,NamedTuple,finalfrombiogemeimportexceptionsfrom.base_expressionsimportExpressionlogger=logging.getLogger(__name__)SEPARATOR=';'SELECTION_SEPARATOR=':'
[docs]defdelegate_to_selected(method_name:str):""" Create a method that delegates its call to `self.selected()[1].<method_name>(...)`. This is useful for classes that wrap or dispatch to another `Expression` object, avoiding code duplication for common method overrides. :param method_name: The name of the method to delegate. It must be a valid method name on the `Expression` returned by `self.selected()[1]`. :return: A method that can be assigned to a class and will delegate the call. """defmethod(self,*args,**kwargs):_,expr=self.selected()returngetattr(expr,method_name)(*args,**kwargs)method.__name__=method_namereturnmethod
[docs]classMultipleExpression(Expression,metaclass=abc.ABCMeta):"""Interface for catalog of expressions that are interchangeable. Only one of them defines the specification. They are designed to be modified algorithmically. """def__init__(self,the_name:str):self.name=the_name# The name of the expression catalogifSEPARATORinnameorSELECTION_SEPARATORinname:error_msg=(f'Invalid name: {the_name}. Cannot contain characters 'f'{SELECTION_SEPARATOR} or {SELECTION_SEPARATOR}')raiseexceptions.BiogemeError(error_msg)super().__init__()
[docs]defdeep_flat_copy(self)->Expression:"""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` such as this one is transformed into the currently selected expression. The flat part is irrelevant for this expression. """the_expression=self.selected_expression()returnthe_expression.deep_flat_copy()
[docs]@abc.abstractmethoddefselected(self)->NamedExpression:"""Return the selected expression and its name :return: the name and the selected expression :rtype: tuple(str, biogeme.expressions.Expression) """
[docs]@abc.abstractmethoddefget_iterator(self)->Iterator[NamedExpression]:"""Returns an iterator on NamedExpression"""
[docs]@finaldefcatalog_size(self)->int:"""Provide the size of the catalog :return: number of expressions in the catalog :rtype: int """the_iterator=self.get_iterator()returnlen(list(the_iterator))
[docs]@finaldefselected_name(self)->str:"""Obtain the name of the selection :return: the name of the selected expression :rtype: str """the_name,_=self.selected()returnthe_name
[docs]@finaldefselected_expression(self)->NamedExpression:"""Obtain the selected expression :return: the selected expression :rtype: biogeme.expressions.Expression """_,the_expression=self.selected()returnthe_expression
# We now specify all methods that must be delegated to the selected expressiondelegated_methods=['set_maximum_number_of_observations_per_individual','change_init_values','rename_elementary','get_elementary_expression','get_value','requires_draws','recursive_construct_jax_function','logit_choice_avail','add_suffix_to_all_variables','set_specific_id',]fornameindelegated_methods:setattr(MultipleExpression,name,final(delegate_to_selected(name)))