Package madgraph :: Package iolibs :: Module ufo_expression_parsers
[hide private]
[frames] | no frames]

Source Code for Module madgraph.iolibs.ufo_expression_parsers

   1  ################################################################################ 
   2  # 
   3  # Copyright (c) 2009 The MadGraph5_aMC@NLO Development team and Contributors 
   4  # 
   5  # This file is a part of the MadGraph5_aMC@NLO project, an application which  
   6  # automatically generates Feynman diagrams and matrix elements for arbitrary 
   7  # high-energy processes in the Standard Model and beyond. 
   8  # 
   9  # It is subject to the MadGraph5_aMC@NLO license which should accompany this  
  10  # distribution. 
  11  # 
  12  # For more information, visit madgraph.phys.ucl.ac.be and amcatnlo.web.cern.ch 
  13  # 
  14  ################################################################################ 
  15   
  16  """Parsers for algebraic expressions coming from UFO, outputting into 
  17  different languages/frameworks (Fortran and Pythia8). Uses the PLY 3.3 
  18  Lex + Yacc framework""" 
  19   
  20  import logging 
  21  import os 
  22  import re 
  23  import sys 
  24  import copy 
  25   
  26  root_path = os.path.split(os.path.dirname(os.path.realpath( __file__ )))[0] 
  27  sys.path.append(os.path.join(root_path, os.path.pardir)) 
  28   
  29  import madgraph.various.misc as misc 
  30   
  31  from madgraph import MadGraph5Error 
  32  import vendor.ply.lex as lex 
  33  import vendor.ply.yacc as yacc 
  34  import models.check_param_card as check_param_card 
  35   
  36  logger = logging.getLogger('madgraph.ufo_parsers') 
  37   
  38  # PLY lexer class 
  39   
