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
25 root_path = os.path.split(os.path.dirname(os.path.realpath( __file__ )))[0]
26 sys.path.append(os.path.join(root_path, os.path.pardir))
27
28 from madgraph import MadGraph5Error
29 import vendor.ply.lex as lex
30 import vendor.ply.yacc as yacc
31 import models.check_param_card as check_param_card
32
33 logger = logging.getLogger('madgraph.ufo_parsers')
34
35
36
38 """Appropriate Error for a wrong parsing"""
39
41 """A base class for parsers for algebraic expressions coming from UFO."""
42
43 parsed_string = ""
44 logical_equiv = {}
45
47 """Initialize the lex and yacc"""
48
49 modname = self.__class__.__name__
50 self.debugfile = os.path.devnull
51 self.tabmodule = os.path.join(root_path, "iolibs", modname + "_" + "parsetab.py")
52 lex.lex(module=self, debug=0)
53 self.y=yacc.yacc(module=self, debug=0, debugfile=self.debugfile,
54 tabmodule=self.tabmodule)
55
60
61
62 tokens = (
63 'LOGICAL','LOGICALCOMB','POWER', 'CSC', 'SEC', 'ACSC', 'ASEC',
64 'SQRT', 'CONJ', 'RE', 'IM', 'PI', 'COMPLEX', 'FUNCTION', 'IF','ELSE',
65 'VARIABLE', 'NUMBER','COND','REGLOG', 'ARG'
66 )
67 literals = "=+-*/(),"
68
69
70
72 r'(?<!\w)csc(?=\()'
73 return t
75 r'(?<!\w)sec(?=\()'
76 return t
78 r'(?<!\w)acsc(?=\()'
79 return t
81 r'(?<!\w)asec(?=\()'
82 return t
84 r'(?<!\w)reglog(?=\()'
85 return t
87 r'(?<!\w)cond(?=\()'
88 return t
92 r'(?<!\w)if\s'
93 return t
95 r'(?<!\w)else\s'
96 return t
98 r'==|!=|<=|>=|<|>'
99 return t
101 r'(?<!\w)and(?=[\s\(])|(?<!\w)or(?=[\s\(])'
102 return t
104 r'cmath\.sqrt'
105 return t
107 r'cmath\.pi'
108 return t
110 r'complexconjugate'
111 return t
113 r'(?<!\w)im(?=\()'
114 return t
116 r'(?<!\w)re(?=\()'
117 return t
119 r'(?<!\w)complex(?=\()'
120 return t
122 r'(cmath\.){0,1}[a-zA-Z_][0-9a-zA-Z_]*(?=\()'
123 return t
125 r'[a-zA-Z_][0-9a-zA-Z_]*'
126 return t
127
128 t_NUMBER = r'([0-9]+\.[0-9]*|\.[0-9]+|[0-9]+)([eE][+-]{0,1}[0-9]+){0,1}'
129 t_POWER = r'\*\*'
130
131 t_ignore = " \t"
132
133 re_cmath_function = re.compile("cmath\.(?P<name>[0-9a-zA-Z_]+)")
134
136 r'\n+'
137 t.lexer.lineno += t.value.count("\n")
138
140 logger.error("Illegal character '%s'" % t.value[0])
141 t.lexer.skip(1)
142
143
144 - def build(self,**kwargs):
145 self.lexer = lex.lex(module=self, **kwargs)
146
147
148
149 precedence = (
150 ('right', 'LOGICALCOMB'),
151 ('right', 'LOGICAL'),
152 ('right','IF'),
153 ('right','ELSE'),
154 ('left','='),
155 ('left','+','-'),
156 ('left','*','/'),
157 ('right','UMINUS'),
158 ('left','POWER'),
159 ('right','REGLOG'),
160 ('right','ARG'),
161 ('right','CSC'),
162 ('right','SEC'),
163 ('right','ACSC'),
164 ('right','ASEC'),
165 ('right','SQRT'),
166 ('right','CONJ'),
167 ('right','RE'),
168 ('right','IM'),
169 ('right','FUNCTION'),
170 ('right','COMPLEX'),
171 ('right','COND'),
172 )
173
174
178
180 '''expression : expression '=' expression
181 | expression '+' expression
182 | expression '-' expression
183 | expression '*' expression
184 | expression '/' expression'''
185 p[0] = p[1] + p[2] + p[3]
186
188 '''boolexpression : expression LOGICAL expression'''
189 if p[2] not in self.logical_equiv:
190 p[0] = p[1] + p[2] + p[3]
191 else:
192 p[0] = p[1] + self.logical_equiv[p[2]] + p[3]
193
195 '''boolexpression : boolexpression LOGICALCOMB boolexpression'''
196 if p[2] not in self.logical_equiv:
197 p[0] = p[1] + p[2] + p[3]
198 else:
199 p[0] = p[1] + self.logical_equiv[p[2]] + p[3]
200
202 "expression : '-' expression %prec UMINUS"
203 p[0] = '-' + p[2]
204
206 "group : '(' expression ')'"
207 p[0] = '(' + p[2] +')'
208
210 "boolexpression : '(' boolexpression ')'"
211 p[0] = '(' + p[2] +')'
212
214 "expression : group"
215 p[0] = p[1]
216
218 "expression : FUNCTION '(' expression ')'"
219 p1 = p[1]
220 re_groups = self.re_cmath_function.match(p1)
221 if re_groups:
222 p1 = re_groups.group("name")
223 p[0] = p1 + '(' + p[3] + ')'
224
226 "expression : FUNCTION '(' expression ',' expression ')'"
227 p1 = p[1]
228 re_groups = self.re_cmath_function.match(p1)
229 if re_groups:
230 p1 = re_groups.group("name")
231 p[0] = p1 + '(' + p[3] + ',' + p[5] + ')'
232
234 if p:
235 raise ModelError("Syntax error at '%s' (%s)." %(p.value,p))
236 else:
237 logger.error("Syntax error at EOF")
238 self.parsed_string = "Error"
239
241 """A parser for UFO algebraic expressions, outputting
242 Fortran-style code."""
243
244
245
246
247 logical_equiv = {'==':'.EQ.',
248 '>=':'.GE.',
249 '<=':'.LE.',
250 '!=':'.NE.',
251 '>':'.GT.',
252 '<':'.LT.',
253 'or':'.OR.',
254 'and':'.AND.'}
255
257 "expression : NUMBER"
258 p[0] = ('%e' % float(p[1])).replace('e', 'd')
259
261 "expression : VARIABLE"
262 p[0] = p[1].lower()
263
265 'expression : expression POWER expression'
266 try:
267 p3 = float(p[3].replace('d','e'))
268
269 if p3 == int(p3):
270 p3 = str(int(p3))
271 p[0] = p[1] + "**" + p3
272 else:
273 p[0] = p[1] + "**" + p[3]
274 except Exception:
275 p[0] = p[1] + "**" + p[3]
276
278 "expression : expression IF boolexpression ELSE expression "
279 p[0] = 'CONDIF(%s,DCMPLX(%s),DCMPLX(%s))' % (p[3], p[1], p[5])
280
282 "expression : expression IF expression ELSE expression "
283 p[0] = 'CONDIF(DCMPLX(%s).NE.(0d0,0d0),DCMPLX(%s),DCMPLX(%s))'\
284 %(p[3], p[1], p[5])
285
287 "expression : COND '(' expression ',' expression ',' expression ')'"
288 p[0] = 'COND(DCMPLX('+p[3]+'),DCMPLX('+p[5]+'),DCMPLX('+p[7]+'))'
289
291 "expression : COMPLEX '(' expression ',' expression ')'"
292 p[0] = '(' + p[3] + ',' + p[5] + ')'
293
295 '''expression : CSC group
296 | SEC group
297 | ACSC group
298 | ASEC group
299 | RE group
300 | IM group
301 | ARG group
302 | SQRT group
303 | CONJ group
304 | REGLOG group'''
305 if p[1] == 'csc': p[0] = '1d0/cos' + p[2]
306 elif p[1] == 'sec': p[0] = '1d0/sin' + p[2]
307 elif p[1] == 'acsc': p[0] = 'asin(1./' + p[2] + ')'
308 elif p[1] == 'asec': p[0] = 'acos(1./' + p[2] + ')'
309 elif p[1] == 're': p[0] = 'dble' + p[2]
310 elif p[1] == 'im': p[0] = 'dimag' + p[2]
311 elif p[1] == 'arg': p[0] = 'arg(DCMPLX'+p[2]+')'
312 elif p[1] == 'cmath.sqrt' or p[1] == 'sqrt': p[0] = 'sqrt' + p[2]
313 elif p[1] == 'complexconjugate': p[0] = 'conjg(DCMPLX' + p[2]+')'
314 elif p[1] == 'reglog': p[0] = 'reglog(DCMPLX' + p[2] +')'
315
317 '''expression : PI'''
318 p[0] = 'pi'
319
321 """A parser for UFO algebraic expressions, outputting
322 Fortran-style code for quadruple precision computation."""
323
324 mp_prefix = check_param_card.ParamCard.mp_prefix
325
326
327
328
330 "expression : NUMBER"
331 p[0] = '%e_16' % float(p[1])
332
334 "expression : VARIABLE"
335
336 p[0] = (self.mp_prefix+p[1]).lower()
337
339 'expression : expression POWER expression'
340 try:
341 p3 = float(p[3].replace('_16',''))
342
343 if p3 == int(p3):
344 p3 = str(int(p3))
345 p[0] = p[1] + "**" + p3
346 else:
347 p[0] = p[1] + "**" + p[3]
348 except Exception:
349 p[0] = p[1] + "**" + p[3]
350
352 "expression : expression IF boolexpression ELSE expression "
353 p[0] = 'MP_CONDIF(%s,CMPLX(%s,KIND=16),CMPLX(%s,KIND=16))' % (p[3], p[1], p[5])
354
356 "expression : expression IF expression ELSE expression "
357 p[0] = 'MP_CONDIF(CMPLX(%s,KIND=16).NE.(0.0e0_16,0.0e0_16),CMPLX(%s,KIND=16),CMPLX(%s,KIND=16))'\
358 %(p[3], p[1], p[5])
359
361 "expression : COND '(' expression ',' expression ',' expression ')'"
362 p[0] = 'MP_COND(CMPLX('+p[3]+',KIND=16),CMPLX('+p[5]+\
363 ',KIND=16),CMPLX('+p[7]+',KIND=16))'
364
366 '''expression : CSC group
367 | SEC group
368 | ACSC group
369 | ASEC group
370 | RE group
371 | IM group
372 | ARG group
373 | SQRT group
374 | CONJ group
375 | REGLOG group'''
376 if p[1] == 'csc': p[0] = '1e0_16/cos' + p[2]
377 elif p[1] == 'sec': p[0] = '1e0_16/sin' + p[2]
378 elif p[1] == 'acsc': p[0] = 'asin(1e0_16/' + p[2] + ')'
379 elif p[1] == 'asec': p[0] = 'acos(1e0_16/' + p[2] + ')'
380 elif p[1] == 're': p[0] = 'real' + p[2]
381 elif p[1] == 'im': p[0] = 'imag' + p[2]
382 elif p[1] == 'arg': p[0] = 'mp_arg(CMPLX(' + p[2] + ',KIND=16))'
383 elif p[1] == 'cmath.sqrt' or p[1] == 'sqrt': p[0] = 'sqrt' + p[2]
384 elif p[1] == 'complexconjugate': p[0] = 'conjg(CMPLX(' + p[2] + ',KIND=16))'
385 elif p[1] == 'reglog': p[0] = 'mp_reglog(CMPLX(' + p[2] +',KIND=16))'
386
388 '''expression : PI'''
389 p[0] = self.mp_prefix+'pi'
390
392 """A parser for UFO algebraic expressions, outputting
393 C++-style code."""
394
395 logical_equiv = {'==':'==',
396 '>=':'>=',
397 '<=':'<=',
398 '!=':'!=',
399 '>':'>',
400 '<':'<',
401 'or':'||',
402 'and':'&&'}
403
404
405
406
408 'expression : NUMBER'
409 p[0] = p[1]
410
411 if float(p[1]) == int(float(p[1])) and float(p[1]) < 1000:
412 p[0] = str(int(float(p[1]))) + '.'
413
415 'expression : VARIABLE'
416 p[0] = p[1]
417
419 "expression : expression IF boolexpression ELSE expression "
420 p[0] = '(%s ? %s : %s)' % (p[3], p[1], p[5])
421
423 "expression : expression IF expression ELSE expression "
424 p[0] = '(%s ? %s : %s)' % (p[3], p[1], p[5])
425
427 "expression : COND '(' expression ',' expression ',' expression ')'"
428 p[0] = 'COND('+p[3]+','+p[5]+','+p[7]+')'
429
431 'expression : expression POWER expression'
432 p1=p[1]
433 p3=p[3]
434 if p[1][0] == '(' and p[1][-1] == ')':
435 p1 = p[1][1:-1]
436 if p[3][0] == '(' and p[3][-1] == ')':
437 p3 = p[3][1:-1]
438 p[0] = 'pow(' + p1 + ',' + p3 + ')'
439
441 "expression : COMPLEX '(' expression ',' expression ')'"
442 p[0] = 'std::complex<double>(' + p[3] + ',' + p[5] + ')'
443
445 '''expression : CSC group
446 | SEC group
447 | ACSC group
448 | ASEC group
449 | RE group
450 | IM group
451 | ARG group
452 | SQRT group
453 | CONJ group
454 | REGLOG group '''
455 if p[1] == 'csc': p[0] = '1./cos' + p[2]
456 elif p[1] == 'sec': p[0] = '1./sin' + p[2]
457 elif p[1] == 'acsc': p[0] = 'asin(1./' + p[2] + ')'
458 elif p[1] == 'asec': p[0] = 'acos(1./' + p[2] + ')'
459 elif p[1] == 're': p[0] = 'real' + p[2]
460 elif p[1] == 'im': p[0] = 'imag' + p[2]
461 elif p[1] == 'arg':p[0] = 'arg' + p[2]
462 elif p[1] == 'cmath.sqrt' or p[1] == 'sqrt': p[0] = 'sqrt' + p[2]
463 elif p[1] == 'complexconjugate': p[0] = 'conj' + p[2]
464 elif p[1] == 'reglog': p[0] = 'reglog' + p[2]
465
467 '''expression : PI'''
468 p[0] = 'M_PI'
469
470
471
472
473 if __name__ == '__main__':
474
475 if len(sys.argv) == 1:
476 print "Please specify a parser: fortran, mpfortran or c++"
477 exit()
478 if sys.argv[1] == "fortran":
479 calc = UFOExpressionParserFortran()
480 elif sys.argv[1] == "mpfortran":
481 calc = UFOExpressionParserMPFortran()
482 elif sys.argv[1] == "c++":
483 calc = UFOExpressionParserCPP()
484 elif sys.argv[1] == "aloha":
485 calc = UFOExpressionParserCPP()
486 else:
487 print "Please specify a parser: fortran, mpfortran or c++"
488 print "You gave", sys.argv[1]
489 exit()
490
491 while 1:
492 try:
493 s = raw_input('calc > ')
494 except EOFError:
495 break
496 if not s: continue
497 print calc.parse(s)
498