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