class Expressions: examples of use of each function

This webpage is for programmers who need examples of use of the functions of the class. The examples are designed to illustrate the syntax. They do not correspond to any meaningful model. For examples of models, visit biogeme.epfl.ch.

In [1]:
import datetime
print(datetime.datetime.now())
2019-12-29 21:17:15.300720
In [2]:
import biogeme.version as ver
print(ver.getText())
biogeme 3.2.5 [2019-12-29]
Version entirely written in Python
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)

In [3]:
import numpy as np
import pandas as pd
import biogeme.expressions as ex
import biogeme.database as db

We first create a small database

In [4]:
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':[1,2,3,1,2],
                   'Av1':[0,1,1,1,1],
                   'Av2':[1,1,1,1,1],
                   'Av3':[0,1,1,1,1]})
myData = db.Database('test',df)

The following type of expression is a literal called Variable that corresponds to an entry in the database.

In [5]:
Person=ex.Variable('Person')
Variable1=ex.Variable('Variable1')
Variable2=ex.Variable('Variable2')
Choice=ex.Variable('Choice')
Av1=ex.Variable('Av1')
Av2=ex.Variable('Av2')
Av3=ex.Variable('Av3')

It is possible to add a new column to thre database, that creates a new variable that can be used in expressions.

In [6]:
newvar = ex.DefineVariable('newvar',Variable1+Variable2,myData)
print(myData)
biogeme database test:
   Person  Exclude  Variable1  Variable2  Choice  Av1  Av2  Av3  newvar
0       1        0         10        100       1    0    1    0     110
1       1        0         20        200       2    1    1    1     220
2       1        1         30        300       3    1    1    1     330
3       2        0         40        400       1    1    1    1     440
4       2        1         50        500       2    1    1    1     550

The following type of expression is another literal, corresponding to an unknown parameter.

In [7]:
beta1 = ex.Beta('beta1',0,None,None,0)
beta2 = ex.Beta('beta2',0,None,None,0)
beta3 = ex.Beta('beta3',1,None,None,1)
beta4 = ex.Beta('beta4',0,None,None,1)

Arithmetic operators are overloaded to allow standard manipulations of expressions. The first expression is $$e_1 = 2 \beta_1 - \frac{\exp(-\beta_2)}{\beta_3 (\beta_2 \geq \beta_1)},$$ where $(\beta_2 \geq \beta_1)$ equals 1 if $\beta_2 \geq \beta_1$ and 0 otherwise.

In [8]:
expr1 = 2 * beta1 - ex.exp(-beta2) / (beta3 * (beta2 >= beta1))
print(expr1)
((`2` * beta1(0)) - (exp((-beta2(0))) / (beta3(1) * (beta2(0) >= beta1(0)))))

The evaluation of expressions can be done in two ways. For simple expressions, the fonction getValue(), implemented in Python, returns the value of the expression.

In [9]:
expr1.getValue()
Out[9]:
-1.0

It is possible to modify the values of the parameters

In [10]:
newvalues = {'beta1':1,'beta2':2,'beta3':3,'beta4':2}
expr1.changeInitValues(newvalues)
expr1.getValue()
Out[10]:
1.954888238921129

The function getValue_c() is implemented in C++, and works for any expression. It requires a database as input, and evaluates the expression for each entry in the database. In the following example, as no variable of the database is involved in the expression, the output of the expression is the same for each entry.

In [11]:
expr1.getValue_c(myData)
Out[11]:
[1.954888238921129,
 1.954888238921129,
 1.954888238921129,
 1.954888238921129,
 1.954888238921129]

The following function scans the expression and extracts a dict with all free parameters.

In [12]:
expr1.setOfBetas()
Out[12]:
{'beta1', 'beta2'}

Options can be set to extract free parameters, fixed parameters, or both.

In [13]:
expr1.setOfBetas(free=False,fixed=True)
Out[13]:
{'beta3'}
In [14]:
expr1.setOfBetas(free=True,fixed=True)
Out[14]:
{'beta1', 'beta2', 'beta3'}
In [15]:
expr1.getElementaryExpression('beta2')
Out[15]:
beta2(2)

