.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "auto_examples/programmers/plot_expressions.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code. .. rst-class:: sphx-glr-example-title .. _sphx_glr_auto_examples_programmers_plot_expressions.py: biogeme.expressions =================== Examples of use of several functions. This is designed for programmers who need examples of use of the functions of the module. The examples are designed to illustrate the syntax. They do not correspond to any meaningful model. Michel Bierlaire Sun Jun 29 2025, 07:12:52 .. GENERATED FROM PYTHON SOURCE LINES 15-62 .. code-block:: Python import numpy as np import pandas as pd from IPython.core.display_functions import display import biogeme.biogeme_logging as blog from biogeme.calculator.function_call import ( CallableExpression, function_from_expression, ) from biogeme.calculator.simple_formula import evaluate_simple_expression from biogeme.calculator.single_formula import ( calculate_single_formula_from_expression, get_value_and_derivatives, ) from biogeme.database import Database from biogeme.exceptions import BiogemeError from biogeme.expressions import ( Beta, BinaryMax, BinaryMin, Derive, Draws, Elem, IntegrateNormal, LinearTermTuple, LinearUtility, LogLogit, MonteCarlo, MultipleSum, NormalCdf, Numeric, RandomVariable, Variable, cos, exp, list_of_all_betas_in_expression, list_of_fixed_betas_in_expression, list_of_free_betas_in_expression, list_of_variables_in_expression, log, sin, ) from biogeme.function_output import FunctionOutput from biogeme.second_derivatives import SecondDerivativesMode from biogeme.version import get_text .. GENERATED FROM PYTHON SOURCE LINES 63-64 Version of Biogeme. .. GENERATED FROM PYTHON SOURCE LINES 64-66 .. code-block:: Python print(get_text()) .. rst-class:: sphx-glr-script-out .. code-block:: none biogeme 3.3.1 [2025-09-03] Home page: http://biogeme.epfl.ch Submit questions to https://groups.google.com/d/forum/biogeme Michel Bierlaire, Transport and Mobility Laboratory, Ecole Polytechnique Fédérale de Lausanne (EPFL) .. GENERATED FROM PYTHON SOURCE LINES 67-69 .. code-block:: Python logger = blog.get_screen_logger(level=blog.INFO) .. GENERATED FROM PYTHON SOURCE LINES 70-74 Simple expressions ------------------ Simple expressions can be evaluated with the function `get_value`, implemented in Python. This is available when no database is needed. .. GENERATED FROM PYTHON SOURCE LINES 76-79 .. code-block:: Python x = Beta('x', 2, None, None, 1) display(x) .. rst-class:: sphx-glr-script-out .. code-block:: none Beta('x', 2, None, None, 1) .. GENERATED FROM PYTHON SOURCE LINES 80-81 The `get_value`function simply returns the value of the expression if it can be evaluated. .. GENERATED FROM PYTHON SOURCE LINES 81-83 .. code-block:: Python display(x.get_value()) .. rst-class:: sphx-glr-script-out .. code-block:: none 2 .. GENERATED FROM PYTHON SOURCE LINES 84-87 .. code-block:: Python y = Beta('y', 3, None, None, 1) display(y) .. rst-class:: sphx-glr-script-out .. code-block:: none Beta('y', 3, None, None, 1) .. GENERATED FROM PYTHON SOURCE LINES 88-90 .. code-block:: Python display(y.get_value()) .. rst-class:: sphx-glr-script-out .. code-block:: none 3 .. GENERATED FROM PYTHON SOURCE LINES 91-94 .. code-block:: Python one = Numeric(1) display(one) .. rst-class:: sphx-glr-script-out .. code-block:: none `1.0` .. GENERATED FROM PYTHON SOURCE LINES 95-97 .. code-block:: Python display(one.get_value()) .. rst-class:: sphx-glr-script-out .. code-block:: none 1.0 .. GENERATED FROM PYTHON SOURCE LINES 98-99 Addition .. GENERATED FROM PYTHON SOURCE LINES 99-102 .. code-block:: Python z = x + y display(f'{x.get_value()} + {y.get_value()} = {z.get_value()}') .. rst-class:: sphx-glr-script-out .. code-block:: none 2 + 3 = 5 .. GENERATED FROM PYTHON SOURCE LINES 103-104 Substraction .. GENERATED FROM PYTHON SOURCE LINES 104-107 .. code-block:: Python z = x - y display(f'{x.get_value()} - {y.get_value()} = {z.get_value()}') .. rst-class:: sphx-glr-script-out .. code-block:: none 2 - 3 = -1 .. GENERATED FROM PYTHON SOURCE LINES 108-109 Multiplication .. GENERATED FROM PYTHON SOURCE LINES 109-113 .. code-block:: Python z = x * y display(f'{x.get_value()} * {y.get_value()} = {z.get_value()}') .. rst-class:: sphx-glr-script-out .. code-block:: none 2 * 3 = 6 .. GENERATED FROM PYTHON SOURCE LINES 114-115 Division .. GENERATED FROM PYTHON SOURCE LINES 115-118 .. code-block:: Python z = x / y display(f'{x.get_value()} / {y.get_value()} = {z.get_value()}') .. rst-class:: sphx-glr-script-out .. code-block:: none 2 / 3 = 0.6666666666666666 .. GENERATED FROM PYTHON SOURCE LINES 119-120 Power .. GENERATED FROM PYTHON SOURCE LINES 120-124 .. code-block:: Python z = x**y z.get_value() display(f'{x.get_value()} ** {y.get_value()} = {z.get_value()}') .. rst-class:: sphx-glr-script-out .. code-block:: none 2 ** 3 = 8 .. GENERATED FROM PYTHON SOURCE LINES 125-126 Exponential .. GENERATED FROM PYTHON SOURCE LINES 126-130 .. code-block:: Python z = exp(x) z.get_value() display(f'exp({x.get_value()}) = {z.get_value()}') .. rst-class:: sphx-glr-script-out .. code-block:: none exp(2) = 7.38905609893065 .. GENERATED FROM PYTHON SOURCE LINES 131-132 Logarithm .. GENERATED FROM PYTHON SOURCE LINES 132-136 .. code-block:: Python z = log(x) z.get_value() display(f'log({x.get_value()}) = {z.get_value()}') .. rst-class:: sphx-glr-script-out .. code-block:: none log(2) = 0.6931471805599453 .. GENERATED FROM PYTHON SOURCE LINES 137-138 Sine .. GENERATED FROM PYTHON SOURCE LINES 138-142 .. code-block:: Python z = sin(x) z.get_value() display(f'sin({x.get_value()}) = {z.get_value()}') .. rst-class:: sphx-glr-script-out .. code-block:: none sin(2) = 0.9092974268256817 .. GENERATED FROM PYTHON SOURCE LINES 143-144 Cosine .. GENERATED FROM PYTHON SOURCE LINES 144-148 .. code-block:: Python z = cos(x) z.get_value() display(f'cos({x.get_value()}) = {z.get_value()}') .. rst-class:: sphx-glr-script-out .. code-block:: none cos(2) = -0.4161468365471424 .. GENERATED FROM PYTHON SOURCE LINES 149-150 Minimum .. GENERATED FROM PYTHON SOURCE LINES 150-154 .. code-block:: Python z = BinaryMin(x, y) z.get_value() display(f'min({x.get_value()}, {y.get_value()}) = {z.get_value()}') .. rst-class:: sphx-glr-script-out .. code-block:: none min(2, 3) = 2 .. GENERATED FROM PYTHON SOURCE LINES 155-156 Maximum .. GENERATED FROM PYTHON SOURCE LINES 156-161 .. code-block:: Python z = BinaryMax(x, y) z.get_value() display(f'max({x.get_value()}, {y.get_value()}) = {z.get_value()}') .. rst-class:: sphx-glr-script-out .. code-block:: none max(2, 3) = 3 .. GENERATED FROM PYTHON SOURCE LINES 162-165 And An expression is considered False if its value is 0 and True otherwise. The outcome of a logical operator is 0 (False) or 1 (True). .. GENERATED FROM PYTHON SOURCE LINES 165-169 .. code-block:: Python z = x & y z.get_value() display(f'{x.get_value()} and {y.get_value()} = {z.get_value()}') .. rst-class:: sphx-glr-script-out .. code-block:: none 2 and 3 = 1.0 .. GENERATED FROM PYTHON SOURCE LINES 170-174 .. code-block:: Python z = x & 0 z.get_value() display(f'{x.get_value()} and 0 = {z.get_value()}') .. rst-class:: sphx-glr-script-out .. code-block:: none 2 and 0 = 0.0 .. GENERATED FROM PYTHON SOURCE LINES 175-176 Or .. GENERATED FROM PYTHON SOURCE LINES 178-182 .. code-block:: Python z = x | y z.get_value() display(f'{x.get_value()} or {y.get_value()} = {z.get_value()}') .. rst-class:: sphx-glr-script-out .. code-block:: none 2 or 3 = 1.0 .. GENERATED FROM PYTHON SOURCE LINES 183-186 .. code-block:: Python z = Numeric(0) | Numeric(0) z.get_value() .. rst-class:: sphx-glr-script-out .. code-block:: none 0.0 .. GENERATED FROM PYTHON SOURCE LINES 187-188 Equal .. GENERATED FROM PYTHON SOURCE LINES 188-192 .. code-block:: Python z = x == y z.get_value() display(f'{x.get_value()} == {y.get_value()} = {z.get_value()}') .. rst-class:: sphx-glr-script-out .. code-block:: none 2 == 3 = 0 .. GENERATED FROM PYTHON SOURCE LINES 193-197 .. code-block:: Python z = (x + 1) == y z.get_value() display(f'({x.get_value()} + 1) == {y.get_value()} = {z.get_value()}') .. rst-class:: sphx-glr-script-out .. code-block:: none (2 + 1) == 3 = 1 .. GENERATED FROM PYTHON SOURCE LINES 198-199 Not equal .. GENERATED FROM PYTHON SOURCE LINES 199-203 .. code-block:: Python z = x != y z.get_value() display(f'{x.get_value()} != {y.get_value()} = {z.get_value()}') .. rst-class:: sphx-glr-script-out .. code-block:: none 2 != 3 = 1 .. GENERATED FROM PYTHON SOURCE LINES 204-209 .. code-block:: Python z = (x + 1) != y z.get_value() display(f'({x.get_value()} + 1) != {y.get_value()} = {z.get_value()}') .. rst-class:: sphx-glr-script-out .. code-block:: none (2 + 1) != 3 = 0 .. GENERATED FROM PYTHON SOURCE LINES 210-211 Lesser or equal .. GENERATED FROM PYTHON SOURCE LINES 211-216 .. code-block:: Python z = x <= y z.get_value() display(f'{x.get_value()} <= {y.get_value()} = {z.get_value()}') .. rst-class:: sphx-glr-script-out .. code-block:: none 2 <= 3 = 1 .. GENERATED FROM PYTHON SOURCE LINES 217-218 Greater or equal .. GENERATED FROM PYTHON SOURCE LINES 218-221 .. code-block:: Python z = x >= y z.get_value() .. rst-class:: sphx-glr-script-out .. code-block:: none 0 .. GENERATED FROM PYTHON SOURCE LINES 222-223 Lesser than .. GENERATED FROM PYTHON SOURCE LINES 223-227 .. code-block:: Python z = x < y z.get_value() display(f'{x.get_value()} < {y.get_value()} = {z.get_value()}') .. rst-class:: sphx-glr-script-out .. code-block:: none 2 < 3 = 1 .. GENERATED FROM PYTHON SOURCE LINES 228-229 Greater than .. GENERATED FROM PYTHON SOURCE LINES 229-233 .. code-block:: Python z = x > y z.get_value() display(f'{x.get_value()} > {y.get_value()} = {z.get_value()}') .. rst-class:: sphx-glr-script-out .. code-block:: none 2 > 3 = 0 .. GENERATED FROM PYTHON SOURCE LINES 234-235 Opposite .. GENERATED FROM PYTHON SOURCE LINES 235-240 .. code-block:: Python z = -x z.get_value() display(f'-{x.get_value()} = {z.get_value()}') .. rst-class:: sphx-glr-script-out .. code-block:: none -2 = -2 .. GENERATED FROM PYTHON SOURCE LINES 241-242 Sum of multiples expressions .. GENERATED FROM PYTHON SOURCE LINES 242-247 .. code-block:: Python list_of_expressions = [x, y, 1 + x, 1 + y] z = MultipleSum(list_of_expressions) all_values = [expression.get_value() for expression in list_of_expressions] display(f'Sum of {all_values} = {z.get_value()}') .. rst-class:: sphx-glr-script-out .. code-block:: none Sum of [2, 3, 3.0, 4.0] = 12.0 .. GENERATED FROM PYTHON SOURCE LINES 248-250 The result is the same as the following, but it implements the sum in a more efficient way. .. GENERATED FROM PYTHON SOURCE LINES 250-254 .. code-block:: Python z = x + y + 1 + x + 1 + y z.get_value() display(f'Sum of {all_values} = {z.get_value()}') .. rst-class:: sphx-glr-script-out .. code-block:: none Sum of [2, 3, 3.0, 4.0] = 12.0 .. GENERATED FROM PYTHON SOURCE LINES 255-258 Element: this expression considers a dictionary of expressions, and an expression for the index. The index is evaluated, and the value of the corresponding expression in the dictionary is returned. .. GENERATED FROM PYTHON SOURCE LINES 258-260 .. code-block:: Python my_dict = {1: exp(-1), 2: log(1.2), 3: 1234} .. GENERATED FROM PYTHON SOURCE LINES 261-264 .. code-block:: Python index = x display(f'Value of the index: {index.get_value()}') .. rst-class:: sphx-glr-script-out .. code-block:: none Value of the index: 2 .. GENERATED FROM PYTHON SOURCE LINES 265-269 .. code-block:: Python z = Elem(my_dict, index) z.get_value() display(f'Value of the expression with index {index.get_value()}: {z.get_value()}') .. rst-class:: sphx-glr-script-out .. code-block:: none Value of the expression with index 2: 0.1823215567939546 .. GENERATED FROM PYTHON SOURCE LINES 270-276 .. code-block:: Python index = x - 1 z = Elem(my_dict, index) z.get_value() display(f'Value of the expression with index {index.get_value()}: {z.get_value()}') .. rst-class:: sphx-glr-script-out .. code-block:: none Value of the expression with index 1.0: 0.36787944117144233 .. GENERATED FROM PYTHON SOURCE LINES 277-281 .. code-block:: Python index = x - 2 index.get_value() display(f'Value of the index: {index.get_value()}') .. rst-class:: sphx-glr-script-out .. code-block:: none Value of the index: 0.0 .. GENERATED FROM PYTHON SOURCE LINES 282-284 If the value returned as index does not correspond to an entry in the dictionary, an exception is raised. .. GENERATED FROM PYTHON SOURCE LINES 286-292 .. code-block:: Python z = Elem(my_dict, index) try: z.get_value() except BiogemeError as e: print(f'Exception raised: {e}') .. rst-class:: sphx-glr-script-out .. code-block:: none Exception raised: Invalid or missing key: 0. Available keys: dict_keys([1, 2, 3]) .. GENERATED FROM PYTHON SOURCE LINES 293-298 Complex expressions ------------------- When an expression is deemed complex in Biogeme, the `get_value` function is not available. The `evaluate_simple_expression` must be used. It is based on Jax to evaluate the arithmetic expressions. .. GENERATED FROM PYTHON SOURCE LINES 300-304 Normal CDF: it calculates .. math:: \Phi(x) = \frac{1}{\sqrt{2\pi}}\int_{-\infty}^{x} e^{-\frac{1}{2}\omega^2}d\omega. .. GENERATED FROM PYTHON SOURCE LINES 304-316 .. code-block:: Python z = NormalCdf(x) try: z.get_value() except BiogemeError as e: print(e) value = evaluate_simple_expression( expression=z, database=None, numerically_safe=False, use_jit=True ) display(f'NormalCdf({x.get_value()}) = {value}') .. rst-class:: sphx-glr-script-out .. code-block:: none NormalCdf(2) = 0.9772498680518208 .. GENERATED FROM PYTHON SOURCE LINES 317-322 .. code-block:: Python value = evaluate_simple_expression( expression=NormalCdf(0), database=None, numerically_safe=False, use_jit=True ) display(f'NormalCdf(0) = {value}') .. rst-class:: sphx-glr-script-out .. code-block:: none NormalCdf(0) = 0.5 .. GENERATED FROM PYTHON SOURCE LINES 323-325 Derivative It is possible to calculate the derivative with respect to a parameter or a variable. .. GENERATED FROM PYTHON SOURCE LINES 325-329 .. code-block:: Python parameter = Beta('parameter', 0, None, None, 0) variable = Variable('variable') z = 30 * parameter + 20 * variable .. GENERATED FROM PYTHON SOURCE LINES 330-333 .. code-block:: Python dz_dparameter = Derive(z, 'parameter') dz_dvariable = Derive(z, 'variable') .. GENERATED FROM PYTHON SOURCE LINES 334-335 As the expression involves a variable, it requires a database. .. GENERATED FROM PYTHON SOURCE LINES 335-352 .. code-block:: Python simple_dataframe = pd.DataFrame.from_dict({'variable': [1]}) simple_database = Database(dataframe=simple_dataframe, name='simple') value_parameter = evaluate_simple_expression( expression=dz_dparameter, database=simple_database, numerically_safe=False, use_jit=True, ) display(f'dz/dparameter = {value_parameter}') value_variable = evaluate_simple_expression( expression=dz_dvariable, database=simple_database, numerically_safe=False, use_jit=True, ) display(f'dz/variable = {value_variable}') .. rst-class:: sphx-glr-script-out .. code-block:: none dz/dparameter = 30.0 dz/variable = 20.0 .. GENERATED FROM PYTHON SOURCE LINES 353-357 Integral: let's calculate the integral of the pdf of a normal distribution: .. math:: \frac{1}{\sqrt{2\pi}}\int_{-\infty}^{+\infty} e^{-\frac{1}{2}\omega^2}d\omega = 1. .. GENERATED FROM PYTHON SOURCE LINES 359-362 The expression `IntegrateNormal` multiplies its argument by the pdf or the normal distribution before evaluating the integral. Therefore, the expression that we need to provide here is 1. However, Biogeme requires the expression to involve 'omega'. Therefore, we code 1 as the ratio of omega by itself. .. GENERATED FROM PYTHON SOURCE LINES 362-370 .. code-block:: Python omega = RandomVariable('omega') z = IntegrateNormal(omega / omega, 'omega') value = evaluate_simple_expression( expression=z, database=simple_database, numerically_safe=False, use_jit=True ) display(f'The integral between -inf and +inf of the normal pdf is {value}') .. rst-class:: sphx-glr-script-out .. code-block:: none The integral between -inf and +inf of the normal pdf is 0.9999999999999998 .. GENERATED FROM PYTHON SOURCE LINES 371-374 We now illustrate expressions that require a database. Those expressions are evaluated for each row of the database, and the obtained values are then added together to obtain the result. .. GENERATED FROM PYTHON SOURCE LINES 374-388 .. code-block:: Python df = pd.DataFrame( { 'Person': [1, 1, 1, 2, 2], 'Exclude': [0, 0, 1, 0, 1], 'Variable1': [10, 20, 30, 40, 50], 'Variable2': [100, 200, 300, 400, 500], 'Choice': [2, 2, 3, 1, 2], 'Av1': [0, 1, 1, 1, 1], 'Av2': [1, 1, 1, 1, 1], 'Av3': [0, 1, 1, 1, 1], } ) my_data = Database('test', df) .. GENERATED FROM PYTHON SOURCE LINES 389-390 Linear utility: it defines a linear combinations of parameters are variables. .. GENERATED FROM PYTHON SOURCE LINES 390-395 .. code-block:: Python beta1 = Beta('beta1', 10, None, None, 0) beta2 = Beta('beta2', 20, None, None, 0) v1 = Variable('Variable1') v2 = Variable('Variable2') .. GENERATED FROM PYTHON SOURCE LINES 396-406 .. code-block:: Python list_of_terms = [ LinearTermTuple(beta=beta1, x=v1), LinearTermTuple(beta=beta2, x=v2), ] z = LinearUtility(list_of_terms) value = evaluate_simple_expression( expression=z, database=my_data, numerically_safe=False, use_jit=True ) display(f'beta1 * v1 + beta2 * v2 = {value}') .. rst-class:: sphx-glr-script-out .. code-block:: none beta1 * v1 + beta2 * v2 = 31500.0 .. GENERATED FROM PYTHON SOURCE LINES 407-408 It is equivalent to the following, but implemented in a more efficient way. .. GENERATED FROM PYTHON SOURCE LINES 408-414 .. code-block:: Python z = beta1 * v1 + beta2 * v2 value = evaluate_simple_expression( expression=z, database=my_data, numerically_safe=False, use_jit=True ) display(f'beta1 * v1 + beta2 * v2 = {value}') .. rst-class:: sphx-glr-script-out .. code-block:: none beta1 * v1 + beta2 * v2 = 31500.0 .. GENERATED FROM PYTHON SOURCE LINES 415-421 Monte Carlo: we approximate the integral .. math:: \int_0^1 x^2 dx=\frac{1}{3} using Monte-Carlo integration. This is not considered a simple expression. Therefore, another function must be called. .. GENERATED FROM PYTHON SOURCE LINES 421-437 .. code-block:: Python draws = Draws('draws', 'UNIFORM') z = MonteCarlo(draws * draws) number_of_draws = 1_000_000 value = calculate_single_formula_from_expression( expression=z, database=simple_database, number_of_draws=number_of_draws, the_betas={}, second_derivatives_mode=SecondDerivativesMode.NEVER, numerically_safe=False, use_jit=True, ) display( f'The Monte-Carlo approximation of the integral with {number_of_draws:_} draws is equal to {value}.' ) .. rst-class:: sphx-glr-script-out .. code-block:: none The Monte-Carlo approximation of the integral with 1_000_000 draws is equal to 0.3330420826625586. .. GENERATED FROM PYTHON SOURCE LINES 438-441 **Do not use chaining comparison expressions with Biogeme. Not only it does not provide the expected expression, but it does not trigger a warning or an exception.** .. GENERATED FROM PYTHON SOURCE LINES 441-446 .. code-block:: Python try: my_expression = 200 <= Variable('Variable2') <= 400 except BiogemeError as e: print(e) .. rst-class:: sphx-glr-script-out .. code-block:: none Expression (Variable2 >= `200.0`) cannot be used in a boolean expression. Use & for "and" and | for "or" .. GENERATED FROM PYTHON SOURCE LINES 447-448 The correct way to code this expression is .. GENERATED FROM PYTHON SOURCE LINES 448-450 .. code-block:: Python my_expression = (200 <= Variable('Variable2')) & (Variable('Variable2') <= 400) .. GENERATED FROM PYTHON SOURCE LINES 451-456 The reason is that Python executes `200 <= Variable2 <= 400` as `(200 <= Variable2) and (Variable2 <= 400)`. The `and` operator cannot be overloaded in Python. Therefore, it does not return a Biogeme expression. Note that Pandas does not allow chaining either, and has implemented a `between` function instead. .. GENERATED FROM PYTHON SOURCE LINES 456-459 .. code-block:: Python my_data.dataframe['chaining_p'] = my_data.dataframe['Variable2'].between(200, 400) display(my_data.dataframe) .. rst-class:: sphx-glr-script-out .. code-block:: none Person Exclude Variable1 Variable2 Choice Av1 Av2 Av3 chaining_p 0 1.0 0.0 10.0 100.0 2.0 0.0 1.0 0.0 False 1 1.0 0.0 20.0 200.0 2.0 1.0 1.0 1.0 True 2 1.0 1.0 30.0 300.0 3.0 1.0 1.0 1.0 True 3 2.0 0.0 40.0 400.0 1.0 1.0 1.0 1.0 True 4 2.0 1.0 50.0 500.0 2.0 1.0 1.0 1.0 False .. GENERATED FROM PYTHON SOURCE LINES 460-463 The following type of expression is another literal, corresponding to an unknown parameter. Note that the value is just a starting value for the algorithm. .. GENERATED FROM PYTHON SOURCE LINES 463-467 .. code-block:: Python beta1 = Beta('beta1', 0.2, None, None, 0) beta2 = Beta('beta2', 0.4, None, None, 0) .. GENERATED FROM PYTHON SOURCE LINES 468-470 The last argument allows to fix the value of the parameter to the value. .. GENERATED FROM PYTHON SOURCE LINES 470-473 .. code-block:: Python beta3 = Beta('beta3', 1, None, None, 1) beta4 = Beta('beta4', 0, None, None, 1) .. GENERATED FROM PYTHON SOURCE LINES 474-476 Arithmetic operators are overloaded to allow standard manipulations of expressions. .. GENERATED FROM PYTHON SOURCE LINES 476-479 .. code-block:: Python expr0 = beta3 + beta4 print(expr0) .. rst-class:: sphx-glr-script-out .. code-block:: none (Beta('beta3', 1, None, None, 1) + Beta('beta4', 0, None, None, 1)) .. GENERATED FROM PYTHON SOURCE LINES 480-483 The evaluation of expressions can be done in two ways. For simple expressions, the function `get_value`, implemented in Python, returns the value of the expression. .. GENERATED FROM PYTHON SOURCE LINES 483-485 .. code-block:: Python display(f'beta3 + beta4 = {expr0.get_value()}') .. rst-class:: sphx-glr-script-out .. code-block:: none beta3 + beta4 = 1 .. GENERATED FROM PYTHON SOURCE LINES 486-487 It is possible to modify the values of the parameters. .. GENERATED FROM PYTHON SOURCE LINES 487-491 .. code-block:: Python new_values = {'beta1': 1, 'beta2': 2, 'beta3': 3, 'beta4': 2} expr0.change_init_values(new_values) display(f'beta3 + beta4 = {expr0.get_value()}') .. rst-class:: sphx-glr-script-out .. code-block:: none Parameter beta3 is fixed, but its value is changed from 1 to 3. Parameter beta4 is fixed, but its value is changed from 0 to 2. beta3 + beta4 = 5 .. GENERATED FROM PYTHON SOURCE LINES 492-499 Consider another expression: .. math:: e_1 = 2 \beta_1 - \frac{\exp(-\beta_2)}{\beta_2 (\beta_3 \geq \beta_4) + \beta_1 (\beta_3 < \beta_4)}, where :math:`(\beta_2 \geq \beta_1)` equals 1 if :math:`\beta_2 \geq \beta_1` and 0 otherwise. .. GENERATED FROM PYTHON SOURCE LINES 499-503 .. code-block:: Python expr1 = 2 * beta1 - exp(-beta2) / (beta2 * (beta3 >= beta4) + beta1 * (beta3 < beta4)) print(expr1) display(f'expr1 = {expr1.get_value()}') .. rst-class:: sphx-glr-script-out .. code-block:: none ((`2.0` * Beta('beta1', 0.2, None, None, 0)) - (exp((-Beta('beta2', 0.4, None, None, 0))) / ((Beta('beta2', 0.4, None, None, 0) * (Beta('beta3', 3, None, None, 1) >= Beta('beta4', 2, None, None, 1))) + (Beta('beta1', 0.2, None, None, 0) * (Beta('beta3', 3, None, None, 1) < Beta('beta4', 2, None, None, 1)))))) expr1 = -1.275800115089098 .. GENERATED FROM PYTHON SOURCE LINES 504-506 It actually calls the function `get_value_and_derivatives`, and returns its first output (without calculating the derivatives). .. GENERATED FROM PYTHON SOURCE LINES 506-519 .. code-block:: Python value_and_derivatives: FunctionOutput = get_value_and_derivatives( expression=expr1, numerically_safe=False, betas={'beta1': 1, 'beta2': 2, 'beta3': 3, 'beta4': 2}, database=simple_database, gradient=True, hessian=True, bhhh=True, named_results=False, use_jit=True, ) .. GENERATED FROM PYTHON SOURCE LINES 520-522 .. code-block:: Python display(f'Value of the function: {value_and_derivatives.function}') .. rst-class:: sphx-glr-script-out .. code-block:: none Value of the function: 1.9323323583816936 .. GENERATED FROM PYTHON SOURCE LINES 523-525 We create a pandas DataFrame just to have a nicer display of the results. The gradient, that is the first derivatives. .. GENERATED FROM PYTHON SOURCE LINES 525-528 .. code-block:: Python display('Gradient') display(pd.DataFrame(value_and_derivatives.gradient)) .. rst-class:: sphx-glr-script-out .. code-block:: none Gradient 0 0 2.000000 1 0.101501 .. GENERATED FROM PYTHON SOURCE LINES 529-530 The hessian, that is the second derivatives. .. GENERATED FROM PYTHON SOURCE LINES 530-533 .. code-block:: Python display('Hessian') display(pd.DataFrame(value_and_derivatives.hessian)) .. rst-class:: sphx-glr-script-out .. code-block:: none Hessian 0 1 0 0.0 0.000000 1 0.0 -0.169169 .. GENERATED FROM PYTHON SOURCE LINES 534-535 The BHHH matrix, that is the sum of the outer product of the gradient of each observation by itself. .. GENERATED FROM PYTHON SOURCE LINES 535-538 .. code-block:: Python display('BHHH') display(pd.DataFrame(value_and_derivatives.bhhh)) .. rst-class:: sphx-glr-script-out .. code-block:: none BHHH 0 1 0 4.000000 0.203003 1 0.203003 0.010303 .. GENERATED FROM PYTHON SOURCE LINES 539-540 We illustrate the fact that the BHHH matrix is the outer product of the gradient with itself. .. GENERATED FROM PYTHON SOURCE LINES 540-552 .. code-block:: Python display('Outer product of the gradient') display( pd.DataFrame( np.outer( value_and_derivatives.gradient, value_and_derivatives.gradient, ) ) ) .. rst-class:: sphx-glr-script-out .. code-block:: none Outer product of the gradient 0 1 0 4.000000 0.203003 1 0.203003 0.010303 .. GENERATED FROM PYTHON SOURCE LINES 553-565 .. code-block:: Python value_and_derivatives: FunctionOutput = get_value_and_derivatives( expression=expr1, numerically_safe=False, betas={'beta1': 1, 'beta2': 2, 'beta3': 3, 'beta4': 2}, database=simple_database, gradient=True, hessian=True, bhhh=True, named_results=True, use_jit=True, ) .. GENERATED FROM PYTHON SOURCE LINES 566-568 .. code-block:: Python display(f'Value of the function: {value_and_derivatives.function}') .. rst-class:: sphx-glr-script-out .. code-block:: none Value of the function: 1.9323323583816936 .. GENERATED FROM PYTHON SOURCE LINES 569-570 The gradient, that is the first derivatives. .. GENERATED FROM PYTHON SOURCE LINES 570-572 .. code-block:: Python display(value_and_derivatives.gradient) .. rst-class:: sphx-glr-script-out .. code-block:: none {'beta1': np.float64(2.0), 'beta2': np.float64(0.10150146242745953)} .. GENERATED FROM PYTHON SOURCE LINES 573-574 The hessian, that is the second derivatives. .. GENERATED FROM PYTHON SOURCE LINES 574-576 .. code-block:: Python display(pd.DataFrame(value_and_derivatives.hessian)) .. rst-class:: sphx-glr-script-out .. code-block:: none beta1 beta2 beta1 0.0 0.000000 beta2 0.0 -0.169169 .. GENERATED FROM PYTHON SOURCE LINES 577-578 The BHHH matrix, that is the sum of the outer product of the gradient of each observation by itself. .. GENERATED FROM PYTHON SOURCE LINES 578-581 .. code-block:: Python display(pd.DataFrame(value_and_derivatives.bhhh)) .. rst-class:: sphx-glr-script-out .. code-block:: none beta1 beta2 beta1 4.000000 0.203003 beta2 0.203003 0.010303 .. GENERATED FROM PYTHON SOURCE LINES 582-585 It is also possible to generate a function that takes the value of the parameters as argument, and provides a tuple with the value of the expression and its derivatives. . .. GENERATED FROM PYTHON SOURCE LINES 585-594 .. code-block:: Python the_function: CallableExpression = function_from_expression( expression=expr1, database=simple_database, numerically_safe=False, use_jit=True, the_betas={}, ) .. GENERATED FROM PYTHON SOURCE LINES 595-596 We evaluate it at one point... .. GENERATED FROM PYTHON SOURCE LINES 596-602 .. code-block:: Python result: FunctionOutput = the_function([1, 2], gradient=True, hessian=True, bhhh=False) display(f'Value of the function: {result.function}') display(f'Value of the gradient: {result.gradient}') display(f'Value of the hessian: {result.hessian}') display(f'The BHHH matrix has not been requested: {result.bhhh}') .. rst-class:: sphx-glr-script-out .. code-block:: none Value of the function: -1.275800115089098 Value of the gradient: [2. 5.8653004] Value of the hessian: [[ 0. 0. ] [ 0. -31.00230213]] The BHHH matrix has not been requested: None .. GENERATED FROM PYTHON SOURCE LINES 603-604 ... and at another point. .. GENERATED FROM PYTHON SOURCE LINES 604-610 .. code-block:: Python result: FunctionOutput = the_function([10, -2], gradient=True, hessian=True, bhhh=True) display(f'Value of the function: {result.function}') display(f'Value of the gradient: {result.gradient}') display(f'Value of the hessian: {result.hessian}') display(f'Value of the BHHH matrix: {result.bhhh}') .. rst-class:: sphx-glr-script-out .. code-block:: none Value of the function: 23.694528049465326 Value of the gradient: [ 2. -1.84726402] Value of the hessian: [[0. 0. ] [0. 1.84726402]] Value of the BHHH matrix: [[ 4. -3.69452805] [-3.69452805 3.41238438]] .. GENERATED FROM PYTHON SOURCE LINES 611-620 .. code-block:: Python the_function: CallableExpression = function_from_expression( expression=expr1, database=simple_database, numerically_safe=False, the_betas={}, named_output=True, use_jit=True, ) .. GENERATED FROM PYTHON SOURCE LINES 621-622 We evaluate it at one point... .. GENERATED FROM PYTHON SOURCE LINES 622-627 .. code-block:: Python result: FunctionOutput = the_function([2, 1], gradient=True, hessian=True, bhhh=False) display(f'Value of the function: {result.function}') display(f'Value of the gradient: {result.gradient}') display(f'Value of the hessian: {result.hessian}') .. rst-class:: sphx-glr-script-out .. code-block:: none Value of the function: -1.275800115089098 Value of the gradient: {'beta1': np.float64(2.0), 'beta2': np.float64(5.865300402811842)} Value of the hessian: {'beta1': {'beta1': np.float64(0.0), 'beta2': np.float64(0.0)}, 'beta2': {'beta1': np.float64(0.0), 'beta2': np.float64(-31.002302129148305)}} .. GENERATED FROM PYTHON SOURCE LINES 628-630 The following function scans the expression and extracts a dict with all free parameters. .. GENERATED FROM PYTHON SOURCE LINES 630-634 .. code-block:: Python free_betas = list_of_free_betas_in_expression(the_expression=expr1) set_of_free_beta_names = {beta.name for beta in free_betas} display(f'free parameters: {set_of_free_beta_names}') .. rst-class:: sphx-glr-script-out .. code-block:: none free parameters: {'beta2', 'beta1'} .. GENERATED FROM PYTHON SOURCE LINES 635-639 .. code-block:: Python fixed_betas = list_of_fixed_betas_in_expression(the_expression=expr1) set_of_fixed_beta_names = {beta.name for beta in fixed_betas} display(f'fixed parameters: {set_of_fixed_beta_names}') .. rst-class:: sphx-glr-script-out .. code-block:: none fixed parameters: {'beta4', 'beta3'} .. GENERATED FROM PYTHON SOURCE LINES 640-644 .. code-block:: Python all_betas = list_of_all_betas_in_expression(the_expression=expr1) set_of_all_beta_names = {beta.name for beta in all_betas} display(f'all parameters: {set_of_all_beta_names}') .. rst-class:: sphx-glr-script-out .. code-block:: none all parameters: {'beta4', 'beta2', 'beta3', 'beta1'} .. GENERATED FROM PYTHON SOURCE LINES 645-646 The list of variables can also be extracted. In this case, there is none. .. GENERATED FROM PYTHON SOURCE LINES 646-650 .. code-block:: Python all_variables = list_of_variables_in_expression(the_expression=expr1) set_of_variables = {variable.name for variable in all_variables} display(f'all variables: {set_of_variables}') .. rst-class:: sphx-glr-script-out .. code-block:: none all variables: set() .. GENERATED FROM PYTHON SOURCE LINES 651-652 We include one variable .. GENERATED FROM PYTHON SOURCE LINES 652-658 .. code-block:: Python new_expression = expr1 + Variable('a_variable') all_variables = list_of_variables_in_expression(the_expression=new_expression) set_of_variables = {variable.name for variable in all_variables} display(f'all variables: {set_of_variables}') .. rst-class:: sphx-glr-script-out .. code-block:: none all variables: {'a_variable'} .. GENERATED FROM PYTHON SOURCE LINES 659-665 We now illustrate how to calculate a logit model, that is .. math:: \frac{y_1 e^{V_1}}{y_0 e^{V_0}+y_1 e^{V_1}+y_2 e^{V_2}} where :math:`V_0=-\beta_1`, :math:`V_1=-\beta_2` and :math:`V_2=-\beta_1`, and :math:`y_i = 1`, :math:`i=1,2,3`. .. GENERATED FROM PYTHON SOURCE LINES 665-670 .. code-block:: Python v = {0: -beta1, 1: -beta2, 2: -beta1} av = {0: 1, 1: 1, 2: 1} expr7 = LogLogit(v, av, 1) # value = evaluate_simple_expression(expression=z, database=None, numerically_safe=False) .. GENERATED FROM PYTHON SOURCE LINES 671-673 .. code-block:: Python display(f'Value of the log of the logit for alternative 1: {expr7.get_value()}') .. rst-class:: sphx-glr-script-out .. code-block:: none Value of the log of the logit for alternative 1: -1.2362866960692134 .. GENERATED FROM PYTHON SOURCE LINES 674-675 If the alternative is not in the choice set, an exception is raised. .. GENERATED FROM PYTHON SOURCE LINES 675-681 .. code-block:: Python expr7_wrong = LogLogit(v, av, 3) try: expr7_wrong.get_value() except BiogemeError as e: print(f'Exception: {e}') .. rst-class:: sphx-glr-script-out .. code-block:: none Exception: Alternative 3 does not appear in the list of utility functions: dict_keys([0, 1, 2]) .. GENERATED FROM PYTHON SOURCE LINES 682-683 We show how to calculate the logsum. .. GENERATED FROM PYTHON SOURCE LINES 683-686 .. code-block:: Python for util in v.values(): print(util.get_value()) .. rst-class:: sphx-glr-script-out .. code-block:: none -0.2 -0.4 -0.2 .. GENERATED FROM PYTHON SOURCE LINES 687-693 .. code-block:: Python logsum = np.log( np.sum( [np.exp(util.get_value()) for util in v.values()], ) ) display(f'Value of the logsum: {logsum}') .. rst-class:: sphx-glr-script-out .. code-block:: none Value of the logsum: 0.8362866960692136 .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 0.668 seconds) .. _sphx_glr_download_auto_examples_programmers_plot_expressions.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_expressions.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_expressions.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: plot_expressions.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_