Source code for biogeme.expressions.numeric_expressions

""" Arithmetic expressions accepted by Biogeme: numeric expressions

:author: Michel Bierlaire
:date: Sat Sep  9 15:27:17 2023
"""
import logging
from typing import Any
import biogeme.exceptions as excep
from .base_expressions import Expression
from .numeric_tools import is_numeric, validate

logger = logging.getLogger(__name__)


[docs] def process_numeric(expression): """Transforms a numeric value into an Expression object :param expression: expression to process :type expression: Expression or numeric :raise BiogemeError: if expression is not of type expression """ if isinstance(expression, (int, float, bool)): return Numeric(expression) if not isinstance(expression, Expression): raise excep.BiogemeError(f'This is not a valid expression: {expression}') return expression
[docs] class Numeric(Expression): """ Numerical expression for a simple number """
[docs] def __init__(self, value): """Constructor :param value: numerical value :type value: float """ Expression.__init__(self) the_value = validate(value, modify=False) self.value = float(the_value) #: numeric value
def __str__(self): return '`' + str(self.value) + '`'
[docs] def getValue(self): """Evaluates the value of the expression :return: value of the expression :rtype: float """ return self.value
[docs] def getSignature(self): """The signature of a string characterizing an expression. This is designed to be communicated to C++, so that the expression can be reconstructed in this environment. The list contains the following elements: 1. the name of the expression between < > 2. the id of the expression between { } 3. the value, preceeded by a comma. Consider the following expression: .. math:: 2 \\beta_1 V_1 - \\frac{\\exp(-\\beta_2 V_2) }{ \\beta_3 (\\beta_2 \\geq \\beta_1)}. It is defined as:: 2 * beta1 * Variable1 - expressions.exp(-beta2*Variable2) / (beta3 * (beta2 >= beta1)) And its signature is:: [b'<Numeric>{4780527008},2', b'<Beta>{4780277152}"beta1"[0],0,0', b'<Times>{4780526952}(2),4780527008,4780277152', b'<Variable>{4511837152}"Variable1",5,2', b'<Times>{4780527064}(2),4780526952,4511837152', b'<Beta>{4780277656}"beta2"[0],1,1', b'<UnaryMinus>{4780527120}(1),4780277656', b'<Variable>{4511837712}"Variable2",6,3', b'<Times>{4780527176}(2),4780527120,4511837712', b'<exp>{4780527232}(1),4780527176', b'<Beta>{4780277264}"beta3"[1],2,0', b'<Beta>{4780277656}"beta2"[0],1,1', b'<Beta>{4780277152}"beta1"[0],0,0', b'<GreaterOrEqual>{4780527288}(2),4780277656,4780277152', b'<Times>{4780527344}(2),4780277264,4780527288', b'<Divide>{4780527400}(2),4780527232,4780527344', b'<Minus>{4780527456}(2),4780527064,4780527400'] :return: list of the signatures of an expression and its children. :rtype: list(string) """ signature = f'<{self.getClassName()}>' signature += f'{{{self.get_id()}}}' signature += f',{self.value}' return [signature.encode()]
[docs] def validate_and_convert(expression: Any) -> Expression: """Validates the expression and returns the converted expression if necessary.""" if isinstance(expression, bool): return Numeric(1) if expression else Numeric(0) if is_numeric(expression): return Numeric(expression) if not isinstance(expression, Expression): raise TypeError(f'This is not a valid expression: {expression}') return expression