Let's consider an expression involving two variables $V_1$ and $V_2$: $$e_2 =2 \beta_1 V_1 - \frac{\exp(-\beta_2 V_2) }{ \beta_3 (\beta_2 \geq \beta_1)}.$$ Note that, in our example, the second term is numerically negligible with respect to the first one.

In [16]:
expr2 = 2 * beta1 * Variable1 - ex.exp(-beta2*Variable2) / (beta3 * (beta2 >= beta1))
print(expr2)
(((`2` * beta1(1)) * Variable1) - (exp(((-beta2(2)) * Variable2)) / (beta3(3) * (beta2(2) >= beta1(1)))))

It is not a simple expression anymore, and only the function getValue_c can be invoked.

In [17]:
expr2.getValue_c(myData)
Out[17]:
[20.0, 40.0, 60.0, 80.0, 100.0]

The following function extracts the names of the parameters apprearing in the expression

In [18]:
expr2.setOfBetas(free=True,fixed=True)
Out[18]:
{'beta1', 'beta2', 'beta3'}

The list of parameters can also be obtained in the form of a dictionary.

In [19]:
expr2.dictOfBetas(free=True,fixed=True)
Out[19]:
{'beta1': beta1(1), 'beta2': beta2(2), 'beta3': beta3(3)}

The list of variables can also be obtained in the form of a dictionary

In [20]:
expr2.dictOfVariables()
Out[20]:
{'Variable1': Variable1, 'Variable2': Variable2}

or a set...

In [21]:
expr2.setOfVariables()
Out[21]:
{'Variable1', 'Variable2'}

Expressions are defined recursively, using a tree representation. The following function describes the type of the upper most node of the tree.

In [22]:
expr2.getClassName()
Out[22]:
'Minus'

The signature is a formal representation of the expression, assigning identifiers to each node of the tree, and representing them starting from the leaves. It is easy to parse, and is passed to the C++ implementation.

In [23]:
expr2.getSignature()
Out[23]:
[b'<Numeric>{4667374656},2',
 b'<Beta>{4667262096}"beta1"[0],0,0',
 b'<Times>{4667374416}(2),4667374656,4667262096',
 b'<Variable>{4666962272}"Variable1",5,2',
 b'<Times>{4667374608}(2),4667374416,4666962272',
 b'<Beta>{4667262000}"beta2"[0],1,1',
 b'<UnaryMinus>{4667374704}(1),4667262000',
 b'<Variable>{4666962464}"Variable2",6,3',
 b'<Times>{4667374080}(2),4667374704,4666962464',
 b'<exp>{4667374752}(1),4667374080',
 b'<Beta>{4667262144}"beta3"[1],2,0',
 b'<Beta>{4667262000}"beta2"[0],1,1',
 b'<Beta>{4667262096}"beta1"[0],0,0',
 b'<GreaterOrEqual>{4667374800}(2),4667262000,4667262096',
 b'<Times>{4667374896}(2),4667262144,4667374800',
 b'<Divide>{4667374944}(2),4667374752,4667374896',
 b'<Minus>{4667374992}(2),4667374608,4667374944']

The elementary expressions are

  • free parameters,
  • fixed parameters,
  • random variables (for numerical integration),
  • draws (for Monte-Carlo integration), and
  • variables from the database.

The following function extracts all elementary expressions from a list of formulas, give them a unique numbering, and return them organized by group, as defined above (with the exception of the variables, that are directly available in the database).

In [24]:
collectionOfFormulas = [expr1,expr2]
elementaryExpressionIndex,allFreeBetas,freeBetaNames,allFixedBetas,fixedBetaNames,allRandomVariables,randomVariableNames,allDraws,drawNames = ex.defineNumberingOfElementaryExpressions(collectionOfFormulas,list(myData.data.columns))

Unique numbering for all elementary expressions

In [25]:
elementaryExpressionIndex
Out[25]:
{'beta1': 0,
 'beta2': 1,
 'beta3': 2,
 'Person': 3,
 'Exclude': 4,
 'Variable1': 5,
 'Variable2': 6,
 'Choice': 7,
 'Av1': 8,
 'Av2': 9,
 'Av3': 10,
 'newvar': 11}
