Biogeme: Python Library  2.5
bio_expression.py
Go to the documentation of this file.
1 
5 
6 #import hashlib #remove if not needed
7 #import random #remove if not needed
8 import string
9 ## @brief Generic class for an operator. Manages the IDs of the various operators.
10 class Operator:
11 
12  num = 'numeric'
13  var = 'variable'
14  userexpr = 'UserExpression'
15  userdraws = 'UserDraws'
16  rv = 'randomVariable'
17  param = 'beta'
18  mcdraws = 'MCDraw'
19  mcunifdraws = 'MCUnifDraw'
20  normal = 'N(0,1)'
21  uniform = 'U[0,1]'
22  uniformSym = 'U[-1,1]'
23  absOp, negOp = 'abs','minus'
24  exp, log = 'exp','log'
25  bioNormalCdf = 'bioNormalCdf'
26  add, sub, mul, div, power = '+', '-', '*', '/', '**'
27  andOp, orOp, equal, notEqual = 'and','or','==','<>'
28  greater, greaterEq, less, lessEq = '>','>=','<','<='
29  minOp, maxOp, mod = 'min','max','mod'
30  sumOp, prodOp, integralOp, derivativeOp = 'sum', 'prod','integral','derivative'
31  monteCarloOp = 'MonteCarlo'
32  monteCarloCVOp = 'MonteCarloControlVariate'
33  elemOp, enumOp, logitOp, loglogitOp, multSumOp, multProdOp, bioNormalPdf = 'elem', 'enumerate','logit','loglogit','multSum','multProd','bioNormalPdf'
34  mhOp = 'MH'
35  bayesMeanOp = 'bioBayesNormalDraw'
36  defineOp = 'define'
37 
38  # Bounds
39  MIN_ZEROOP_INDEX = 0
40  MAX_ZEROOP_INDEX = 19
41  MIN_UNOP_INDEX = 20
42  MAX_UNOP_INDEX = 39
43  MIN_BINOP_INDEX = 40
44  MAX_BINOP_INDEX = 69
45  MIN_ITERATOROP_INDEX = 70
46  MAX_ITERATOROP_INDEX = 89
47 
48  UNDEF_OP = -1
49 
50  # Each operator is associated with an index depending on
51  # the above bounds
52  operatorIndexDic = {num:0, \
53  var:1, \
54  param:2, \
55  normal:3, \
56  uniform:4, \
57  rv:5, \
58  uniformSym:6, \
59  userexpr:7, \
60  mcdraws:8, \
61  mcunifdraws:9, \
62  userdraws:10, \
63  absOp:20, negOp:21, \
64  exp:30, log:31, bioNormalCdf: 33, monteCarloOp: 34,\
65  add:40, sub:41, mul:42, div:43, power:44, \
66  andOp:45, orOp:46, equal:47, notEqual:48, \
67  greater:49, greaterEq:50, less:51, lessEq:52, \
68  minOp:53, maxOp:54, mod:55, \
69  sumOp:70, prodOp:71, \
70  elemOp:90, enumOp:91, integralOp:92, derivativeOp:93, \
71  defineOp:94, logitOp:95, bioNormalPdf:96, multSumOp:97, multProdOp:98, mhOp:99, bayesMeanOp:100,monteCarloCVOp: 101,loglogitOp:102 }
72 
73  # Return the index associated to an operator
74  def getOpIndex(self,op):
75  return Operator.operatorIndexDic[op];
76 
77 
78 Operator = Operator()
79 
80 
81 ## @brief Build an "Expression" object from a numeric value
82 # @param exp Object of numeric type or of type Expression
83 def buildExpressionObj(exp):
84  ## Check if the object is numeric
85  def isNumeric(obj):
86  # Consider only ints and floats numeric
87  return isinstance(obj,int) or isinstance(obj,float)
88 
89  if isNumeric(exp) :
90  return Numeric(exp)
91  else :
92  return exp
93 
94 ## @brief Interface for mathematical expressions
95 class Expression:
96  ## Constructor
97  def __init__(self):
98  self.operatorIndex = UNDEF_OP
99 
100 
101  ## @return Return the string representation of the current expression
102  def getExpression(self):
103  raise NotImplementedError("getExpression must be implemented! ")
104 
105  ## @return Return an ID for this expression, can be "xx-no ID" if the sublcass doest not override the function
106  def getID(self):
107  return str(self.operatorIndex) + "-no ID"
108 
109  ## @return Returns a string with the expression
110  def __str__(self):
111  return self.getExpression()
112 
113  ## @return If E is the expression, returns -E
114  # @ingroup operators
115 
116  def __neg__(self):
117  return UnOp(Operator.negOp, self)
118 
119  ## @param expression An another expression
120  ## @return If E is the expression, returns E + expression
121  # @ingroup operators
122  def __add__(self, expression):
123  return BinOp(Operator.add, self, buildExpressionObj(expression))
124 
125  ## @param expression An another expression
126  ## @return If E is the expression, returns expression + E
127  # @ingroup operators
128  def __radd__(self, expression):
129  return BinOp(Operator.add, buildExpressionObj(expression), self)
130 
131  ## @param expression An another expression
132  ## @return If E is the expression, returns E - expression
133  # @ingroup operators
134  def __sub__(self, expression):
135  return BinOp(Operator.sub, self, buildExpressionObj(expression))
136 
137  ## @param expression An another expression
138  ## @return If E is the expression, returns expression - E
139  # @ingroup operators
140  def __rsub__(self, expression):
141  return BinOp(Operator.sub, buildExpressionObj(expression), self)
142 
143  ## @param expression An another expression
144  ## @return If E is the expression, returns E * expression
145  # @ingroup operators
146  def __mul__(self, expression):
147  return BinOp(Operator.mul, self, buildExpressionObj(expression))
148 
149  ## @param expression An another expression
150  ## @return If E is the expression, returns expression * E
151  # @ingroup operators
152  def __rmul__(self, expression):
153  return BinOp(Operator.mul, buildExpressionObj(expression), self)
154 
155  ## @param expression An another expression
156  ## @return If E is the expression, returns E / expression
157  # @ingroup operators
158  def __div__(self, expression):
159  return BinOp(Operator.div, self, buildExpressionObj(expression))
160 
161  ## @param expression An another expression
162  ## @return If E is the expression, returns expression / E
163  # @ingroup operators
164  def __rdiv__(self, expression):
165  return BinOp(Operator.div, buildExpressionObj(expression), self)
166 
167  ## Support for Python version 3.x
168  ## @param expression An another expression
169  ## @return If E is the expression, returns E / expression
170  # @ingroup operators
171  def __truediv__(self, expression):
172  return BinOp(Operator.div, self, buildExpressionObj(expression))
173 
174  ## Support for Python version 3.x
175  ## @param expression An another expression
176  ## @return If E is the expression, returns expression / E
177  # @ingroup operators
178  def __rtruediv__(self, expression):
179  return BinOp(Operator.div, buildExpressionObj(expression), self)
180 
181  ## @param expression An another expression
182  ## @return If E is the expression, returns E % expression (modulo)
183  # @ingroup operators
184  def __mod__(self, expression):
185  return BinOp(Operator.modOp, self, buildExpressionObj(expression))
186 
187  ## @param expression An another expression
188  ## @return If E is the expression, returns E ^ expression
189  # @ingroup operators
190  def __pow__(self, expression):
191  return BinOp(Operator.power, self, buildExpressionObj(expression))
192 
193  ## @param expression An another expression
194  ## @return If E is the expression, returns expression ^ E
195  # @ingroup operators
196  def __rpow__(self, expression):
197  return BinOp(Operator.power, buildExpressionObj(expression), self)
198 
199  ## @param expression An another expression
200  ## @return If E is the expression, returns E and expression
201  # @ingroup operators
202  def __and__(self, expression):
203  return BinOp(Operator.andOp, self, buildExpressionObj(expression))
204 
205  ## @param expression An another expression
206  ## @return If E is the expression, returns E or expression
207  # @ingroup operators
208  def __or__(self, expression):
209  return BinOp(Operator.orOp, self, buildExpressionObj(expression))
210 
211  ## @param expression An another expression
212  ## @return If E is the expression, returns E == expression
213  # @ingroup operators
214  def __eq__(self, expression):
215  return BinOp(Operator.equal, self, buildExpressionObj(expression))
216 
217  ## @param expression An another expression
218  ## @return If E is the expression, returns E != expression
219  # @ingroup operators
220  def __ne__(self, expression):
221  return BinOp(Operator.notEqual, self, buildExpressionObj(expression))
222 
223  ## @param expression An another expression
224  ## @return If E is the expression, returns E <= expression
225  # @ingroup operators
226  def __le__(self, expression):
227  return BinOp(Operator.lessEq, self, buildExpressionObj(expression))
228 
229  ## @param expression An another expression
230  ## @return If E is the expression, returns E >= expression
231  # @ingroup operators
232  def __ge__(self, expression):
233  return BinOp(Operator.greaterEq, self, buildExpressionObj(expression))
234 
235  ## @param expression An another expression
236  ## @return If E is the expression, returns E < expression
237  # @ingroup operators
238  def __lt__(self, expression):
239  return BinOp(Operator.less, self, buildExpressionObj(expression))
240 
241  ## @param expression An another expression
242  ## @return If E is the expression, returns E > expression
243  # @ingroup operators
244  def __gt__(self, expression):
245  return BinOp(Operator.greater, self, buildExpressionObj(expression))
246 
247 
248 ## @brief Class wrapping an integer or a float value
250  ## @param number integer or float
251  # @ingroup expressions
252  def __init__(self,number):
253  self.number = number
254  self.operatorIndex = Operator.operatorIndexDic[Operator.num]
255 
256  def getExpression(self):
257  return "(" + str(self.number) + ")"
258 
259  def getID(self):
260  return str(self.operatorIndex)+"-"+str(self.number)
261 
262 ## @brief Class representing the variables defined in the data file.
263 # @ingroup expressions
264 # @details Most
265 # users will not need it. Biogeme automatically invokes this
266 # expression for all headers in the data file.
267 # Example:
268 # @code
269 # x = Variable('x')
270 # @endcode
272  ## @param name name of the variable
273  def __init__(self,name):
274  self.name = name
275  self.operatorIndex = Operator.operatorIndexDic[Operator.var]
276 
277  def getExpression(self):
278  return str(self.name)
279 
280  def getID(self):
281  return str(self.operatorIndex)+"-"+str(self.name)
282 
283 ## @brief Class representing a random variable for numerical
284 # integration.
285 # @ingroup expressions
286 # @details Typically used for integrals. Note that nothing is
287 # said here about the distribution of the random variable. Therefore,
288 # a density function will have to be specified.
289 # Example:
290 # @code
291 # omega = RandomVariable('omega')
292 # @endcode
294  ## @param name name of the random variable
295  def __init__(self,name):
296  self.name = name
297  self.operatorIndex = Operator.operatorIndexDic[Operator.rv]
298 
299  def getExpression(self):
300  return str(self.name)
301 
302 ## @brief Class representing the definition of a new variable.
303 # @ingroup expressions
304 # @details Defining a new
305 # variable is equivalent to add a column to the data file. Note that
306 # the expression defining the new variable is computed during the
307 # processing of the data file, before the estimation, so that it saves
308 # computational time to define variables using this technique.
309 # Example:
310 # @code
311 # TRAIN_TT_SCALED = DefineVariable('TRAIN_TT_SCALED', TRAIN_TT / 100.0)
312 # @endcode
313 # will result in a more efficient estimation than the statement:
314 # @code
315 # TRAIN_TT_SCALED = TRAIN_TT / 100.0
316 # @endcode
318  ## @param name name of the variable
319  # @param expression expression to compute the value of the variable
320  def __init__(self,name,expression):
321  self.name = name
322  self.expression = buildExpressionObj(expression)
323  self.operatorIndex = Operator.operatorIndexDic[Operator.userexpr]
324 
325  def getExpression(self):
326  return self.name + self.expression.getExpression()
327 
328 ## @brief Class representing the definition of a new type of draws.
329 # @ingroup expressions
330 # @details The expression defining the draws is computed during the
331 # processing of the data file, before the estimation, so that it may save
332 # computational time to define draws using this technique.
334  ## @param name name of the draws
335  # @param expression expression to compute the value of the variable
336  def __init__(self,name,expression, iteratorName):
337  self.name = name
338  self.expression = buildExpressionObj(expression)
339  self.iteratorName = iteratorName
340  self.operatorIndex = Operator.operatorIndexDic[Operator.userdraws]
341 
342  def getExpression(self):
343  return self.name + self.expression.getExpression()
344 
345  def getID(self):
346  return str(self.operatorIndex) + "-" + self.getExpression()
347 
348 
349 ## @brief Class representing a parameter to be estimated.
350 # @ingroup expressions
351 # @details It is highly recommended to use the same name as an argument as the
352 # name of the python variable on the left of the equal sign. Indeed,
353 # Biogeme has no access to the name of the python variable, and the report
354 # will use only the name provided as an argument.
355 # Example:
356 # @code
357 # beta = Beta( 'beta', 0.0, -10000, 10000, 0)
358 # @endcode
360  ## @param name name of the parameter
361  # @param value starting value of the parameter
362  # @param lowerbound minimum value that the parameter can take
363  # @param upperbound maximum value that the parameter can take
364  # @param status 0 if the parameter must be estimated, 1 if the starting value is maintained
365  # @param desc text used in the LaTeX output file (optional, default value:'' [empty string])
366  def __init__(self,name,value,lowerbound,upperbound,status,desc=''):
367  self.name = name
368  self.val = value
369  self.lb = lowerbound
370  self.ub = upperbound
371  self.st = status
372  self.desc = desc
373  self.operatorIndex = Operator.operatorIndexDic[Operator.param]
374 
375  def getExpression(self):
376  #return str(self.name)
377  return self.name + " " + str(self.val) + " " + str(self.lb) + \
378  " " + str(self.ub) + " " + str(self.st) + " " + self.desc
379 
380  def getID(self):
381  return str(self.operatorIndex) + "-" + self.getExpression()
382 
383 
384 
385 
386 ## @brief Class representing a random variable for integration using
387 # Monte Carlo simulation.
388 # @ingroup expressions
390 
391  ## @param name name of the draws
392  def __init__(self,name):
393  print("**** DRAWS", name," ",Operator.mcdraws)
394  self.name = name
395  self.operatorIndex = Operator.operatorIndexDic[Operator.mcdraws]
396 
397  def getExpression(self):
398  return str(self.name)
399 
400  def getID(self):
401  return str(self.operatorIndex)+"-Draw"+self.getExpression()
402 
403 
404 
405 
406 ## @brief Class representing the uniform draw of a random variable used for integration using Monte Carlo simulation.
407 # @ingroup expressions
409 
410  ## @param name name of the draws
411  def __init__(self,name):
412  print("**** RECYCLED DRAWS", name," ",Operator.mcunifdraws)
413  self.name = name
414  self.operatorIndex = Operator.operatorIndexDic[Operator.mcunifdraws]
415  print("Id: ", self.getID())
416 
417  def getExpression(self):
418  return "Unif("+str(self.name)+")"
419 
420  def getID(self):
421  return str(self.operatorIndex)+"-Unif"+self.getExpression()
422 
423 
424 ## @brief Class representing a normally distributed random variable for
425 # simulated integration.
426 # @ingroup expressions
427 # @details A different set of draws will be generated
428 # for each group in the data file. By default, the groups are
429 # identified by __rowId__, and a set of draws is
430 # generated for each row in the sample. Another typical case
431 # corresponds to panel data, where several rows correspond to the
432 # same individual. If Id identifies individuals in the data set, a
433 # set of draws will be generated for each individual, and not for
434 # each observation. Example:
435 # @code
436 # Errorcomp = bioNormalDraws('Errorcomp','Id')
437 # @endcode
439 
440  ## @param name name of the random variable
441  # @param index name of the identifier of groups of data associated
442  # with a different set of draws. (optional, default='__rowId__')
443  def __init__(self,name,index='__rowId__'):
444  msg = 'Deprecated syntax: bioNormalDraws(\''+name+'\'). Use bioDraws(\''+name+'\') and BIOGEME_OBJECT.DRAWS = { \''+name+'\': \'NORMAL\' }'
445 
446  raise SyntaxError(msg)
447 
448 
449 ## @brief Class representing a uniformly distributed random variable
450 # on [-1,1] for simulated integration.
451 # @ingroup expressions
452 # @details A different set of draws will be generated
453 # for each group in the data file. By default, the groups are
454 # identified by __rowId__, and a set of draws is
455 # generated for each row in the sample. Another typical case
456 # corresponds to panel data, where several rows correspond to the
457 # same individual. If Id identifies individuals in the data set, a
458 # set of draws will be generated for each individual, and not for
459 # each observation. Example:
460 # @code
461 # Errorcomp = bioUniformSymmetricDraws('Errorcomp','Id')
462 # @endcode
464 
465  ## @param name name of the random variable
466  # @param index name of the identifier of groups of data associated
467  # with a different set of draws. (optional, default='__rowId__')
468  def __init__(self,name,index='__rowId__'):
469  msg = 'Deprecated syntax: bioUniformSymmetricDraws(\''+name+'\'). Use bioDraws(\''+name+'\') and BIOGEME_OBJECT.DRAWS = { \''+name+'\': \'UNIFORMSYM\' }'
470 
471  raise SyntaxError(msg)
472 
473 
474 ## @brief Class representing a uniformly distributed random variable
475 # on [0,1] for simulated integration.
476 # @ingroup expressions
477 # @details A different set of draws will be generated
478 # for each group in the data file. By default, the groups are
479 # identified by __rowId__, and a set of draws is
480 # generated for each row in the sample. Another typical case
481 # corresponds to panel data, where several rows correspond to the
482 # same individual. If Id identifies individuals in the data set, a
483 # set of draws will be generated for each individual, and not for
484 # each observation. Example:
485 # @code
486 # Errorcomp = bioUniformDraws('Errorcomp','Id')
487 # @endcode
489 
490  ## @param name name of the random variable
491  # @param index name of the identifier of groups of data associated
492  # with a different set of draws. (optional, default='__rowId__')
493  def __init__(self,name,index='__rowId__'):
494  msg = 'Deprecated syntax: bioUniformDraws(\''+name+'\'). Use bioDraws(\''+name+'\') and BIOGEME_OBJECT.DRAWS = { \''+name+'\': \'UNIFORM\' }'
495 
496  raise SyntaxError(msg)
497 ## @brief Generic class for unary operators
499  ## @param op Object of type Operator
500  ## @param expression any valid bio_expression
501  def __init__(self,op,expression):
502  self.op = op
503  self.expression = buildExpressionObj(expression)
504  self.operatorIndex = Operator.operatorIndexDic[op]
505 
506  def getExpression(self):
507  return self.op + "(" + self.expression.getExpression() + ")"
508 
509 
510 
511 ## @brief Class representing the expression for absolute value
512 # @ingroup expressions
513 # @details It is not a differentiable operator. If the expression
514 # contains parameters to be estimated, Biogeme will complain.
515 # Example:
516 # @code
517 # y = abs(2*x-1)
518 # @endcode
520  ## @param expression any valid bio_expression
521  def __init__(self,expression):
522  self.expression = buildExpressionObj(expression)
523  self.operatorIndex = Operator.operatorIndexDic[Operator.absOp]
524 
525  def getExpression(self):
526  return Operator.absOp + "(" + self.expression.getExpression() + ")"
527 
528 
529 ## @brief Class representing the expression for exponential
530 # @ingroup expressions
531 # @details Roughly speaking, floating point arithmetic allows to represent positive real numbers between \f$10^{-307}\f$ and \f$10^{+308}\f$, which corresponds to a range between \f$e^{-707}\f$ and \f$e^{709}\f$. Make sure that the value of the expression of exp does not lie outside the range [-707,709].
532 # Example:
533 # @code
534 # P = exp(V1) / (exp(V1) + exp(V2))
535 # @endcode
537  ## @param expression any valid bio_expression
538  def __init__(self,expression):
539  self.expression = buildExpressionObj(expression)
540  self.operatorIndex = Operator.operatorIndexDic[Operator.exp]
541 
542  def getExpression(self):
543  return Operator.exp + "(" + self.expression.getExpression() + ")"
544 
545  def getID(self):
546  return str(self.operatorIndex) + "-" + self.getExpression()
547 
548 
549 ## @brief Class representing the expression for natural logarithm.
550 # @ingroup expressions
551 ## @details It is the natural logarithm (base e), so that \f$y=\log(x)\f$ means that \f$x=e^y\f$. To compute a logarithm in another base \f$b \neq 1\f$, use the formula \f[ \log_b(x) = \log(x) / \log(b) \f].
553  ## @param expression any valid bio_expression
554  def __init__(self,expression):
555  self.expression = buildExpressionObj(expression)
556  self.operatorIndex = Operator.operatorIndexDic[Operator.log]
557 
558  def getExpression(self):
559  return Operator.log + "(" + self.expression.getExpression() + ")"
560 
561  def getID(self):
562  return str(self.operatorIndex) + "-" + self.getExpression()
563 
564 ## @brief Class representing the cumulative distribution function of
565 # the normal distribution
566 # @ingroup expressions
567 # @details The CDF of the normal distribution is
568 # \f[
569 # \mbox{bioNormalCdf}(x) = \frac{1}{\sqrt{2\pi}}\int_{-\infty}^x \exp\left(\frac{-t^2}{2}\right) dt
570 # \f]
571 #A typical example is the probability of a binary probit model, which is computed as follows:
572 # @code
573 # prob = normalCdf(V1-V2)
574 # @endcode
576  ## @param expression any valid bio_expression
577  def __init__(self,expression):
578  self.expression = buildExpressionObj(expression)
579  self.operatorIndex = Operator.operatorIndexDic[Operator.bioNormalCdf]
580 
581  def getExpression(self):
582  return Operator.normalCdf + "(" + self.expression.getExpression() + ")"
583 
584 ## @brief Class representing the expression for the maximum of two expressions.
585 # @ingroup expressions
586 # @details Note that this operator is not differentiable. If one of
587 # the two expressions contains parameters to be estimated, Biogeme
588 # will complain. Example: @code max(x,0) @endcode
590  ## @param left any valid bio_expression
591  ## @param right any valid bio_expression
592  def __init__(self,left,right):
593  self.left = buildExpressionObj(left)
594  self.right = buildExpressionObj(right)
595  self.operatorIndex = Operator.operatorIndexDic[Operator.maxOp]
596 
597  def getExpression(self):
598  return "max(" + self.left.getExpression() + "," + self.right.getExpression() + ")"
599 
600 ## @brief Class representing the expression for the minimum of two expressions.
601 # @ingroup expressions
602 # @details Example:
603 # @code
604 # max(x,0)
605 # @endcode
607  def __init__(self,left,right):
608  self.left = buildExpressionObj(left)
609  self.right = buildExpressionObj(right)
610  self.operatorIndex = Operator.operatorIndexDic[Operator.minOp]
611 
612  def getExpression(self):
613  return "min(" + self.left.getExpression() + "," + self.right.getExpression() + ")"
614 
615 ## @brief Generic class for binary operators
617  ## @param op Object of type Operator
618  ## @param left any valid bio_expression
619  ## @param right any valid bio_expression
620  def __init__(self,op,left,right):
621  self.op = op
622  self.left = buildExpressionObj(left)
623  self.right = buildExpressionObj(right)
624  self.operatorIndex = Operator.operatorIndexDic[op]
625 
626  def getExpression(self):
627  return "(" + self.left.getExpression() + self.op + self.right.getExpression() + ")"
628 
629  def getID(self):
630  return str(self.operatorIndex) + "-" + self.getExpression()
631 
632 ## @brief Class representing the Monte Carlo integration of an expression
633 # @ingroup expressions
635  ## @param term any valid bio_expression
636  def __init__(self, expression) :
637  self.expression = buildExpressionObj(expression)
638  self.operatorIndex = Operator.operatorIndexDic[Operator.monteCarloOp]
639 
640  def getExpression(self) :
641  strexpr = "MonteCarlo"
642  strexpr += "(" + self.expression.getExpression() + ")"
643  return strexpr
644 
645 ## @brief Class representing the Monte Carlo integration of an
646 ## expression, using a control variate method to decrease the
647 ## variance. The analytical result of the simulation of the second
648 ## argument should be equal to the third.
649 # @ingroup expressions
651  ## @param term any valid bio_expression
652  def __init__(self, expression, integrand,integral) :
653  self.expression = buildExpressionObj(expression)
654  self.integrand = buildExpressionObj(integrand)
655  self.integral = buildExpressionObj(integral)
656  self.operatorIndex = Operator.operatorIndexDic[Operator.monteCarloCVOp]
657 
658  def getExpression(self) :
659  strexpr = "MonteCarloControlVariate"
660  strexpr += "(" + self.function.getExpression() + ")"
661  return strexpr
662 
663 ## @brief Class representing the sum of the same expression applied to a list of data.
664 # @ingroup expressions
665 # @details The concept of iterators identifies a sequence such that,
666 # for each instance, the value of the variables is read from the data
667 # file, and an expression can be evaluated. The two expressions
668 # described in this section consider one iterator and one expression,
669 # and evaluate the expression for each instance defined by the
670 # iterator. A sum can then be computed. Example:
671 # @code
672 # prob = bioLogit(V,av,CHOICE)
673 # rowIterator('obsIter')
674 # loglikelihood = Sum(log(prob),'obsIter')
675 # @endcode
676 class Sum(Expression) :
677  ## @param term any valid bio_expression
678  ## @param iteratorName name of an iterator already defined
679  def __init__(self, term, iteratorName) :
680  self.function = buildExpressionObj(term)
681  self.iteratorName = iteratorName
682  self.operatorIndex = Operator.operatorIndexDic[Operator.sumOp]
683 
684  def getExpression(self) :
685  strexpr = "sum"
686  strexpr += "[" + str(self.iteratorName) + "]"
687  strexpr += "(" + self.function.getExpression() + ")"
688  return strexpr
689 
690 
691 
692 
693 
694 ## @brief Class representing the product of the same expression applied to a list of data.
695 # @ingroup expressions
696 # @details The concept of iterators identifies a sequence such that,
697 # for each instance, the value of the variables is read from the data
698 # file, and an expression can be evaluated. The two expressions
699 # described in this section consider one iterator and one expression,
700 # and evaluate the expression for each instance defined by the
701 # iterator. A product can then be computed. The following example computes the loglikelihood for a model with panel data.
702 # @code
703 # metaIterator('personIter','__dataFile__','panelObsIter','Id')
704 # rowIterator('panelObsIter','personIter')
705 #
706 # condProbIndiv = Prod(prob,'panelObsIter')
707 # probIndiv = MonteCarlo(condProbIndiv)
708 # loglikelihood = Sum(log(probIndiv),'personIter')
709 # @endcode
710 # The iterator personIter iterates on each individual in the file,
711 # characterized by the identifier Id. The iterator panelObsIter
712 # iterates on the observations (that is, the rows in the data file)
713 # associated with the current individual.
714 #
715 # Assuming that prob is the likelihood of the observation in one raw,
716 # for a given set of draws, the following quantities are computed:
717 # - The conditional probability of the sequence of observations for
718 # the current individual n:
719 #
720 # \f[ \mbox{condProbIndiv} = P(y_1,\ldots,y_T|\xi_n) = \prod_t P(y_t|\xi_n)\f]
721 #
722 # - The unconditional probability of the sequence of observations for the
723 # current individual n:
724 # \f[
725 # \mbox{probIndiv} = \int_{\xi_n}P(y_1,\ldots,y_T|\xi_n) \approx \sum_r P(y_1,\ldots,y_T|\xi_r) / R
726 # \f]
727 #where \f$\xi_r\f$ are the R draws generated from \f$\xi_n\f$.
728 #
729 # - The loglikelihood for all individuals in the sample:
730 # \f[
731 # \mbox{loglikelihood} = \sum_n \log(\sum_r P(y_1,\ldots,y_T|\xi_r) / R)
732 # \f]
733 class Prod(Expression) :
734  ## @param term any valid bio_expression
735  ## @param iteratorName name of an iterator already defined
736  ## @param positive Set it to True if all factors of the product are
737  ## strictly positive. In that case, it will be computed as \f[
738  ## \prod_r x_r = \exp(\sum_r \ln x_r)\f]
739  def __init__(self, term, iteratorName,positive=False) :
740  self.function = buildExpressionObj(term)
741  self.iteratorName = iteratorName
742  self.positive = positive
743  self.operatorIndex = Operator.operatorIndexDic[Operator.prodOp]
744 
745  def getExpression(self) :
746  strexpr = "prod"
747  strexpr += "[" + str(self.iteratorName) + "]"
748  strexpr += "(" + self.function.getExpression() + ")"
749  return strexpr
750 
751 ## @brief Class performing numerical integration relying on the <a
752 ## href='http://en.wikipedia.org/wiki/Gaussian_quadrature'
753 ## target='_blank'>Gauss-Hermite quadrature</a> to compute
754 ## \f[
755 ## \int_{-\infty}^{+\infty} f(\omega) d\omega.
756 ## \f]
757 # @ingroup expressions
758 # @details As an example, the computation of a normal mixture of logit
759 # models is performed using the following syntax, where condprob is
760 # the conditional (logit) choice probability:
761 # @code
762 # omega = RandomVariable('omega')
763 # density = bioNormalPdf(omega)
764 # result = Integrate(condprob * density,'omega')
765 # @endcode
766 # Comments:
767 # - The Gauss-Hermite procedure is designed to compute integrals of the form
768 # \f[
769 # \int_{-\infty}^{+\infty} e^{-\omega^2} f(\omega) d\omega.
770 # \f]
771 # Therefore, Biogeme multiplies the expression by \f$e^{\omega^2}\f$ before applying the Gauss-Hermite algorithm. This is transparent for the user.
772 #
773 # - It is usually more accurate to compute an integral using a
774 # quadrature procedure. However, it should be used only in the
775 # presence of few (one or two) random variables. The same integral can
776 # be computed using Monte-Carlo integration using the following
777 # syntax:
778 # @code
779 # BIOGEME_OBJECT.DRAWS = { 'omega': 'NORMAL'}
780 # omega = bioDraws('omega')
781 # result = MonteCarlo(condprob)
782 #@endcode
784  ## @param term any valid bio_expression representing the expression to integrate
785  ## @param v name of the integration variable, previously defined using a bioExpression::RandomVariable statement.
786  def __init__(self, term,v):
787  self.function = buildExpressionObj(term)
788  self.variable = v
789  self.operatorIndex = Operator.operatorIndexDic[Operator.integralOp]
790 
791  def getExpression(self) :
792  strexpr = "Integral"
793  strexpr += "(" + self.function.getExpression() + "," + variable + ")"
794  return strexpr
795 
796 ## @brief Class generating the analytical derivative of an expression.
797 # @ingroup expressions
798 # @details This class generates the expression for
799 # \f[
800 # \frac{\partial f(x)}{\partial x}
801 # \f]
802 # The computation of derivatives is usually not necessary for
803 # estimation, as Biogeme automatically generates the analytical
804 # derivatives of the log likelihood function. It is particularly
805 # usuful for simulation, to compute the elasticities of complex
806 # models.
807 # Example:
808 # The computation of the elasticity of a model prob with respect to
809 # the variable TRAIN_TT, say, is obtained as follows, whatever the
810 # model defined by prob:
811 # @code
812 # elasticity = Derive(prob,'TRAIN_TT') * TRAIN_TT / prob
813 # @endcode
815  ## @param term any valid bio_expression to derive
816  ## @param v the variable
817  def __init__(self, term,v):
818  self.function = buildExpressionObj(term)
819  self.variable = v
820  self.operatorIndex = Operator.operatorIndexDic[Operator.derivativeOp]
821 
822  def getExpression(self) :
823  strexpr = "Derive"
824  strexpr += "(" + self.function.getExpression() + "," + variable + ")"
825  return strexpr
826 
827 ## @brief Class representing the probability density function of a
828 # standardized normally distributed random variable
829 # @ingroup expressions
830 # @details The pdf of the normal distribution is
831 # \f[ \mbox{bioNormalPdf}(x) = \frac{1}{\sqrt{2\pi}}e^{-t^2/2}. \f]
832 # The computation of a normal mixture of logit models is performed
833 # using the following syntax, where condprob is the conditional
834 # (logit) choice probability:
835 # @code
836 # omega = RandomVariable('omega')
837 # density = bioNormalPdf(omega)
838 # result = Integrate(condprob * density,'omega')
839 # @endcode
841  ## @param term an expression providing the value of the argument of the pdf
842  def __init__(self, term):
843  self.function = buildExpressionObj(term)
844  self.operatorIndex = Operator.operatorIndexDic[Operator.bioNormalPdf]
845 
846  def getExpression(self) :
847  strexpr = "normalPdf"
848  strexpr += "(" + self.function.getExpression() + ")"
849  return strexpr
850 
851 ## @brief Class extracting an expression from a dictionary.
852 # @ingroup expressions
853 # @details A typical example consists in returning the probability of a chosen alternative in a choice model. Consider the following dictionary:
854 # @code
855 # P = { 1: exp(V1) / (exp(V1)+exp(V2)+exp(V3)),
856 # 2: exp(V2) / (exp(V1)+exp(V2)+exp(V3)),
857 # 3: exp(V3) / (exp(V1)+exp(V2)+exp(V3))}
858 # @endcode
859 # and assume that the variable Choice in the data file contains the
860 # identifier of the chosen alternative of the corresponding
861 # observation, that is 1, 2 or 3. Then, the probability of the chosen
862 # alternative is given by
863 #@code
864 # chosenProba = Elem(P,Choice)
865 #@endcode
866 # If the result of "Choice" does not correspond to any valid entry in the
867 # dictionary, a warning is issued and the value of the default expression
868 # is returned. The warning is issued because this situation is usually
869 # not wanted by the user. To turn off the warning, set the parameter
870 # warnsForIllegalElements to 0.
871 class Elem(Expression) :
872  ## @param dictionary A dictionary (see <a href='http://docs.python.org/py3k/tutorial/datastructures.html' target='_blank'>Python documentation</a>) such
873  ## that the indices are numerical values that can match the result
874  ## of an expression
875  ## @param key expression identifying the entry in the dictionary
876  ## @default If the result of key does not correspond to any
877  ## valid entry in the dictionary, the value of the default expression
878  ## is returned. This argument is optional. If omitted, the default
879  ## value is 0.
880  def __init__(self, dictionary, key, default = Numeric(0)) :
881  self.prob = {} # dictionary
882  for k,v in dictionary.items() :
883  self.prob[k] = buildExpressionObj(v)
884 
885  self.choice = buildExpressionObj(key)
886  self.default = buildExpressionObj(default)
887  self.operatorIndex = Operator.operatorIndexDic[Operator.elemOp]
888 
889  def getExpression(self) :
890  res = "Elem"
891  res += "[" + str(self.choice) + "]"
892  res += "{"
893  for i,v in self.prob.items():
894  res += "(" + str(i) + ": " + str(v) + ")"
895  res += "}"
896  return res
897 
898  def getID(self):
899  return str(self.operatorIndex) + "-" + self.getExpression()
900 
901 
902 ## @brief Class calculating a logit choice probability
903 # @ingroup expressions
904 # @details Computes the probability given by the logit model, that is
905 # \f[
906 # \frac{a_i e^{V_i}}{\sum_{j=1}^{J} a_j e^{V_j}}
907 # \f]
908 # Example:
909 # @code
910 # V = {1: V1, 2: V2, 3: V3}
911 # av = {1: av_1, 2: 1, 3: av_3}
912 # prob = bioLogit(V,av,CHOICE)
913 # @endcode
915  ## @param util dictionary (see <a
916  ## href="http://docs.python.org/py3k/tutorial/datastructures.html"
917  ## target="_blank">Python documentation</a>) containing the utility
918  ## functions \f$V_i\f$.
919  ## @param av dictionary (see <a
920  ## href="http://docs.python.org/py3k/tutorial/datastructures.html"
921  ## target="_blank">Python documentation</a>) containing the
922  ## availability conditions for each alternative \f$a_i\f$ (if 0,
923  ## alternative is not available, if different from zero, it is
924  ## available). The number of entries and the labeling must be
925  ## consistent with utilities.
926  ## @param choice expression providing the index of the alternative
927  ## for which the probability is being computed.
928  def __init__(self, util, av, choice) :
929  self.prob = {} # dictionary
930  for k,v in util.items() :
931  self.prob[k] = buildExpressionObj(v)
932  self.av = {}
933  for k,v in av.items() :
934  self.av[k] = buildExpressionObj(v)
935  self.choice = buildExpressionObj(choice)
936  self.operatorIndex = Operator.operatorIndexDic[Operator.logitOp]
937 
938  def getExpression(self) :
939  res = "Logit"
940  res += "[" + str(self.choice) + "]"
941  res += "{"
942  for i,v in self.prob.items():
943  res += "(" + str(i) + ": " + str(v) + ")"
944  res += "}"
945  res += "{"
946  for i,v in self.av.items():
947  res += "(" + str(i) + ": " + str(v) + ")"
948  res += "}"
949  return res
950 
951 ## @brief Class calculating the log of a logit choice probability
952 # @ingroup expressions
953 # @details Computes the log of the probability given by the logit model, that is
954 # \f[
955 # V_i - \log\left(\sum_{j=1}^{J} a_j e^{V_j}\right)
956 # \f]
957 # Example:
958 # @code
959 # V = {1: V1, 2: V2, 3: V3}
960 # av = {1: av_1, 2: 1, 3: av_3}
961 # logprob = bioLogLogit(V,av,CHOICE)
962 # @endcode
964  ## @param util dictionary (see <a
965  ## href="http://docs.python.org/py3k/tutorial/datastructures.html"
966  ## target="_blank">Python documentation</a>) containing the utility
967  ## functions \f$V_i\f$.
968  ## @param av dictionary (see <a
969  ## href="http://docs.python.org/py3k/tutorial/datastructures.html"
970  ## target="_blank">Python documentation</a>) containing the
971  ## availability conditions for each alternative \f$a_i\f$ (if 0,
972  ## alternative is not available, if different from zero, it is
973  ## available). The number of entries and the labeling must be
974  ## consistent with utilities.
975  ## @param choice expression providing the index of the alternative
976  ## for which the probability is being computed.
977  def __init__(self, util, av, choice) :
978  self.prob = {} # dictionary
979  for k,v in util.items() :
980  self.prob[k] = buildExpressionObj(v)
981  self.av = {}
982  for k,v in av.items() :
983  self.av[k] = buildExpressionObj(v)
984 
985  self.choice = buildExpressionObj(choice)
986  self.operatorIndex = Operator.operatorIndexDic[Operator.loglogitOp]
987 
988  def getExpression(self) :
989  res = "LogLogit"
990  res += "[" + str(self.choice) + "]"
991  res += "{"
992  for i,v in self.prob.items():
993  res += "(" + str(i) + ": " + str(v) + ")"
994  res += "}"
995  res += "{"
996  for i,v in self.av.items():
997  res += "(" + str(i) + ": " + str(v) + ")"
998  res += "}"
999  return res
1000 
1001 
1002 
1003 ## @brief Class computing the sum of multiple expressions
1004 # @ingroup expressions
1005 # @details Given a list of expressions \f$V_i\$, $i=1,\ldots,n$, it computes
1006 # \f[ \sum_{i=1}^n V_i \f]. Example:
1007 # @code
1008 # V = {1: V1, 2: V2, 3: V3}
1009 #
1010 # @endcode
1012 
1013  def __init__(self, terms) :
1014  if type(terms).__name__ == 'list':
1015  self.type = 1
1016  self.terms = [] ;
1017  for k in terms :
1018  self.terms.append(buildExpressionObj(k))
1019  elif type(terms).__name__ == 'dict':
1020  self.type = 2
1021  self.terms = {} ;
1022  for k,v in terms.items() :
1023  self.terms[k] = buildExpressionObj(v)
1024  else:
1025  self.type = -1
1026  self.operatorIndex = Operator.operatorIndexDic[Operator.multSumOp]
1027 
1028  def getExpression(self) :
1029  res = "bioMultSum"
1030  res += "("
1031  if self.type == 2:
1032  for i,v in self.terms.items():
1033  res += v.getExpression() + ","
1034 
1035  if self.type ==1:
1036  for k in self.terms:
1037  res += k.getExpression() + ","
1038 
1039  #remove last coma
1040  res = res[:-1] + ")"
1041  return res
1042 
1043  def getID(self):
1044  return str(self.operatorIndex)+"-"+self.getExpression()
1045 
1046 
1047 ## @brief Class performing a sample enumeration
1048 # @ingroup expressions
1049 # @details The concept of iterators (see the section "Iterators"),
1050 # identifies a sequence such that, for each instance, the value of the
1051 # variables is read from the data file, and an expression can be
1052 # evaluated. In sample enumeration, expressions are computed for each
1053 # instance in the sample and reported in a file.
1054 # Example:
1055 # @code
1056 # simulate = {'Prob. 1': P1, 'Prob. 2': P2, 'Util. 1': V1, 'Util. 2':V2, 'Diff. util.': V1-V2}
1057 # rowIterator('obsIter')
1058 # BIOGEME_OBJECT.SIMULATE = Enumerate(simulate,'obsIter')
1059 # @endcode
1060 # Note that this expression is used exclusively for
1061 # simulation. Contrarily to all other expressions, it does not return
1062 # any value and, consequently, cannot be included in another
1063 # expression. Something like @code X + Enumerate(V,'obsIter') / 2 @endcode does not make any sense.
1064 
1066  ## @param term a dictionary (see <a href="http://docs.python.org/py3k/tutorial/datastructures.html" target="_blank">Python documentation</a>)) of the form
1067  ## @code
1068  ## {label: expression, label: expression,...}
1069  ## @endcode
1070  ## where label is used to describe the results in the output file, and
1071  ## expression is a valid expression.
1072  ## @param iteratorName name of an iterator already defined.
1073  def __init__(self, term, iteratorName) :
1074  self.theDict = {}
1075  for k,v in term.items():
1076  self.theDict[k] = buildExpressionObj(v)
1077  self.iteratorName = iteratorName
1078  self.operatorIndex = Operator.operatorIndexDic[Operator.enumOp]
1079 
1080  def getExpression(self) :
1081  strexpr = "Enumerate"
1082  strexpr += "[" + str(self.iteratorName) + "]"
1083  strexpr += "{"
1084  for i,v in self.term.items():
1085  strexpr += "(" + str(i) + ": " + str(v) + ")"
1086  strexpr += "}"
1087  return strexpr
1088 
1089 ## @brief Class performing draws from the posterior of the mean of a
1090 ## normal variable knowing realizations and variance. See Train (2003)
1091 ## p. 304 step 1.
1092 # @details Let \f$\beta_n\f$, \f$n=1,\ldots,N\f$ be realizations from a
1093 # multivariate normal distribution \f$N(b,W)\f$. This class draws from
1094 # the posterior of \f$b\f$, that is from \f[ N(\bar{\beta},W/N) \f].
1096  def __init__(self, mean, realizations, varcovar):
1097  self.error = None
1098  if type(mean).__name__ == 'list':
1099  self.mean = [] ;
1100  for k in mean :
1101  self.mean.append(buildExpressionObj(k))
1102  else:
1103  self.error = "Syntax error: the first argument of bioBayesNormalDraw must be a list of expressions. Syntax: [B_TIME, B_COST]. " ;
1104 
1105  if type(realizations).__name__ == 'list':
1106  self.realizations = [] ;
1107  for k in realizations :
1108  self.realizations.append(buildExpressionObj(k))
1109  else:
1110  self.error = "Syntax error: the second argument of bioBayesNormalDraw must be a list of expressions. Syntax: [B_TIME_RND, B_COST_RND]"
1111  if type(varcovar).__name__ == 'list':
1112  self.varcovar = [] ;
1113  for k in varcovar :
1114  row = []
1115  if type(k).__name__ == 'list':
1116  for j in k:
1117  row.append(buildExpressionObj(k))
1118  self.varcovar.append(row)
1119  else:
1120  self.error = "Syntax error: the third argument of bioBayesNormalDraw must be a list of list of expressions. Syntax: [[ B_TIME_S , B_COVAR ] , [B_COVAR , B_COST_S]]." ;
1121 
1122 
1123  else:
1124  self.error = "Syntax error: the third argument of bioBayesNormalDraw must be a list of list of expressions. Syntax: [[ B_TIME_S , B_COVAR ] , [B_COVAR , B_COST_S]]."
1125  self.varcovar = varcovar
1126  self.operatorIndex = Operator.operatorIndexDic[Operator.bayesMeanOp]
1127 
1128 ## @brief Class performing draws from densities for Bayesian
1129 ## estimation using Metropolis-Hastings algorithm
1130 # @details Values of Beta parameters are drawn from a given density function using a Metropolis-Hastings algorithm.
1131 # Example:
1132 # @code
1133 # BETA = {ASC_CAR, ASC_TRAIN, B_TIME, B_COST}
1134 # prob = bioLogit(V,av,CHOICE)
1135 # rowIterator('obsIter')
1136 # likelihood = Prod(prob,'obsIter')
1137 # BIOGEME_OBJECT.BAYESIAN = MH(BETA,likelihood)
1138 # @endcode
1139 class MH(Expression) :
1140  ## @param beta a list of the form
1141  ## @code
1142  ## {beta1, beta2,...}
1143  ## @endcode
1144  ## where beta1, beta2, etc. are defined by the Beta expression.
1145  ## @param density valid expression representing the density to draw from.
1146 
1147  ## @param warmup number of steps of the Markov chain to perform to
1148  ## reach stationarity.
1149  ## @param steps number of steps to skip between two draws.
1150  def __init__(self, beta, density, warmup, steps) :
1151  if type(beta).__name__ == 'list':
1152  self.type = 1
1153  self.beta = [] ;
1154  for k in beta :
1155  self.beta.append(buildExpressionObj(k))
1156  elif type(beta).__name__ == 'dict':
1157  self.type = 2
1158  self.beta = {} ;
1159  for k,v in beta.items() :
1160  self.beta[k] = buildExpressionObj(v)
1161  else:
1162  self.type = -1
1163  self.density = density
1164  self.warmup = warmup
1165  self.steps = steps
1166  self.operatorIndex = Operator.operatorIndexDic[Operator.mhOp]
1167 
1168 
1169 #class Define(Expression) :
1170 # def __init__(self, name, expr, classname=None):
1171 # self.name = name
1172 # self.expr = expr
1173 # self.operatorIndex = Operator.operatorIndexDic[Operator.defineOp]
1174 #
1175 # def getExpression(self):
1176 # return str(self.name)
1177 #
1178 # def assign(self, expr) :
1179 # self.expr = expr
1180 
1181 
1182 
Class representing the expression for natural logarithm.
Class representing the product of the same expression applied to a list of data.
def __init__(self, beta, density, warmup, steps)
def __init__(self, op, left, right)
def __eq__(self, expression)
Class representing the definition of a new variable.
Class calculating a logit choice probability.
Class performing numerical integration relying on the Gauss-Hermite quadrature to compute ...
def __truediv__(self, expression)
Support for Python version 3.x.
Class representing the variables defined in the data file.
def __radd__(self, expression)
Class representing a normally distributed random variable for simulated integration.
def __pow__(self, expression)
Class representing the definition of a new type of draws.
def __init__(self, term, iteratorName, positive=False)
Generic class for binary operators.
def __rpow__(self, expression)
def __init__(self, expression)
def __init__(self, name, index='__rowId__')
Class generating the analytical derivative of an expression.
Class representing a uniformly distributed random variable on [0,1] for simulated integration...
Interface for mathematical expressions.
def __gt__(self, expression)
def __ge__(self, expression)
def __init__(self, name)
def __lt__(self, expression)
def __init__(self, expression)
Class computing the sum of multiple expressions.
def __rsub__(self, expression)
Class performing draws from densities for Bayesian estimation using Metropolis-Hastings algorithm...
def __init__(self, expression)
Class representing a random variable for integration using Monte Carlo simulation.
def __init__(self, term, v)
Class performing draws from the posterior of the mean of a normal variable knowing realizations and v...
Class representing the expression for the minimum of two expressions.
def __init__(self, left, right)
def __rdiv__(self, expression)
def __init__(self, expression, integrand, integral)
Class representing a parameter to be estimated.
Class wrapping an integer or a float value.
Generic class for an operator.
def __rmul__(self, expression)
Class representing the expression for the maximum of two expressions.
Class representing the cumulative distribution function of the normal distribution.
def __init__(self, term, iteratorName)
def __init__(self, term, v)
Class calculating the log of a logit choice probability.
Class representing the expression for exponential.
Class representing the expression for absolute value.
Class representing the uniform draw of a random variable used for integration using Monte Carlo simul...
def __init__(self, name, index='__rowId__')
def __init__(self, util, av, choice)
def __mod__(self, expression)
Class representing the probability density function of a standardized normally distributed random var...
def __init__(self, expression)
def __and__(self, expression)
def __init__(self, op, expression)
def __div__(self, expression)
def __rtruediv__(self, expression)
Support for Python version 3.x.
Class representing the sum of the same expression applied to a list of data.
def __init__(self, util, av, choice)
def __sub__(self, expression)
def __init__(self, name, value, lowerbound, upperbound, status, desc='')
Generic class for unary operators.
def __init__(self, dictionary, key, default=Numeric(0))
def __init__(self, expression)
def __init__(self, term, iteratorName)
def __init__(self, name, expression, iteratorName)
Class representing a random variable for numerical integration.
def __init__(self)
Constructor.
def __mul__(self, expression)
def __init__(self, name, index='__rowId__')
Class representing the Monte Carlo integration of an expression, using a control variate method to de...
def __init__(self, name)
Class performing a sample enumeration.
Class representing a uniformly distributed random variable on [-1,1] for simulated integration...
Class extracting an expression from a dictionary.
Class representing the Monte Carlo integration of an expression.
def __or__(self, expression)
def __init__(self, name, expression)
def __le__(self, expression)
def __init__(self, number)
def __add__(self, expression)
def __ne__(self, expression)
Copyright 2016 Michel Bierlaire