1
2
3
4
5
6
7
8
9
10
11
12
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 madgraph.various.misc as misc
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 from madgraph import MadGraph5Error
30 import vendor.ply.lex as lex
31 import vendor.ply.yacc as yacc
32 import models.check_param_card as check_param_card
33
34 logger = logging.getLogger('madgraph.ufo_parsers')
35
36
37
39 """Appropriate Error for a wrong parsing"""
40
42 """A base class for parsers for algebraic expressions coming from UFO."""
43
44 parsed_string = ""
45 logical_equiv = {}
46
48 """Initialize the lex and yacc"""
49
50 modname = self.__class__.__name__
51 self.debugfile = os.path.devnull
52 self.tabmodule = os.path.join(root_path, "iolibs", modname + "_" + "parsetab.py")
53 lex.lex(module=self, debug=0)
54 self.y=yacc.yacc(module=self, debug=0, debugfile=self.debugfile,
55 tabmodule=self.tabmodule)
56
61
62
63 tokens = (
64 'LOGICAL','LOGICALCOMB','POWER', 'CSC', 'SEC', 'ACSC', 'ASEC',
65 'SQRT', 'CONJ', 'RE', 'RE2', 'IM', 'PI', 'COMPLEX', 'FUNCTION', 'IF','ELSE',
66 'VARIABLE', 'NUMBER','COND','REGLOG', 'ARG'
67 )
68 literals = "=+-*/(),"
69
70
71
73 r'(?<!\w)csc(?=\()'
74 return t
76 r'(?<!\w)sec(?=\()'
77 return t
79 r'(?<!\w)acsc(?=\()'
80 return t
82 r'(?<!\w)asec(?=\()'
83 return t
85 r'(?<!\w)reglog(?=\()'
86 return t
88 r'(?<!\w)cond(?=\()'
89 return t
93 r'(?<!\w)if\s'
94 return t
96 r'(?<!\w)else\s'
97 return t
99 r'==|!=|<=|>=|<|>'
100 return t
102 r'(?<!\w)and(?=[\s\(])|(?<!\w)or(?=[\s\(])'
103 return t
105 r'cmath\.sqrt'
106 return t
108 r'cmath\.pi'
109 return t
111 r'complexconjugate'
112 return t
114 r'(?<!\w)im(?=\()'
115 return t
117 r'(?<!\w)re(?=\()'
118 return t
120 r'\.real|\.imag'
121 return t
122
124 r'(?<!\w)complex(?=\()'
125 return t
127 r'(cmath\.){0,1}[a-zA-Z_][0-9a-zA-Z_]*(?=\()'
128 return t
130 r'[a-zA-Z_][0-9a-zA-Z_]*'
131 return t
132
133 t_NUMBER = r'([0-9]+\.[0-9]*|\.[0-9]+|[0-9]+)([eE][+-]{0,1}[0-9]+){0,1}j{0,1}'
134 t_POWER = r'\*\*'
135
136 t_ignore = " \t"
137
138 re_cmath_function = re.compile("cmath\.(?P<name>[0-9a-zA-Z_]+)")
139
141 r'\n+'
142 t.lexer.lineno += t.value.count("\n")
143
145 logger.error("Illegal character '%s'" % t.value[0])
146 t.lexer.skip(1)
147
148
149 - def build(self,**kwargs):
150 self.lexer = lex.lex(module=self, **kwargs)
151
152
153
154 precedence = (
155 ('right', 'LOGICALCOMB'),
156 ('right', 'LOGICAL'),
157 ('right','IF'),
158 ('right','ELSE'),
159 ('left','='),
160 ('left','+','-'),
161 ('left','*','/'),
162 ('left', 'RE2'),
163 ('right','UMINUS'),
164 ('left','POWER'),
165 ('right','REGLOG'),
166 ('right','ARG'),
167 ('right','CSC'),
168 ('right','SEC'),
169 ('right','ACSC'),
170 ('right','ASEC'),
171 ('right','SQRT'),
172 ('right','CONJ'),
173 ('right','RE'),
174 ('right','IM'),
175 ('right','FUNCTION'),
176 ('right','COMPLEX'),
177 ('right','COND'),
178 )
179
180
184
186 '''expression : expression '=' expression
187 | expression '+' expression
188 | expression '-' expression
189 | expression '*' expression
190 | expression '/' expression'''
191 p[0] = p[1] + p[2] + p[3]
192
194 '''boolexpression : expression LOGICAL expression'''
195 if p[2] not in self.logical_equiv:
196 p[0] = p[1] + p[2] + p[3]
197 else:
198 p[0] = p[1] + self.logical_equiv[p[2]] + p[3]
199
201 '''boolexpression : boolexpression LOGICALCOMB boolexpression'''
202 if p[2] not in self.logical_equiv:
203 p[0] = p[1] + p[2] + p[3]
204 else:
205 p[0] = p[1] + self.logical_equiv[p[2]] + p[3]
206
208 "expression : '-' expression %prec UMINUS"
209 p[0] = '-' + p[2]
210
212 "group : '(' expression ')'"
213 p[0] = '(' + p[2] +')'
214
216 "boolexpression : '(' boolexpression ')'"
217 p[0] = '(' + p[2] +')'
218
220 "expression : group"
221 p[0] = p[1]
222
224 "expression : FUNCTION '(' expression ')'"
225 p1 = p[1]
226 re_groups = self.re_cmath_function.match(p1)
227 if re_groups:
228 p1 = re_groups.group("name")
229 p[0] = p1 + '(' + p[3] + ')'
230
232 "expression : FUNCTION '(' expression ',' expression ')'"
233 p1 = p[1]
234 re_groups = self.re_cmath_function.match(p1)
235 if re_groups:
236 p1 = re_groups.group("name")
237 p[0] = p1 + '(' + p[3] + ',' + p[5] + ')'
238
240 if p:
241 raise ModelError("Syntax error at '%s' (%s)." %(p.value,p))
242 else:
243 logger.error("Syntax error at EOF")
244 self.parsed_string = "Error"
245
247 """A parser for UFO algebraic expressions, outputting
248 Fortran-style code."""
249
250
251
252
253 logical_equiv = {'==':'.EQ.',
254 '>=':'.GE.',
255 '<=':'.LE.',
256 '!=':'.NE.',
257 '>':'.GT.',
258 '<':'.LT.',
259 'or':'.OR.',
260 'and':'.AND.'}
261
263 "expression : NUMBER"
264 if p[1].endswith('j'):
265 p[0] = ('DCOMPLX(0d0, %e)' % float(p[1][:-1])).replace('e', 'd')
266 else:
267 p[0] = ('%e' % float(p[1])).replace('e', 'd')
268
270 "expression : VARIABLE"
271 p[0] = p[1].lower()
272
274 'expression : expression POWER expression'
275 try:
276 p3 = float(p[3].replace('d','e'))
277
278 if p3 == int(p3):
279 p3 = str(int(p3))
280 p[0] = p[1] + "**" + p3
281 else:
282 p[0] = p[1] + "**" + p[3]
283 except Exception:
284 p[0] = p[1] + "**" + p[3]
285
287 "expression : expression IF boolexpression ELSE expression "
288 p[0] = 'CONDIF(%s,DCMPLX(%s),DCMPLX(%s))' % (p[3], p[1], p[5])
289
291 "expression : expression IF expression ELSE expression "
292 p[0] = 'CONDIF(DCMPLX(%s).NE.(0d0,0d0),DCMPLX(%s),DCMPLX(%s))'\
293 %(p[3], p[1], p[5])
294
296 "expression : COND '(' expression ',' expression ',' expression ')'"
297 p[0] = 'COND(DCMPLX('+p[3]+'),DCMPLX('+p[5]+'),DCMPLX('+p[7]+'))'
298
300 "expression : COMPLEX '(' expression ',' expression ')'"
301 p[0] = 'DCMPLX(' + p[3] + ',' + p[5] + ')'
302
304 '''expression : CSC group
305 | SEC group
306 | ACSC group
307 | ASEC group
308 | RE group
309 | IM group
310 | ARG group
311 | SQRT group
312 | CONJ group
313 | REGLOG group'''
314 if p[1] == 'csc': p[0] = '1d0/cos' + p[2]
315 elif p[1] == 'sec': p[0] = '1d0/sin' + p[2]
316 elif p[1] == 'acsc': p[0] = 'asin(1./' + p[2] + ')'
317 elif p[1] == 'asec': p[0] = 'acos(1./' + p[2] + ')'
318 elif p[1] == 're': p[0] = 'dble' + p[2]
319 elif p[1] == 'im': p[0] = 'dimag' + p[2]
320 elif p[1] == 'arg': p[0] = 'arg(DCMPLX'+p[2]+')'
321 elif p[1] == 'cmath.sqrt' or p[1] == 'sqrt': p[0] = 'sqrt' + p[2]
322 elif p[1] == 'complexconjugate': p[0] = 'conjg(DCMPLX' + p[2]+')'
323 elif p[1] == 'reglog': p[0] = 'reglog(DCMPLX' + p[2] +')'
324
325
327 ''' expression : expression RE2 '''
328
329 if p[2] == '.real':
330 if p[1].startswith('('):
331 p[0] = 'dble' +p[1]
332 else:
333 p[0] = 'dble(%s)' % p[1]
334 elif p[2] == '.imag':
335 if p[1].startswith('('):
336 p[0] = 'dimag' +p[1]
337 else:
338 p[0] = 'dimag(%s)' % p[1]
339
341 '''expression : PI'''
342 p[0] = 'pi'
343
345 """A parser for UFO algebraic expressions, outputting
346 Fortran-style code for quadruple precision computation."""
347
348 mp_prefix = check_param_card.ParamCard.mp_prefix
349
350
351
352
354 "expression : NUMBER"
355
356 if p[1].endswith('j'):
357 p[0] = 'CMPLX(0.000000e+00_16, %e_16 ,KIND=16)' % float(p[1][:-1])
358 else:
359 p[0] = '%e_16' % float(p[1])
360
362 "expression : VARIABLE"
363
364 p[0] = (self.mp_prefix+p[1]).lower()
365
367 'expression : expression POWER expression'
368 try:
369 p3 = float(p[3].replace('_16',''))
370
371 if p3 == int(p3):
372 p3 = str(int(p3))
373 p[0] = p[1] + "**" + p3
374 else:
375 p[0] = p[1] + "**" + p[3]
376 except Exception:
377 p[0] = p[1] + "**" + p[3]
378
380 "expression : expression IF boolexpression ELSE expression "
381 p[0] = 'MP_CONDIF(%s,CMPLX(%s,KIND=16),CMPLX(%s,KIND=16))' % (p[3], p[1], p[5])
382
384 "expression : expression IF expression ELSE expression "
385 p[0] = 'MP_CONDIF(CMPLX(%s,KIND=16).NE.(0.0e0_16,0.0e0_16),CMPLX(%s,KIND=16),CMPLX(%s,KIND=16))'\
386 %(p[3], p[1], p[5])
387
389 "expression : COMPLEX '(' expression ',' expression ')'"
390 p[0] = 'CMPLX(' + p[3] + ',' + p[5] + ',KIND=16)'
391
393 "expression : COND '(' expression ',' expression ',' expression ')'"
394 p[0] = 'MP_COND(CMPLX('+p[3]+',KIND=16),CMPLX('+p[5]+\
395 ',KIND=16),CMPLX('+p[7]+',KIND=16))'
396
398 '''expression : CSC group
399 | SEC group
400 | ACSC group
401 | ASEC group
402 | RE group
403 | IM group
404 | ARG group
405 | SQRT group
406 | CONJ group
407 | REGLOG group'''
408 if p[1] == 'csc': p[0] = '1e0_16/cos' + p[2]
409 elif p[1] == 'sec': p[0] = '1e0_16/sin' + p[2]
410 elif p[1] == 'acsc': p[0] = 'asin(1e0_16/' + p[2] + ')'
411 elif p[1] == 'asec': p[0] = 'acos(1e0_16/' + p[2] + ')'
412 elif p[1] == 're': p[0] = 'real' + p[2]
413 elif p[1] == 'im': p[0] = 'imag' + p[2]
414 elif p[1] == 'arg': p[0] = 'mp_arg(CMPLX(' + p[2] + ',KIND=16))'
415 elif p[1] == 'cmath.sqrt' or p[1] == 'sqrt': p[0] = 'sqrt' + p[2]
416 elif p[1] == 'complexconjugate': p[0] = 'conjg(CMPLX(' + p[2] + ',KIND=16))'
417 elif p[1] == 'reglog': p[0] = 'mp_reglog(CMPLX(' + p[2] +',KIND=16))'
418
420 ''' expression : expression RE2 '''
421
422 if p[2] == '.real':
423 if p[1].startswith('('):
424 p[0] = 'real' +p[1]
425 else:
426 p[0] = 'real(%s)' % p[1]
427 elif p[2] == '.imag':
428 if p[1].startswith('('):
429 p[0] = 'imag' +p[1]
430 else:
431 p[0] = 'imag(%s)' % p[1]
432
433
435 '''expression : PI'''
436 p[0] = self.mp_prefix+'pi'
437
439 """A parser for UFO algebraic expressions, outputting
440 C++-style code."""
441
442 logical_equiv = {'==':'==',
443 '>=':'>=',
444 '<=':'<=',
445 '!=':'!=',
446 '>':'>',
447 '<':'<',
448 'or':'||',
449 'and':'&&'}
450
451
452
453
455 'expression : NUMBER'
456
457 if p[1].endswith('j'):
458 p[0] = 'std::complex<double>(0., %e)' % float(p[1][:-1])
459 else:
460 p[0] = ('%e' % float(p[1])).replace('e', 'd')
461
462
463 p[0] = p[1]
464
465 if float(p[1]) == int(float(p[1])) and float(p[1]) < 1000:
466 p[0] = str(int(float(p[1]))) + '.'
467
469 'expression : VARIABLE'
470 p[0] = p[1]
471
473 "expression : expression IF boolexpression ELSE expression "
474 p[0] = '(%s ? %s : %s)' % (p[3], p[1], p[5])
475
477 "expression : expression IF expression ELSE expression "
478 p[0] = '(%s ? %s : %s)' % (p[3], p[1], p[5])
479
481 "expression : COND '(' expression ',' expression ',' expression ')'"
482 p[0] = 'COND('+p[3]+','+p[5]+','+p[7]+')'
483
485 'expression : expression POWER expression'
486 p1=p[1]
487 p3=p[3]
488 if p[1][0] == '(' and p[1][-1] == ')':
489 p1 = p[1][1:-1]
490 if p[3][0] == '(' and p[3][-1] == ')':
491 p3 = p[3][1:-1]
492 p[0] = 'pow(' + p1 + ',' + p3 + ')'
493
495 "expression : COMPLEX '(' expression ',' expression ')'"
496 p[0] = 'std::complex<double>(' + p[3] + ',' + p[5] + ')'
497
499 '''expression : CSC group
500 | SEC group
501 | ACSC group
502 | ASEC group
503 | RE group
504 | IM group
505 | ARG group
506 | SQRT group
507 | CONJ group
508 | REGLOG group '''
509 if p[1] == 'csc': p[0] = '1./cos' + p[2]
510 elif p[1] == 'sec': p[0] = '1./sin' + p[2]
511 elif p[1] == 'acsc': p[0] = 'asin(1./' + p[2] + ')'
512 elif p[1] == 'asec': p[0] = 'acos(1./' + p[2] + ')'
513 elif p[1] == 're': p[0] = 'real' + p[2]
514 elif p[1] == 'im': p[0] = 'imag' + p[2]
515 elif p[1] == 'arg':p[0] = 'arg' + p[2]
516 elif p[1] == 'cmath.sqrt' or p[1] == 'sqrt': p[0] = 'sqrt' + p[2]
517 elif p[1] == 'complexconjugate': p[0] = 'conj' + p[2]
518 elif p[1] == 'reglog': p[0] = 'reglog' + p[2]
519
521 ''' expression : expression RE2 '''
522
523 if p[2] == '.real':
524 if p[1].startswith('('):
525 p[0] = 'real' +p[1]
526 else:
527 p[0] = 'real(%s)' % p[1]
528 elif p[2] == '.imag':
529 if p[1].startswith('('):
530 p[0] = 'imag' +p[1]
531 else:
532 p[0] = 'imag(%s)' % p[1]
533
534
536 '''expression : PI'''
537 p[0] = 'M_PI'
538
539
540
541
542 if __name__ == '__main__':
543
544 if len(sys.argv) == 1:
545 print "Please specify a parser: fortran, mpfortran or c++"
546 exit()
547 if sys.argv[1] == "fortran":
548 calc = UFOExpressionParserFortran()
549 elif sys.argv[1] == "mpfortran":
550 calc = UFOExpressionParserMPFortran()
551 elif sys.argv[1] == "c++":
552 calc = UFOExpressionParserCPP()
553 elif sys.argv[1] == "aloha":
554 calc = UFOExpressionParserCPP()
555 else:
556 print "Please specify a parser: fortran, mpfortran or c++"
557 print "You gave", sys.argv[1]
558 exit()
559
560 while 1:
561 try:
562 s = raw_input('calc > ')
563 except EOFError:
564 break
565 if not s: continue
566 print calc.parse(s)
567