In [26]:
allFreeBetas
Out[26]:
{'beta1': beta1(1), 'beta2': beta2(2)}

Each elementary expression has two ids. One unique across all elementary expressions, and one unique within each specific group

In [27]:
[(i.uniqueId,i.betaId) for k,i in allFreeBetas.items()]
Out[27]:
[(0, 0), (1, 1)]
In [28]:
freeBetaNames
Out[28]:
['beta1', 'beta2']
In [29]:
allFixedBetas
Out[29]:
{'beta3': beta3(3)}
In [30]:
[(i.uniqueId,i.betaId) for k,i in allFixedBetas.items()]
Out[30]:
[(2, 0)]
In [31]:
fixedBetaNames
Out[31]:
['beta3']
In [32]:
allRandomVariables
Out[32]:
{}

Monte Carlo integration is based on draws.

In [33]:
myDraws = ex.bioDraws('myDraws','UNIFORM')
expr3 = ex.MonteCarlo(myDraws*myDraws)
In [34]:
print(expr3)
MonteCarlo((bioDraws('myDraws','UNIFORM') * bioDraws('myDraws','UNIFORM')))

Note that draws are not random variables, used for numerical integration.

In [35]:
expr3.dictOfRandomVariables()
Out[35]:
{}

The following function reports the draws involved in an expression.

In [36]:
expr3.dictOfDraws()
Out[36]:
{'myDraws': 'UNIFORM'}

The expression is a Monte-Carlo integration.

In [37]:
expr3.getClassName()
Out[37]:
'MonteCarlo'

Here is its value. It is an approximation of $\int_0^1 x^2 dx=\frac{1}{3}$.

In [38]:
expr3.getValue_c(myData,numberOfDraws=100000)
Out[38]:
[0.3343601301913099,
 0.3334449674544236,
 0.3319844536348692,
 0.3330267847335473,
 0.3335340969718851]

Here is its signature.

In [39]:
expr3.getSignature()
Out[39]:
[b'<bioDraws>{4667528288}"myDraws",0,0',
 b'<bioDraws>{4667528288}"myDraws",0,0',
 b'<Times>{4667528240}(2),4667528288,4667528288',
 b'<MonteCarlo>{4667527520}(1),4667528240']

The same integral can be calculated using numerical integration, declaring a random variable.

In [40]:
omega = ex.RandomVariable('omega')

Numerical integration calculates integrals between $-\infty$ and $+\infty$. Here, the interval being $[0,1]$, a change of variables is required.

In [41]:
a = 0
b = 1
x = a + (b-a) / ( 1 + ex.exp(-omega))
dx = (b-a) * ex.exp(-omega) * (1+ex.exp(-omega))**(-2) 
integrand = x * x
expr4 = ex.Integrate(integrand * dx /(b-a),'omega')

In this case, omega is a random variable.

In [42]:
expr4.dictOfRandomVariables()
Out[42]:
{'omega': omega}
In [43]:
print(expr4)
Integrate(((((`0` + (`1` / (`1` + exp((-omega))))) * (`0` + (`1` / (`1` + exp((-omega)))))) * ((`1` * exp((-omega))) * ((`1` + exp((-omega))) ** `-2`))) / `1`),'omega')

Calculating its value requires the C++ implementation.

In [44]:
expr4.getValue_c(myData)
Out[44]:
[0.3333323120662823,
 0.3333323120662823,
 0.3333323120662823,
 0.3333323120662823,
 0.3333323120662823]

We illustrate now the Elem function. It takes two arguments: a dictionary, and a formula for the key. For each entry in the database, the formula is evaluated, and its result identifies which formula in the dictionary should be evaluated. Here is 'Person' is 1, the expression is $$e_1=2 \beta_1 - \frac{\exp(-\beta_2)}{\beta_3 (\beta_2 \geq \beta_1)},$$ and if 'Person' is 2, the expression is $$e_2=2 \beta_1 V_1 - \frac{\exp(-\beta_2 V_2) }{ \beta_3 (\beta_2 \geq \beta_1)}.$$ As it is a regular expression, it can be included in any formula. Here, we illustrate it by dividing the result by 10.