40 -class ModelError(MadGraph5Error):
41 """Appropriate Error for a wrong parsing"""
42
43 -class UFOExpressionParser(object):
44 """A base class for parsers for algebraic expressions coming from UFO.""" 45 46 parsed_string = "" 47 logical_equiv = {} 48
49 - def __init__(self, **kw):
50 """Initialize the lex and yacc""" 51 52 modname = self.__class__.__name__ 53 self.debugfile = os.path.devnull 54 self.tabmodule = os.path.join(root_path, "iolibs", modname + "_" + "parsetab.py") 55 lex.lex(module=self, debug=0) 56 self.y=yacc.yacc(module=self, debug=0, debugfile=self.debugfile, 57 tabmodule=self.tabmodule)
58
59 - def parse(self, buf):
60 """Parse the string buf""" 61 self.clean() 62 self.y.parse(buf) 63 return self.parsed_string
64 65 # List of tokens and literals 66 tokens = ( 67 'LOGICAL','LOGICALCOMB','POWER', 'CSC', 'SEC', 'ACSC', 'ASEC', 'TAN', 'ATAN', 68 'SQRT', 'BUILTIN', 'CONJ', 'RE', 'RE2', 'IM', 'PI', 'COMPLEX', 'FUNCTION', 'IF','ELSE', 69 'VARIABLE', 'NUMBER','COND','REGLOG', 'REGLOGP', 'REGLOGM','RECMS','ARG' 70 ) 71 literals = "=+-*/()," 72 73 # Definition of tokens 74
75 - def t_CSC(self, t):
76 r'(?<!\w)csc(?=\()' 77 return t
78 - def t_SEC(self, t):
79 r'(?<!\w)sec(?=\()' 80 return t
81 - def t_ACSC(self, t):
82 r'(?<!\w)acsc(?=\()' 83 return t
84 - def t_TAN(self, t):
85 r'(?<!\w)tan(?=\()|(?<!\w)cmath.tan(?=\()' 86 return t
87 - def t_ATAN(self, t):
88 r'(?<!\w)atan(?=\()|(?<!\w)cmath.atan(?=\()' 89 return t
90 - def t_ASEC(self, t):
91 r'(?<!\w)asec(?=\()' 92 return t
93 - def t_REGLOG(self, t):
94 r'(?<!\w)reglog(?=\()' 95 return t
96 - def t_REGLOGP(self, t):
97 r'(?<!\w)reglogp(?=\()' 98 return t
99 - def t_REGLOGM(self, t):
100 r'(?<!\w)reglogm(?=\()' 101 return t
102 - def t_RECMS(self, t):
103 r'(?<!\w)recms(?=\()' 104 return t
105 - def t_COND(self, t):
106 r'(?<!\w)cond(?=\()' 107 return t
108 - def t_ARG(self,t):
109 r'(?<!\w)arg(?=\()' 110 return t
111 - def t_IF(self, t):
112 r'(?<!\w)if\s' 113 return t
114 - def t_ELSE(self, t):
115 r'(?<!\w)else\s' 116 return t
117 - def t_LOGICAL(self, t):
118 r'==|!=|<=|>=|<|>' 119 return t
120 - def t_LOGICALCOMB(self, t):
121 r'(?<!\w)and(?=[\s\(])|(?<!\w)or(?=[\s\(])' 122 return t
123 - def t_SQRT(self, t):
124 r'cmath\.sqrt' 125 return t
126 - def t_PI(self, t):
127 r'cmath\.pi' 128 return t
129 - def t_CONJ(self, t):
130 r'complexconjugate' 131 return t
132 - def t_BUILTIN(self, t):
133 r'(?<!\w)abs|bool|float|int|min|max(?=\()' 134 return t
135 - def t_IM(self, t):
136 r'(?<!\w)im(?=\()' 137 return t
138 - def t_RE(self, t):
139 r'(?<!\w)re(?=\()' 140 return t
141 - def t_RE2(self, t):
142 r'\.real|\.imag|\.conjugate\(\)' 143 return t
144
145 - def t_COMPLEX(self, t):
146 r'(?<!\w)complex(?=\()' 147 return t
148 - def t_FUNCTION(self, t):
149 r'(cmath\.){0,1}[a-zA-Z_][0-9a-zA-Z_]*(?=\()' 150 return t
151 - def t_VARIABLE(self, t):
152 r'[a-zA-Z_][0-9a-zA-Z_]*' 153 return t
154 155 t_NUMBER = r'([0-9]+\.[0-9]*|\.[0-9]+|[0-9]+)([eE][+-]{0,1}[0-9]+){0,1}j{0,1}' 156 t_POWER = r'\*\*' 157 158 t_ignore = " \t" 159 160 re_cmath_function = re.compile("cmath\.(?P<name>[0-9a-zA-Z_]+)") 161
162 - def t_newline(self, t):
163 r'\n+' 164 t.lexer.lineno += t.value.count("\n")
165
166 - def t_error(self, t):
167 logger.error("Illegal character '%s'" % t.value[0]) 168 t.lexer.skip(1)
169
170 - def clean(self):
171 """remove variable related to the latest parsing""" 172 #nothing to do here 173 return
174 175 176 # Build the lexer
177 - def build(self,**kwargs):
178 self.lexer = lex.lex(module=self, **kwargs)
179 180 # Definitions for the PLY yacc parser 181 # Parsing rules 182 precedence = ( 183 ('right', 'LOGICALCOMB'), 184 ('right', 'LOGICAL'), 185 ('right','IF'), 186 ('right','ELSE'), 187 ('left','='), 188 ('left','+','-'), 189 ('left','*','/'), 190 ('left', 'RE2'), 191 ('right','UMINUS'), 192 ('left','POWER'), 193 ('right','REGLOG'), 194 ('right','REGLOGP'), 195 ('right','REGLOGM'), 196 ('right','RECMS'), 197 ('right','ARG'), 198 ('right','CSC'), 199 ('right','SEC'), 200 ('right','ACSC'), 201 ('right','ASEC'), 202 ('right','SQRT'), 203 ('right','CONJ'), 204 ('right','RE'), 205 ('right','IM'), 206 ('right', 'BUILTIN'), 207 ('right','FUNCTION'), 208 ('right','COMPLEX'), 209 ('right','COND'), 210 ) 211 212 # Dictionary of parser expressions
213 - def p_statement_expr(self, p):
214 'statement : expression' 215 self.parsed_string = p[1]
216
217 - def p_expression_binop(self, p):
218 '''expression : expression '=' expression 219 | expression '+' expression 220 | expression '-' expression 221 | expression '*' expression 222 | expression '/' expression''' 223 p[0] = p[1] + p[2] + p[3]
224
225 - def p_expression_logical(self, p):
226 '''boolexpression : expression LOGICAL expression''' 227 if p[2] not in self.logical_equiv: 228 p[0] = p[1] + p[2] + p[3] 229 else: 230 p[0] = p[1] + self.logical_equiv[p[2]] + p[3]
231
232 - def p_expression_logicalcomb(self, p):
233 '''boolexpression : boolexpression LOGICALCOMB boolexpression''' 234 if p[2] not in self.logical_equiv: 235 p[0] = p[1] + p[2] + p[3] 236 else: 237 p[0] = p[1] + self.logical_equiv[p[2]] + p[3]
238
239 - def p_expression_uminus(self, p):
240 "expression : '-' expression %prec UMINUS" 241 p[0] = '-' + p[2]
242
243 - def p_group_parentheses(self, p):
244 "group : '(' expression ')'" 245 p[0] = '(' + p[2] +')'
246 247
248 - def p_group_parentheses_boolexpr(self, p):
249 "boolexpression : '(' boolexpression ')'" 250 p[0] = '(' + p[2] +')'
251
252 - def p_expression_group(self, p):
253 "expression : group" 254 p[0] = p[1]
255
256 - def p_expression_function1(self, p):
257 "expression : FUNCTION '(' expression ')'" 258 p1 = p[1] 259 re_groups = self.re_cmath_function.match(p1) 260 if re_groups: 261 p1 = re_groups.group("name") 262 p[0] = p1 + '(' + p[3] + ')'
263
264 - def p_expression_function2(self, p):
265 "expression : FUNCTION '(' expression ',' expression ')'" 266 p1 = p[1] 267 re_groups = self.re_cmath_function.match(p1) 268 if re_groups: 269 p1 = re_groups.group("name") 270 p[0] = p1 + '(' + p[3] + ',' + p[5] + ')'
271
272 - def p_expression_function3(self, p):
273 "expression : FUNCTION '(' expression ',' expression ',' expression ')'" 274 p1 = p[1] 275 re_groups = self.re_cmath_function.match(p1) 276 if re_groups: 277 p1 = re_groups.group("name") 278 p[0] = p1 + '(' + p[3] + ',' + p[5] + ' , ' + p[7] + ')'
279
280 - def p_expression_function4(self, p):
281 "expression : FUNCTION '(' expression ',' expression ',' expression ',' expression ')'" 282 p1 = p[1] 283 re_groups = self.re_cmath_function.match(p1) 284 if re_groups: 285 p1 = re_groups.group("name") 286 p[0] = p1 + '(' + p[3] + ',' + p[5] + ' , ' + p[7] + ' , ' + p[9] + ')'
287
288 - def p_error(self, p):
289 if p: 290 raise ModelError("Syntax error at '%s' (%s)." %(p.value,p)) 291 else: 292 logger.error("Syntax error at EOF") 293 self.parsed_string = "Error"
294
295 -class UFOExpressionParserFortran(UFOExpressionParser):
296 """A parser for UFO algebraic expressions, outputting 297 Fortran-style code.""" 298 299 300 builtin_equiv = {'abs': 'ABS', 301 'bool': 'LOGICAL', 302 'float': 'REAL', 303 #'complex': 'COMPLEX', handle separatly 304 'int': 'INTEGER', 305 'min': 'MIN', 306 'max': 'MAX' 307 } 308 309 # The following parser expressions need to be defined for each 310 # output language/framework 311 312 logical_equiv = {'==':'.EQ.', 313 '>=':'.GE.', 314 '<=':'.LE.', 315 '!=':'.NE.', 316 '>':'.GT.', 317 '<':'.LT.', 318 'or':'.OR.', 319 'and':'.AND.'} 320 321 types_def = { bool: lambda v: v , 322 int :lambda v: 'INT(%s)' % v , 323 float: lambda v: 'DBLE(%s)' % v, 324 complex: lambda v: 'DCMPLX(%s)' % v } 325
326 - def __init__(self, model, *args, **opts):
327 """ """ 328 self.model = model 329 out = super(UFOExpressionParserFortran,self).__init__(*args, **opts) 330 self.to_define = set()
331
332 - def clean(self):
333 """remove information about object parse for previous parsing 334 """ 335 self.to_define = set()
336 337 338 339
340 - def p_expression_number(self, p):
341 "expression : NUMBER" 342 343 if p[1].endswith('j'): 344 p[0] = ('DCMPLX(0d0, %e)' % float(p[1][:-1])).replace('e', 'd') 345 else: 346 p[0] = ('%e' % float(p[1])).replace('e', 'd')
347
348 - def p_expression_variable(self, p):
349 "expression : VARIABLE" 350 p[0] = p[1].lower()
351
352 - def p_expression_power(self, p):
353 'expression : expression POWER expression' 354 try: 355 p3 = float(p[3].replace('d','e')) 356 # Chebck if exponent is an integer 357 if p3 == int(p3): 358 p3 = str(int(p3)) 359 p[0] = p[1] + "**" + p3 360 else: 361 p[0] = p[1] + "**" + p[3] 362 except Exception: 363 p[0] = p[1] + "**" + p[3]
364
365 - def p_expression_if(self,p):
366 "expression : expression IF boolexpression ELSE expression " 367 p[0] = 'CONDIF(%s,DCMPLX(%s),DCMPLX(%s))' % (p[3], p[1], p[5]) 368 self.to_define.add('condif')
369
370 - def p_expression_ifimplicit(self,p):
371 "expression : expression IF expression ELSE expression " 372 p[0] = 'CONDIF(DCMPLX(%s).NE.(0d0,0d0),DCMPLX(%s),DCMPLX(%s))'\ 373 %(p[3], p[1], p[5]) 374 self.to_define.add('condif')
375
376 - def p_expression_cond(self, p):
377 "expression : COND '(' expression ',' expression ',' expression ')'" 378 p[0] = 'COND(DCMPLX('+p[3]+'),DCMPLX('+p[5]+'),DCMPLX('+p[7]+'))' 379 self.to_define.add('cond')
380
381 - def p_expression_recms(self, p):
382 "expression : RECMS '(' boolexpression ',' expression ')'" 383 p[0] = 'RECMS('+p[3]+',DCMPLX('+p[5]+'))' 384 self.to_define.add('recms')
385
386 - def p_expression_complex(self, p):
387 "expression : COMPLEX '(' expression ',' expression ')'" 388 p[0] = 'DCMPLX(' + p[3] + ',' + p[5] + ')'
389
390 - def p_expression_func(self, p):
391 '''expression : CSC group 392 | SEC group 393 | ACSC group 394 | ASEC group 395 | RE group 396 | IM group 397 | ARG group 398 | SQRT group 399 | CONJ group 400 | REGLOG group 401 | REGLOGP group 402 | REGLOGM group 403 | TAN group 404 | ATAN group 405 | BUILTIN group''' 406 407 if p[1] == 'csc': p[0] = '1d0/sin' + p[2] 408 elif p[1] == 'sec': p[0] = '1d0/cos' + p[2] 409 elif p[1] == 'acsc': p[0] = 'asin(1./' + p[2] + ')' 410 elif p[1] == 'asec': p[0] = 'acos(1./' + p[2] + ')' 411 elif p[1] in ['atan', 'cmath.atan'] : p[0] = 'atan(dble' + p[2]+')' 412 elif p[1] in ['tan', 'cmath.tan'] : p[0] = 'tan(dble' + p[2]+')' 413 elif p[1] == 're': p[0] = 'dble' + p[2] 414 elif p[1] == 'im': p[0] = 'dimag' + p[2] 415 elif p[1] == 'arg': p[0] = 'arg(DCMPLX'+p[2]+')' 416 elif p[1] == 'cmath.sqrt' or p[1] == 'sqrt': p[0] = 'sqrt(dcmplx' + p[2]+')' 417 elif p[1] == 'complexconjugate': p[0] = 'conjg(DCMPLX' + p[2]+')' 418 elif p[1] == 'reglog': p[0] = 'reglog(DCMPLX' + p[2] +')' 419 elif p[1] == 'reglogp': p[0] = 'reglogp(DCMPLX' + p[2] + ')' 420 elif p[1] == 'reglogm': p[0] = 'reglogm(DCMPLX' + p[2] + ')' 421 elif p[1] in self.builtin_equiv: p[0] = self.builtin_equiv[p[1]] + p[2] 422 423 if p[1] in ['reglog', 'reglogp', 'reglogm']: 424 self.to_define.add(p[1])
425
426 - def create_modelfct(self):
427 self.modelfct = dict([(f.name,f) for f in self.model.get('functions')])
428
429 - def p_expression_function1(self, p):
430 "expression : FUNCTION '(' expression ')'" 431 p1 = p[1] 432 re_groups = self.re_cmath_function.match(p1) 433 if re_groups: 434 p1 = re_groups.group("name") 435 p[0] = p1 + '(' + p[3] + ')' 436 else: 437 if not hasattr(self, 'modelfct'): 438 self.create_modelfct() 439 if p1 in self.modelfct: 440 if not hasattr(self.modelfct[p1], 'argstype') or not self.modelfct[p1].argstype: 441 types = [self.types_def[complex] for _ in self.modelfct[p1].arguments] 442 else: 443 types = [self.types_def[t] for t in self.modelfct[p1].argstype] 444 445 p[0] = p1 + '(' + types[0](p[3]) + ')' 446 else: 447 p[0] = p1 + '(' + p[3] + ')'
448 449
450 - def p_expression_function2(self, p):
451 '''expression : FUNCTION '(' expression ',' expression ')' 452 | FUNCTION '(' boolexpression ',' expression ')' ''' 453 454 p1 = p[1] 455 re_groups = self.re_cmath_function.match(p1) 456 if re_groups: 457 p1 = re_groups.group("name") 458 p[0] = p1 + '(' + p[3] + ',' + p[5] + ')' 459 else: 460 if not hasattr(self, 'modelfct'): 461 self.create_modelfct() 462 if p1 in self.modelfct: 463 if not hasattr(self.modelfct[p1], 'argstype') or not self.modelfct[p1].argstype: 464 p[0] = p1 + '(' + p[3] + ',' + p[5] + ')' 465 else: 466 types = [self.types_def[t] for t in self.modelfct[p1].argstype] 467 468 p[0] = p1 + '(' + types[0](p[3]) + ',' + types[1](p[5]) + ')' 469 else: 470 p[0] = p1 + '(' + p[3] + ',' + p[5] + ')'
471
472 - def p_expression_function3(self, p):
473 "expression : FUNCTION '(' expression ',' expression ',' expression ')'" 474 p1 = p[1] 475 re_groups = self.re_cmath_function.match(p1) 476 if re_groups: 477 p1 = re_groups.group("name") 478 p[0] = p1 + '(' + p[3] + ',' + p[5] + ' , ' + p[7] + ')' 479 else: 480 if not hasattr(self, 'modelfct'): 481 self.create_modelfct() 482 if p1 in self.modelfct: 483 if not hasattr(self.modelfct[p1], 'argstype') or not self.modelfct[p1].argstype: 484 p[0] = p1 + '(' + p[3] + ',' + p[5] + ' , ' + p[7] + ')' 485 else: 486 types = [self.types_def[t] for t in self.modelfct[p1].argstype] 487 488 p[0] = p1 + '(' + types[0](p[3]) + ',' + types[1](p[5]) + ' , ' + types[2](p[7]) + ')' 489 else: 490 p[0] = p1 + '(' + p[3] + ',' + p[5] + ' , ' + p[7] + ')'
491
492 - def p_expression_function4(self, p):
493 "expression : FUNCTION '(' expression ',' expression ',' expression ',' expression ')'" 494 p1 = p[1] 495 re_groups = self.re_cmath_function.match(p1) 496 if re_groups: 497 p1 = re_groups.group("name") 498 p[0] = p1 + '(' + p[3] + ',' + p[5] + ' , ' + p[7] + ' , ' + p[9] + ')' 499 else: 500 if not hasattr(self, 'modelfct'): 501 self.create_modelfct() 502 if p1 in self.modelfct: 503 if not hasattr(self.modelfct[p1], 'argstype') or not self.modelfct[p1].argstype: 504 p[0] = p1 + '(' + p[3] + ',' + p[5] + ' , ' + p[7] + ' , ' + p[9] + ')' 505 else: 506 types = [self.types_def[t] for t in self.modelfct[p1].argstype] 507 p[0] = p1 + '(' + types[0](p[3]) + ',' + types[1](p[5]) + ' , ' + types[2](p[7]) + ' , ' + types[3](p[9]) + ')' 508 509 else: 510 p[0] = p1 + '(' + p[3] + ',' + p[5] + ' , ' + p[7] + ' , ' + p[9] + ')'
511
512 - def p_expression_real(self, p):
513 ''' expression : expression RE2 ''' 514 515 if p[2] == '.real': 516 if p[1].startswith('('): 517 p[0] = 'dble' +p[1] 518 else: 519 p[0] = 'dble(%s)' % p[1] 520 elif p[2] == '.imag': 521 if p[1].startswith('('): 522 p[0] = 'dimag' +p[1] 523 else: 524 p[0] = 'dimag(%s)' % p[1] 525 elif p[2] == '.conjugate()': 526 if p[1].startswith('('): 527 p[0] = 'conjg(DCMPLX%s)' % p[1] 528 else: 529 p[0] = 'conjg(DCMPLX(%s))' % p[1]
530
531 - def p_expression_pi(self, p):
532 '''expression : PI''' 533 p[0] = 'pi' 534 self.to_define.add('pi')
535 536
537 -class UFOExpressionParserMPFortran(UFOExpressionParserFortran):
538 """A parser for UFO algebraic expressions, outputting 539 Fortran-style code for quadruple precision computation.""" 540 541 mp_prefix = check_param_card.ParamCard.mp_prefix 542 types_def = { bool: lambda v: v , 543 int :lambda v: 'mp__%s' % v if not v.startswith(('(','mp__','1','2','3','4','5','6','7','8','9','0','-')) else v, 544 float: lambda v: 'mp__%s' % v if not v.startswith(('(','mp__','1','2','3','4','5','6','7','8','9','0','-')) else v, 545 complex: lambda v: 'CMPLX(mp__%s, KIND=16)' % v if not v.startswith(('(','mp__','1','2','3','4','5','6','7','8','9','0','-' )) else 'CMPLX(%s, KIND=16)' % v} 546 547 builtin_equiv = {'abs': lambda v: 'ABS' +v, 548 'bool': lambda v: 'LOGICAL' +v , 549 'float': lambda v: 'REAL(' +v+", KIND=16)", 550 'complex': lambda v: 'COMPLEX(' +v+", KIND=16)", 551 'int': lambda v: 'INTEGER' +v , 552 'min': lambda v: 'MIN' +v , 553 'max': lambda v: 'MAX' +v 554 } 555 556 # The following parser expressions need to be defined for each 557 # output language/framework 558
559 - def p_expression_number(self, p):
560 "expression : NUMBER" 561 562 if p[1].endswith('j'): 563 p[0] = 'CMPLX(0.000000e+00_16, %e_16 ,KIND=16)' % float(p[1][:-1]) 564 else: 565 p[0] = '%e_16' % float(p[1])
566
567 - def p_expression_variable(self, p):
568 "expression : VARIABLE" 569 # All the multiple_precision variables are defined with the prefix _MP_" 570 p[0] = (self.mp_prefix+p[1]).lower()
571
572 - def p_expression_power(self, p):
573 'expression : expression POWER expression' 574 try: 575 p3 = float(p[3].replace('_16','')) 576 # Check if exponent is an integer 577 if p3 == int(p3): 578 p3 = str(int(p3)) 579 p[0] = p[1] + "**" + p3 580 else: 581 p[0] = p[1] + "**" + p[3] 582 except Exception: 583 p[0] = p[1] + "**" + p[3]
584
585 - def p_expression_function1(self, p):
586 "expression : FUNCTION '(' expression ')'" 587 p1 = p[1] 588 re_groups = self.re_cmath_function.match(p1) 589 if re_groups: 590 p1 = re_groups.group("name") 591 p[0] = p1 + '(' + p[3] + ')' 592 else: 593 if not hasattr(self, 'modelfct'): 594 self.create_modelfct() 595 if p1 in self.modelfct: 596 if not hasattr(self.modelfct[p1], 'argstype') or not self.modelfct[p1].argstype: 597 types = [self.types_def[complex] for _ in self.modelfct[p1].arguments] 598 else: 599 types = [self.types_def[t] for t in self.modelfct[p1].argstype] 600 601 p[0] = 'MP_' + p1 + '(' + types[0](p[3]) + ')' 602 else: 603 p[0] = 'MP_' + p1 + '(' + p[3] + ')'
604 605
606 - def p_expression_function2(self, p):
607 '''expression : FUNCTION '(' expression ',' expression ')' 608 | FUNCTION '(' boolexpression ',' expression ')' ''' 609 610 p1 = p[1] 611 re_groups = self.re_cmath_function.match(p1) 612 if re_groups: 613 p1 = re_groups.group("name") 614 p[0] = p1 + '(' + p[3] + ',' + p[5] + ')' 615 else: 616 if not hasattr(self, 'modelfct'): 617 self.create_modelfct() 618 if p1 in self.modelfct: 619 if not hasattr(self.modelfct[p1], 'argstype') or not self.modelfct[p1].argstype: 620 p[0] = p1 + '(' + p[3] + ',' + p[5] + ')' 621 else: 622 types = [self.types_def[t] for t in self.modelfct[p1].argstype] 623 624 p[0] = 'MP_' + p1 + '(' + types[0](p[3]) + ',' + types[1](p[5]) + ')' 625 else: 626 p[0] = 'MP_' + p1 + '(' + p[3] + ',' + p[5] + ')'
627
628 - def p_expression_function3(self, p):
629 "expression : FUNCTION '(' expression ',' expression ',' expression ')'" 630 p1 = p[1] 631 re_groups = self.re_cmath_function.match(p1) 632 if re_groups: 633 p1 = re_groups.group("name") 634 p[0] = p1 + '(' + p[3] + ',' + p[5] + ' , ' + p[7] + ')' 635 else: 636 if not hasattr(self, 'modelfct'): 637 self.create_modelfct() 638 if p1 in self.modelfct: 639 if not hasattr(self.modelfct[p1], 'argstype') or not self.modelfct[p1].argstype: 640 p[0] = 'MP_' + p1 + '(' + p[3] + ',' + p[5] + ' , ' + p[7] + ')' 641 else: 642 types = [self.types_def[t] for t in self.modelfct[p1].argstype] 643 644 p[0] = 'MP_' + p1 + '(' + types[0](p[3]) + ',' + types[1](p[5]) + ' , ' + types[2](p[7]) + ')' 645 else: 646 p[0] = 'MP_' + p1 + '(' + p[3] + ',' + p[5] + ' , ' + p[7] + ')'
647
648 - def p_expression_function4(self, p):
649 "expression : FUNCTION '(' expression ',' expression ',' expression ',' expression ')'" 650 p1 = p[1] 651 re_groups = self.re_cmath_function.match(p1) 652 if re_groups: 653 p1 = re_groups.group("name") 654 p[0] = p1 + '(' + p[3] + ',' + p[5] + ' , ' + p[7] + ' , ' + p[9] + ')' 655 else: 656 if not hasattr(self, 'modelfct'): 657 self.create_modelfct() 658 if p1 in self.modelfct: 659 if not hasattr(self.modelfct[p1], 'argstype') or not self.modelfct[p1].argstype: 660 p[0] = 'MP_' + p1 + '(' + p[3] + ',' + p[5] + ' , ' + p[7] + ' , ' + p[9] + ')' 661 else: 662 types = [self.types_def[t] for t in self.modelfct[p1].argstype] 663 misc.sprint(types) 664 p[0] = 'MP_' + p1 + '(' + types[0](p[3]) + ',' + types[1](p[5]) + ' , ' + types[2](p[7]) + ' , ' + types[3](p[9]) + ')' 665 666 else: 667 p[0] = 'MP_' + p1 + '(' + p[3] + ',' + p[5] + ' , ' + p[7] + ' , ' + p[9] + ')'
668 669 670
671 - def p_expression_if(self,p):
672 "expression : expression IF boolexpression ELSE expression " 673 p[0] = 'MP_CONDIF(%s,CMPLX(%s,KIND=16),CMPLX(%s,KIND=16))' % (p[3], p[1], p[5]) 674 self.to_define.add('condif')
675
676 - def p_expression_ifimplicit(self,p):
677 "expression : expression IF expression ELSE expression " 678 p[0] = 'MP_CONDIF(CMPLX(%s,KIND=16).NE.(0.0e0_16,0.0e0_16),CMPLX(%s,KIND=16),CMPLX(%s,KIND=16))'\ 679 %(p[3], p[1], p[5]) 680 self.to_define.add('condif')
681
682 - def p_expression_complex(self, p):
683 "expression : COMPLEX '(' expression ',' expression ')'" 684 p[0] = 'CMPLX(' + p[3] + ',' + p[5] + ',KIND=16)'
685
686 - def p_expression_cond(self, p):
687 "expression : COND '(' expression ',' expression ',' expression ')'" 688 p[0] = 'MP_COND(CMPLX('+p[3]+',KIND=16),CMPLX('+p[5]+\ 689 ',KIND=16),CMPLX('+p[7]+',KIND=16))' 690 self.to_define.add('cond')
691
692 - def p_expression_recms(self, p):
693 "expression : RECMS '(' boolexpression ',' expression ')'" 694 p[0] = 'MP_RECMS('+p[3]+',CMPLX('+p[5]+',KIND=16))' 695 self.to_define.add('recms')
696
697 - def p_expression_func(self, p):
698 '''expression : CSC group 699 | SEC group 700 | ACSC group 701 | ASEC group 702 | RE group 703 | IM group 704 | ARG group 705 | SQRT group 706 | CONJ group 707 | REGLOG group 708 | REGLOGP group 709 | REGLOGM group 710 | TAN group 711 | ATAN group 712 | BUILTIN group''' 713 714 if p[1] == 'csc': p[0] = '1e0_16/cos' + p[2] 715 elif p[1] == 'sec': p[0] = '1e0_16/sin' + p[2] 716 elif p[1] == 'acsc': p[0] = 'asin(1e0_16/' + p[2] + ')' 717 elif p[1] == 'asec': p[0] = 'acos(1e0_16/' + p[2] + ')' 718 elif p[1] in ['atan', 'cmath.atan'] : p[0] = 'atan(real' + p[2]+')' 719 elif p[1] in ['tan', 'cmath.tan']: p[0] = 'tan(real' + p[2]+')' 720 elif p[1] == 're': p[0] = 'real' + p[2] 721 elif p[1] == 'im': p[0] = 'imag' + p[2] 722 elif p[1] == 'arg': p[0] = 'mp_arg(CMPLX(' + p[2] + ',KIND=16))' 723 elif p[1] == 'cmath.sqrt' or p[1] == 'sqrt': p[0] = 'sqrt(CMPLX(' + p[2] + ',KIND=16))' 724 elif p[1] == 'complexconjugate': p[0] = 'conjg(CMPLX(' + p[2] + ',KIND=16))' 725 elif p[1] == 'reglog': p[0] = 'mp_reglog(CMPLX(' + p[2] +',KIND=16))' 726 elif p[1] == 'reglogp': p[0] = 'mp_reglogp(CMPLX(' + p[2] + ',KIND=16))' 727 elif p[1] == 'reglogm': p[0] = 'mp_reglogm(CMPLX(' + p[2] + ',KIND=16))' 728 elif p[1] in self.builtin_equiv: p[0] = self.builtin_equiv[p[1]](p[2]) 729 730 if p[1] in ['reglog', 'reglogp', 'reglogm']: 731 self.to_define.add(p[1])
732
733 - def p_expression_real(self, p):
734 ''' expression : expression RE2 ''' 735 736 if p[2] == '.real': 737 if p[1].startswith('('): 738 p[0] = 'real' +p[1] 739 else: 740 p[0] = 'real(%s)' % p[1] 741 elif p[2] == '.imag': 742 if p[1].startswith('('): 743 p[0] = 'imag' +p[1] 744 else: 745 p[0] = 'imag(%s)' % p[1] 746 elif p[2] == '.conjugate()': 747 p[0] = 'conjg(CMPLX(%s,KIND=16))' % p[1]
748 749
750 - def p_expression_pi(self, p):
751 '''expression : PI''' 752 p[0] = self.mp_prefix+'pi' 753 self.to_define.add('pi')
754 755
756 -class UFOExpressionParserCPP(UFOExpressionParser):
757 """A parser for UFO algebraic expressions, outputting 758 C++-style code.""" 759 760 logical_equiv = {'==':'==', 761 '>=':'>=', 762 '<=':'<=', 763 '!=':'!=', 764 '>':'>', 765 '<':'<', 766 'or':'||', 767 'and':'&&'} 768 769 builtin_equiv = {'abs': 'ABS', 770 'bool': 'bool', 771 'float': 'float', 772 #'complex': 'COMPLEX', handle separatly 773 'int': 'int', 774 'min': 'min', 775 'max': 'max' 776 } 777 778 # The following parser expressions need to be defined for each 779 # output language/framework 780
781 - def p_expression_number(self, p):
782 'expression : NUMBER' 783 784 if p[1].endswith('j'): 785 p[0] = 'std::complex<double>(0., %e)' % float(p[1][:-1]) 786 else: 787 p[0] = ('%e' % float(p[1])).replace('e', 'd') 788 789 790 p[0] = p[1] 791 # Check number is an integer, if so add "." 792 if float(p[1]) == int(float(p[1])) and float(p[1]) < 1000: 793 p[0] = str(int(float(p[1]))) + '.'
794
795 - def p_expression_variable(self, p):
796 'expression : VARIABLE' 797 p[0] = p[1]
798
799 - def p_expression_if(self,p):
800 "expression : expression IF boolexpression ELSE expression " 801 p[0] = '(%s ? %s : %s)' % (p[3], p[1], p[5])
802
803 - def p_expression_ifimplicit(self,p):
804 "expression : expression IF expression ELSE expression " 805 p[0] = '(%s ? %s : %s)' % (p[3], p[1], p[5])
806
807 - def p_expression_cond(self, p):
808 "expression : COND '(' expression ',' expression ',' expression ')'" 809 p[0] = 'COND('+p[3]+','+p[5]+','+p[7]+')'
810
811 - def p_expression_recms(self, p):
812 "expression : RECMS '(' boolexpression ',' expression ')'" 813 p[0] = 'RECMS('+p[3]+','+p[5]+')'
814
815 - def p_expression_power(self, p):
816 'expression : expression POWER expression' 817 p1=p[1] 818 p3=p[3] 819 if p[1][0] == '(' and p[1][-1] == ')': 820 p1 = p[1][1:-1] 821 if p[3][0] == '(' and p[3][-1] == ')': 822 p3 = p[3][1:-1] 823 if float(p3) == 2: 824 p[0] = '((' + p1 + ')*(' + p1 + '))' 825 elif float(p3) == 3: 826 p[0] = '((' + p1 + ')*(' + p1 + ')*(' + p1 + '))' 827 elif float(p3) == 4: 828 p[0] = '((' + p1 + ')*(' + p1 + ')*(' + p1 + ')*(' + p1 + '))' 829 elif float(p3) == 0.5 or p3 == '0.5' or p3 == '1./2' or p3 == '1/2.' or p3 == '1./2.': 830 p[0] = 'sqrt(' + p1 + ')' 831 elif float(p3) == 1./3 or p3 == '1./3' or p3 == '1/3.' or p3 == '1./3.': 832 p[0] = 'cbrt(' + p1 + ')' 833 else: 834 p[0] = 'pow(' + p1 + ',' + p3 + ')'
835
836 - def p_expression_complex(self, p):
837 "expression : COMPLEX '(' expression ',' expression ')'" 838 p[0] = 'std::complex<double>(' + p[3] + ',' + p[5] + ')'
839
840 - def p_expression_func(self, p):
841 '''expression : CSC group 842 | SEC group 843 | ACSC group 844 | ASEC group 845 | TAN group 846 | ATAN group 847 | RE group 848 | IM group 849 | ARG group 850 | SQRT group 851 | CONJ group 852 | REGLOG group 853 | REGLOGP group 854 | REGLOGM group 855 | BUILTIN group ''' 856 if p[1] == 'csc': p[0] = '1./cos' + p[2] 857 elif p[1] == 'sec': p[0] = '1./sin' + p[2] 858 elif p[1] == 'acsc': p[0] = 'asin(1./' + p[2] + ')' 859 elif p[1] == 'asec': p[0] = 'acos(1./' + p[2] + ')' 860 elif p[1] in ['atan', 'cmath.atan']: p[0] = 'atan' +p[2] 861 elif p[1] in ['tan', 'cmath.tan']: p[0] = 'tan' +p[2] 862 elif p[1] == 're': p[0] = 'real' + p[2] 863 elif p[1] == 'im': p[0] = 'imag' + p[2] 864 elif p[1] == 'arg':p[0] = 'arg' + p[2] 865 elif p[1] == 'cmath.sqrt' or p[1] == 'sqrt': p[0] = 'sqrt' + p[2] 866 elif p[1] == 'complexconjugate': p[0] = 'conj' + p[2] 867 elif p[1] == 'reglog': p[0] = 'reglog' + p[2] 868 elif p[1] == 'reglogp': p[0] = 'reglogp' + p[2] 869 elif p[1] == 'reglogm': p[0] = 'reglogm' + p[2] 870 elif p[1] in self.buitin_equiv: p[0] = self.builtin_equiv[p[1]] + p[2]
871 872
873 - def p_expression_real(self, p):
874 ''' expression : expression RE2 ''' 875 876 if p[2] == '.real': 877 if p[1].startswith('('): 878 p[0] = 'real' +p[1] 879 else: 880 p[0] = 'real(%s)' % p[1] 881 elif p[2] == '.imag': 882 if p[1].startswith('('): 883 p[0] = 'imag' +p[1] 884 else: 885 p[0] = 'imag(%s)' % p[1]
886 887
888 - def p_expression_pi(self, p):
889 '''expression : PI''' 890 p[0] = 'M_PI'
891
892 -class UFOExpressionParserPythonIF(UFOExpressionParser):
893 """An ad hoc parser for UFO algebraic expressions with if statement, outputting 894 Python-style code, with the conditional 'if' expressions simplified using 895 pre-defined set of variables specified when instanciating this parser.""" 896 897 logical_equiv = {'==':'==', 898 '>=':'>=', 899 '<=':'<=', 900 '!=':'!=', 901 '>':'>', 902 '<':'<', 903 'or':' or ', 904 'and':' and '} 905 906 builtin_equiv = {'abs': 'abs', 907 'bool': 'bool', 908 'float': 'float', 909 #'complex': 'COMPLEX', handle separatly 910 'int': 'int', 911 'min': 'min', 912 'max': 'max' 913 } 914
915 - def __init__(self, *args,**kw):
916 """Initialize the lex and yacc""" 917 918 self.changes_performed = 0 919 920 if len(args) > 0: 921 if isinstance(args[0],dict): 922 self.defined_variables = copy.copy(args[0]) 923 elif isinstance(args[0],str): 924 try: 925 self.defined_variables = eval(args[0]) 926 except: 927 raise ModelError, 'The expression "%s"'%str(args[0])+\ 928 " given as defined variables for the UFOExpressionParserPythonIF"+\ 929 " does not have a correct syntax." 930 if not isinstance(self.defined_variables, dict): 931 raise ModelError, 'The argument "%s"'%str(args[0])+\ 932 " given as defined variables for the UFOExpressionParserPythonIF"+\ 933 " is not a dictionary." 934 else: 935 raise ModelError, "The argument %s"%str(args[0])+\ 936 " given as defined variables for the UFOExpressionParserPythonIF"+\ 937 " must be either a dictionary or a string." 938 args = args[1:] 939 for key, value in self.defined_variables.items(): 940 if not isinstance(key,str) or \ 941 not any(isinstance(value,t) for t in [float,complex,int]): 942 # This is not a valid environment variable for the parser 943 del self.defined_variables[key] 944 945 else: 946 # If the user doesn't specify any defined variable for this parser, this means 947 # that it shouldn't do anything, not even simplify trivial conditional expressions 948 # such as '1 if True else 2' 949 self.defined_variables = None 950 951 super(UFOExpressionParserPythonIF,self).__init__(*args, **kw)
952
953 - def parse(self, *args, **kw):
954 """ Wrapper around the parse function so as to also return the number 955 of if substitutions made.""" 956 self.changes_performed = 0 957 new_expression = super(UFOExpressionParserPythonIF,self).parse(*args, **kw) 958 return new_expression, self.changes_performed
959
960 - def p_expression_number(self, p):
961 "expression : NUMBER" 962 p[0] = p[1]
963
964 - def p_expression_variable(self, p):
965 "expression : VARIABLE" 966 p[0] = p[1]
967
968 - def p_expression_power(self, p):
969 'expression : expression POWER expression' 970 p[0] = p[1] + "**" + p[3]
971
972 - def p_expression_if(self,p):
973 "expression : expression IF boolexpression ELSE expression " 974 if self.defined_variables is None: 975 p[0] = '%s if %s else %s'%(p[1],p[3],p[5]) 976 return 977 try: 978 p[0] = '%s'%p[1] if eval(p[3],self.defined_variables) else '%s'%p[5] 979 self.changes_performed += 1 980 except Exception: 981 p[0] = '%s if %s else %s'%(p[1],p[3],p[5])
982
983 - def p_expression_ifimplicit(self,p):
984 "expression : expression IF expression ELSE expression " 985 if self.defined_variables is None: 986 p[0] = '%s if %s!=0.0 else %s'%(p[1],p[3],p[5]) 987 return 988 try: 989 p[0] = '%s'%p[1] if eval(p[3]+'!= 0.0',self.defined_variables) else '%s'%p[5] 990 self.changes_performed += 1 991 except Exception: 992 p[0] = '%s if %s!=0.0 else %s'%(p[1],p[3],p[5])
993
994 - def p_expression_cond(self, p):
995 "expression : COND '(' expression ',' expression ',' expression ')'" 996 # We assume the cond syntax is used by the Model builder when he doesn't want it to 997 # get simplified, ever. 998 p[0] = 'cond('+p[3]+','+p[5]+','+p[7]+')'
999
1000 - def p_expression_complex(self, p):
1001 "expression : COMPLEX '(' expression ',' expression ')'" 1002 p[0] = 'complex(' + p[3] + ',' + p[5] + ')'
1003
1004 - def p_expression_recms(self, p):
1005 "expression : RECMS '(' boolexpression ',' expression ')'" 1006 p[0] = 'recms('+p[3]+','+p[5]+')'
1007
1008 - def p_expression_func(self, p):
1009 '''expression : CSC group 1010 | SEC group 1011 | ACSC group 1012 | ASEC group 1013 | RE group 1014 | IM group 1015 | ARG group 1016 | SQRT group 1017 | TAN group 1018 | ATAN group 1019 | CONJ group 1020 | REGLOG group 1021 | REGLOGP group 1022 | REGLOGM group 1023 | BUILTIN group''' 1024 if p[1] == 'csc': p[0] = 'csc' + p[2] 1025 elif p[1] == 'sec': p[0] = 'sec' + p[2] 1026 elif p[1] == 'acsc': p[0] = 'acsc' + p[2] 1027 elif p[1] == 'asec': p[0] = 'asec' + p[2] 1028 elif p[1] in ['tan','cmath.tan']: p[0] = 'tan' + p[2] 1029 elif p[1] in ['atan','cmath.atan']: p[0] = 'atan' + p[2] 1030 elif p[1] == 're': p[0] = 're' + p[2] 1031 elif p[1] == 'im': p[0] = 'im' + p[2] 1032 elif p[1] == 'arg': p[0] = 'arg' + p[2] 1033 elif p[1] == 'cmath.sqrt' or p[1] == 'sqrt': p[0] = 'cmath.sqrt' + p[2] 1034 elif p[1] == 'complexconjugate': p[0] = 'complexconjugate' + p[2] 1035 elif p[1] == 'reglog': p[0] = 'reglog' + p[2] 1036 elif p[1] == 'reglogp': p[0] = 'reglogp' + p[2] 1037 elif p[1] == 'reglogm': p[0] = 'reglogm' + p[2] 1038 elif p[1] in self.builtin_equiv: p[0] = self.builtin_equiv[p[1]] + p[2]
1039
1040 - def p_expression_real(self, p):
1041 ''' expression : expression RE2 ''' 1042 p[0] = p[1]+p[2]
1043
1044 - def p_expression_pi(self, p):
1045 '''expression : PI''' 1046 1047 p[0] = 'cmath.pi'
1048 1049 1050 1051 # Main program, allows to interactively test the parser 1052 if __name__ == '__main__': 1053 1054 if len(sys.argv) == 1: 1055 print "Please specify a parser: fortran, mpfortran or c++" 1056 exit() 1057 if sys.argv[1] == "fortran": 1058 calc = UFOExpressionParserFortran() 1059 elif sys.argv[1] == "mpfortran": 1060 calc = UFOExpressionParserMPFortran() 1061 elif sys.argv[1] == "c++": 1062 calc = UFOExpressionParserCPP() 1063 elif sys.argv[1] == "aloha": 1064 calc = UFOExpressionParserCPP() 1065 elif sys.argv[1] == "pythonif": 1066 if len(sys.argv) > 2: 1067 calc = UFOExpressionParserPythonIF(sys.argv[2]) 1068 else: 1069 calc = UFOExpressionParserPythonIF() 1070 else: 1071 print "Please specify a parser: fortran, mpfortran, c++ or pythonif" 1072 print "You gave", sys.argv[1] 1073 if len(sys.argv) > 2: 1074 print "with the second argument",sys.argv[2] 1075 exit() 1076 1077 while 1: 1078 try: 1079 s = raw_input('calc > ') 1080 except EOFError: 1081 break 1082 if not s: continue 1083 print calc.parse(s) 1084