In [45]:
elemExpr = ex.Elem({1:expr1,2:expr2},Person) 
expr5 =  elemExpr / 10
print(expr5)
({{1:((`2` * beta1(1)) - (exp((-beta2(2))) / (beta3(3) * (beta2(2) >= beta1(1))))),2:(((`2` * beta1(1)) * Variable1) - (exp(((-beta2(2)) * Variable2)) / (beta3(3) * (beta2(2) >= beta1(1)))))}[Person] / `10`)
In [46]:
expr5.dictOfVariables()
Out[46]:
{'Variable1': Variable1, 'Variable2': Variable2, 'Person': Person}
In [47]:
expr5.getValue_c(myData)
Out[47]:
[0.19548882389211292, 0.19548882389211292, 0.19548882389211292, 8.0, 10.0]

The next expression is simply the sum of multiples expressions. The argument is a list of expressions.

In [48]:
expr6 = ex.bioMultSum([expr1,expr2,expr4])
In [49]:
print(expr6)
bioMultSum(((`2` * beta1(1)) - (exp((-beta2(2))) / (beta3(3) * (beta2(2) >= beta1(1))))) + (((`2` * beta1(1)) * Variable1) - (exp(((-beta2(2)) * Variable2)) / (beta3(3) * (beta2(2) >= beta1(1))))) + Integrate(((((`0` + (`1` / (`1` + exp((-omega))))) * (`0` + (`1` / (`1` + exp((-omega)))))) * ((`1` * exp((-omega))) * ((`1` + exp((-omega))) ** `-2`))) / `1`),'omega'))
In [50]:
expr6.getValue_c(myData,100000)
Out[50]:
[22.28822055098741,
 42.28822055098741,
 62.28822055098741,
 82.2882205509874,
 102.2882205509874]

We now illustrate how to calculate a logit model, that is $$ \frac{y_1 e^{V_1}}{y_0 e^{V_0}+y_1 e^{V_1}+y_2 e^{V_2}}$$ where $V_0=-\beta_1$, $V_1=-\beta_2$ and $V_2=-\beta_1$, and $y_i = 1$, $i=1,2,3$.

In [51]:
V = {0:-beta1,1:-beta2,2:-beta1}
av = {0:1,1:1,2:1}
expr7 = ex.LogLogit(V,av,1)
In [52]:
expr7.getValue()
Out[52]:
-1.861994804058251

It is actually better to use the C++ implementation, availablr in the module models

In [53]:
import biogeme.models as models
expr8 = models.loglogit(V,av,1)
In [54]:
expr8.getValue_c(myData)
Out[54]:
[-1.8619948040582512,
 -1.8619948040582512,
 -1.8619948040582512,
 -1.8619948040582512,
 -1.8619948040582512]

As the result is a numpy array, it can be used for any calculation. Here, we show how to calculate the logsum

In [55]:
for v in V.values():
    print(v.getValue_c(myData))
[-1.0, -1.0, -1.0, -1.0, -1.0]
[-2.0, -2.0, -2.0, -2.0, -2.0]
[-1.0, -1.0, -1.0, -1.0, -1.0]
In [56]:
logsum = np.log(np.sum([np.exp(v.getValue_c(myData)) for v in V.values()],axis=1))
logsum
Out[56]:
array([ 0.60943791, -0.39056209,  0.60943791])

It is possible to calculate the derivative of a formula with respect to a literal: $$e_9=\frac{\partial e_8}{\partial \beta_2}.$$

In [57]:
expr9 = ex.Derive(expr8,'beta2')
In [58]:
expr9.getValue_c(myData)
Out[58]:
[-0.8446375965030364,
 -0.8446375965030364,
 -0.8446375965030364,
 -0.8446375965030364,
 -0.8446375965030364]

Biogeme also provides an approximation of the CDF of the normal distribution: $$e_{10}= \frac{1}{{\sigma \sqrt {2\pi } }}\int_{-\infty}^t e^{{{ - \left( {x - \mu } \right)^2 } \mathord{\left/ {\vphantom {{ - \left( {x - \mu } \right)^2 } {2\sigma ^2 }}} \right. } {2\sigma ^2 }}}dx$$

In [59]:
expr10 = ex.bioNormalCdf(Variable1/10-1)
In [60]:
expr10.getValue_c(myData)
Out[60]:
[0.5,
 0.8413447460685283,
 0.9772498680518218,
 0.99865010196837,
 0.9999683287581669]

Min and max operators are also available. To avoid any ambiguity with the Python operator, they are called bioMin and bioMax.

In [61]:
expr11 = ex.bioMin(expr5,expr10)
expr11.getValue_c(myData)
Out[61]:
[0.19548882389211292,
 0.19548882389211292,
 0.19548882389211292,
 0.99865010196837,
 0.9999683287581669]
In [62]:
expr12 = ex.bioMax(expr5,expr10)
expr12.getValue_c(myData)
Out[62]:
[0.5, 0.8413447460685283, 0.9772498680518218, 8.0, 10.0]

For the sake of efficiency, it is possible to specify explicitly a linear function, where each term is the product of a parameter and a variable.

In [63]:
terms = [(beta1,ex.Variable('Variable1')),(beta2,ex.Variable('Variable2')),(beta3,ex.Variable('newvar'))]
In [64]:
expr13 = ex.bioLinearUtility(terms)
In [65]:
expr13.getValue_c(myData)
Out[65]:
[540.0, 1080.0, 1620.0, 2160.0, 2700.0]

In terms of specification, it is equivalent to the expression below. But the calculation of the derivates is more efficient, as the linear structure of the specification is exploited.

In [66]:
expr13bis = beta1 * Variable1 + beta2 * Variable2 + beta3 * newvar
In [67]:
expr13bis.getValue_c(myData)
Out[67]:
[540.0, 1080.0, 1620.0, 2160.0, 2700.0]

A Pythonic way to write a linear utility function

In [68]:
variables = ['v1','v2','v3','cost','time','headway']
coefficients = {f'{v}':ex.Beta(f'beta_{v}',0,None,None,0) for v in variables}
terms = [coefficients[v] * ex.Variable(v) for v in variables]
util = sum(terms)
print(util)
((((((`0` + (beta_v1(0) * v1)) + (beta_v2(0) * v2)) + (beta_v3(0) * v3)) + (beta_cost(0) * cost)) + (beta_time(0) * time)) + (beta_headway(0) * headway))

Signatures

The Python library communicates the expressions to the C++ library using a syntax called a "signature". We describe and illustrate now the signature for each expression. Each expression is identified by an identifier provided by Python using the function 'id'.

In [69]:
id(expr1)
Out[69]:
4667263248

Numerical expression

< Numeric >{identifier},value I DO NOT KNOW HOW TO GET RID OF THE WHITE SPACES

In [70]:
ex.Numeric(0).getSignature()
Out[70]:
[b'<Numeric>{4667695264},0']

Beta parameters

< Beta >{identifier}"name"[status],uniqueId,betaId' where

  • status is 0 for free parameters, and non zero for fixed parameters,
  • uniqueId is a unique index given by Biogeme to all elementary expressions,
  • betaId is a unique index given by Biogeme to all free parameters, and to all fixed parameters.
In [71]:
beta1.getSignature()
Out[71]:
[b'<Beta>{4667262096}"beta1"[0],0,0']
In [72]:
beta3.getSignature()
Out[72]:
[b'<Beta>{4667262144}"beta3"[1],2,0']

Variables

< Variable >{identifier}"name",uniqueId,variableId where

  • uniqueId is a unique index given by Biogeme to all elementary expressions,
  • variableId is a unique index given by Biogeme to all variables.
In [73]:
Variable1.getSignature()
Out[73]:
[b'<Variable>{4666962272}"Variable1",5,2']

Random variables

< RandomVariable >{identifier}"name",uniqueId,randomVariableId where

  • uniqueId is a unique index given by Biogeme to all elementary expressions,
  • randomVariableId is a unique index given by Biogeme to all random variables.
In [74]:
omega.getSignature()
Out[74]:
[b'<RandomVariable>{4667481584}"omega",3,0']

Draws

< bioDraws >{identifier}"name",uniqueId,drawId where

  • uniqueId is a unique index given by Biogeme to all elementary expressions,
  • drawId is a unique index given by Biogeme to all draws.
In [75]:
myDraws.getSignature()
Out[75]:
[b'<bioDraws>{4667528288}"myDraws",0,0']

General expression

< operator >{identifier}(numberOfChildren),idFirstChild,idSecondChild,idThirdChild, etc... where the number of identifiers given after the comma matches the reported number of children.

Specific examples are reported below.

Binary operator

< operator >{identifier}(2),idFirstChild,idSecondChild where operator is one of:

- 'Plus'
- 'Minus'
- 'Times'
- 'Divide'
- 'Power'
- 'bioMin'
- 'bioMax'
- 'And'
- 'Or'
- 'Equal'
- 'NotEqual'
- 'LessOrEqual'
- 'GreaterOrEqual'
- 'Less'
- 'Greater'
In [76]:
sum = beta1 + Variable1
In [77]:
sum.getSignature()
Out[77]:
[b'<Beta>{4667262096}"beta1"[0],0,0',
 b'<Variable>{4666962272}"Variable1",5,2',
 b'<Plus>{4667694624}(2),4667262096,4666962272']

Unary operator

< operator >{identifier}(1),idChild, where operator is one of:

- 'UnaryMinus'
- 'MonteCarlo'
- 'bioNormalCdf'
- 'PanelLikelihoodTrajectory'
- 'exp'
- 'log'
In [78]:
m = -beta1
In [79]:
m.getSignature()
Out[79]:
[b'<Beta>{4667262096}"beta1"[0],0,0',
 b'<UnaryMinus>{4667736704}(1),4667262096']

LogLogit

< LogLogit >{identifier}(nbrOfAlternatives),chosenAlt,altNumber,utility,availability,altNumber,utility,availability, etc.

In [80]:
expr7.getSignature()
Out[80]:
[b'<Numeric>{4667264160},1',
 b'<Beta>{4667262096}"beta1"[0],0,0',
 b'<UnaryMinus>{4667261376}(1),4667262096',
 b'<Beta>{4667262000}"beta2"[0],1,1',
 b'<UnaryMinus>{4667263824}(1),4667262000',
 b'<Beta>{4667262096}"beta1"[0],0,0',
 b'<UnaryMinus>{4667262624}(1),4667262096',
 b'<Numeric>{4667261856},1',
 b'<Numeric>{4667263776},1',
 b'<Numeric>{4667262384},1',
 b'<LogLogit>{4667261040}(3),4667264160,0,4667261376,4667261856,1,4667263824,4667263776,2,4667262624,4667262384']

Derive

< Derive >{identifier},id of expression to derive,unique index of elementary expression

In [81]:
expr9.getSignature()
Out[81]:
[b'<Numeric>{4667478752},1',
 b'<Beta>{4667262096}"beta1"[0],0,0',
 b'<UnaryMinus>{4667261376}(1),4667262096',
 b'<Beta>{4667262000}"beta2"[0],1,1',
 b'<UnaryMinus>{4667263824}(1),4667262000',
 b'<Beta>{4667262096}"beta1"[0],0,0',
 b'<UnaryMinus>{4667262624}(1),4667262096',
 b'<Numeric>{4667479856},1',
 b'<Numeric>{4667479328},1',
 b'<Numeric>{4667479280},1',
 b'<_bioLogLogit>{4667480048}(3),4667478752,0,4667261376,4667479856,1,4667263824,4667479328,2,4667262624,4667479280',
 b'<Derive>{4667662448},4667480048,1']

Integrate

< Integrate >{identifier},id of expression to derive,index of random variable

In [82]:
expr4.getSignature()
Out[82]:
[b'<Numeric>{4667371968},0',
 b'<Numeric>{4667372256},1',
 b'<Numeric>{4667375520},1',
 b'<RandomVariable>{4667481584}"omega",3,0',
 b'<UnaryMinus>{4667373888}(1),4667481584',
 b'<exp>{4667374320}(1),4667373888',
 b'<Plus>{4667373456}(2),4667375520,4667374320',
 b'<Divide>{4667373840}(2),4667372256,4667373456',
 b'<Plus>{4667373264}(2),4667371968,4667373840',
 b'<Numeric>{4667371968},0',
 b'<Numeric>{4667372256},1',
 b'<Numeric>{4667375520},1',
 b'<RandomVariable>{4667481584}"omega",3,0',
 b'<UnaryMinus>{4667373888}(1),4667481584',
 b'<exp>{4667374320}(1),4667373888',
 b'<Plus>{4667373456}(2),4667375520,4667374320',
 b'<Divide>{4667373840}(2),4667372256,4667373456',
 b'<Plus>{4667373264}(2),4667371968,4667373840',
 b'<Times>{4667372160}(2),4667373264,4667373264',
 b'<Numeric>{4667373648},1',
 b'<RandomVariable>{4667481584}"omega",3,0',
 b'<UnaryMinus>{4667374128}(1),4667481584',
 b'<exp>{4667375376}(1),4667374128',
 b'<Times>{4667372544}(2),4667373648,4667375376',
 b'<Numeric>{4667375328},1',
 b'<RandomVariable>{4667481584}"omega",3,0',
 b'<UnaryMinus>{4667374032}(1),4667481584',
 b'<exp>{4667371776}(1),4667374032',
 b'<Plus>{4667371584}(2),4667375328,4667371776',
 b'<Numeric>{4667375232},-2',
 b'<Power>{4667373744}(2),4667371584,4667375232',
 b'<Times>{4667373120}(2),4667372544,4667373744',
 b'<Times>{4667372640}(2),4667372160,4667373120',
 b'<Numeric>{4667372112},1',
 b'<Divide>{4667373072}(2),4667372640,4667372112',
 b'<Integrate>{4667375472},4667373072,0']

Elem

< Elem >{identifier}(numberOfExpressions),keyId,value1,expression1,value2,expression2, etc...

where

  • keyId is the identifier of the expression calculating the key,
  • the number of pairs valuex,expressionx must correspond to the value of numberOfExpressions
In [83]:
elemExpr.getSignature()
Out[83]:
[b'<Variable>{4666962368}"Person",3,0',
 b'<Numeric>{4667262672},2',
 b'<Beta>{4667262096}"beta1"[0],0,0',
 b'<Times>{4667262960}(2),4667262672,4667262096',
 b'<Beta>{4667262000}"beta2"[0],1,1',
 b'<UnaryMinus>{4667263008}(1),4667262000',
 b'<exp>{4667263056}(1),4667263008',
 b'<Beta>{4667262144}"beta3"[1],2,0',
 b'<Beta>{4667262000}"beta2"[0],1,1',
 b'<Beta>{4667262096}"beta1"[0],0,0',
 b'<GreaterOrEqual>{4667263104}(2),4667262000,4667262096',
 b'<Times>{4667262912}(2),4667262144,4667263104',
 b'<Divide>{4667263152}(2),4667263056,4667262912',
 b'<Minus>{4667263248}(2),4667262960,4667263152',
 b'<Numeric>{4667374656},2',
 b'<Beta>{4667262096}"beta1"[0],0,0',
 b'<Times>{4667374416}(2),4667374656,4667262096',
 b'<Variable>{4666962272}"Variable1",5,2',
 b'<Times>{4667374608}(2),4667374416,4666962272',
 b'<Beta>{4667262000}"beta2"[0],1,1',
 b'<UnaryMinus>{4667374704}(1),4667262000',
 b'<Variable>{4666962464}"Variable2",6,3',
 b'<Times>{4667374080}(2),4667374704,4666962464',
 b'<exp>{4667374752}(1),4667374080',
 b'<Beta>{4667262144}"beta3"[1],2,0',
 b'<Beta>{4667262000}"beta2"[0],1,1',
 b'<Beta>{4667262096}"beta1"[0],0,0',
 b'<GreaterOrEqual>{4667374800}(2),4667262000,4667262096',
 b'<Times>{4667374896}(2),4667262144,4667374800',
 b'<Divide>{4667374944}(2),4667374752,4667374896',
 b'<Minus>{4667374992}(2),4667374608,4667374944',
 b'<Elem>{4667530496}(2),4666962368,1,4667263248,2,4667374992']
In [ ]: