1 from __future__ import absolute_import
2 from __future__ import print_function
3 import array
4 import copy
5 import math
6 from six.moves import map
7 from six.moves import range
8 from six.moves import zip
9 from functools import reduce
10
11 import madgraph.various.misc as misc
14
16 """ Returns the number of independent coefficients there is in a
17 fully symmetric tensor of rank r """
18 import madgraph.various.misc as misc
19 return sum([((3+ri)*(2+ri)*(1+ri))//6 for ri in range(0,r+1)])
20
22 """ A class to represent a polynomial in the loop momentum (4-vector) q
23 and how the symmetrized coefficients are ordered. The ordering rule
24 correspond to what is presented in Eq. C.15 of arxiv:hep-ph/1405.0301"""
25
27
28 assert rank > -1, "The rank of a q-polynomial should be 0 or positive"
29 self.rank=rank
30 self.init_coef_list()
31
33 """ Creates a list whose elements are arrays being the coefficient
34 indices. We order this list according to the algorithm in
35 get_coef_position. This coef_list can then be used for the function
36 get_coef_at_position()
37 """
38
39 self.coef_list=[None,]*get_number_of_coefs_for_rank(self.rank)
40
41 PNO = Polynomial_naive_ordering(self.rank)
42
43 for coef in PNO.coef_list:
44 self.coef_list[self.get_coef_position(list(coef))]=coef
45
47 """ Returns the canonical position for a coefficient characterized
48 by the value of the indices of the loop momentum q it multiplies,
49 that is for example C_01032 multiplying q_0*q_1*q_0*q_3*q_2.
50 We assume that the explicit construction of the position below is
51 faster than a lookup in a table"""
52
53 fact = math.factorial
54
55 if len(indices_list)==0:
56 return 0
57
58 res = get_number_of_coefs_for_rank(len(indices_list)-1)
59
60 new_indices_list = copy.copy(indices_list)
61 new_indices_list.sort()
62
63 for i, ind in enumerate(new_indices_list):
64 if ind>0:
65 res = res + (fact(ind+i)//(fact(i+1)*fact(ind - 1)))
66
67 return res
68
70 """ Returns the coefficient at position pos in the one dimensional
71 vector """
72 return list(self.coef_list[pos])
73
75 """ A class to represent a polynomial in the loop momentum (4-vector) q"""
76
78
79 assert rank > -1, "The rank of a q-polynomial should be 0 or positive"
80 self.rank=rank
81 self.init_coef_list()
82
84 """ Creates a list whose elements are arrays being the coefficient
85 indices sorted in growing order and the value is their position in a
86 one-dimensional vector. For example the position of the coefficient
87 C_01032 will be placed in the list under array.array('i',(0,0,1,3,2)).
88 """
89 self.coef_list=[]
90 self.coef_list.append(array.array('i',()))
91
92 if self.rank==0:
93 return
94
95 tmp_coef_list=[array.array('i',(0,)),array.array('i',(1,)),
96 array.array('i',(2,)),array.array('i',(3,))]
97 self.coef_list.extend(tmp_coef_list)
98
99 for i in range(1,self.rank):
100 new_tmp_coef_list=[]
101 for coef in tmp_coef_list:
102 for val in range(coef[-1],4):
103 new_coef=copy.copy(coef)
104 new_coef.append(val)
105 new_tmp_coef_list.append(new_coef)
106 tmp_coef_list=new_tmp_coef_list
107 self.coef_list.extend(tmp_coef_list)
108
110 """ Returns the canonical position for a coefficient characterized
111 by the value of the indices of the loop momentum q it multiplies,
112 that is for example C_01032 multiplying q_0*q_1*q_0*q_3*q_2 """
113
114 new_indices_list=copy.copy(indices_list)
115 new_indices_list.sort()
116 try:
117 return self.coef_list.index(array.array('i',new_indices_list))
118 except ValueError:
119 raise PolynomialError("The index %s looked for could not be found"%str(indices_list))
120
122 """ Returns the coefficient at position pos in the one dimensional
123 vector """
124 return list(self.coef_list[pos])
125
127 """ The mother class to output the polynomial subroutines """
128
129 - def __init__(self, max_rank, updater_max_rank=None,
130 coef_format='complex*16', sub_prefix='',
131 proc_prefix='',mp_prefix='',
132 line_split=30):
133
134 self.coef_format=coef_format
135 self.sub_prefix=sub_prefix
136 self.proc_prefix=proc_prefix
137 self.mp_prefix=mp_prefix
138 if updater_max_rank is None:
139 self.updater_max_rank = max_rank
140 else:
141 if updater_max_rank > max_rank:
142 raise PolynomialError("The updater max rank must be at most"+\
143 " equal to the overall max rank")
144 else:
145 self.updater_max_rank = updater_max_rank
146 if coef_format=='complex*16':
147 self.rzero='0.0d0'
148 self.czero='(0.0d0,0.0d0)'
149 elif coef_format=='complex*32':
150 self.rzero='0.0e0_16'
151 self.czero='CMPLX(0.0e0_16,0.0e0_16,KIND=16)'
152 else:
153 self.rzero='0.0e0'
154 self.czero='(0.0e0,0.0e0)'
155 self.line_split=line_split
156 if max_rank<0:
157 raise PolynomialError("The rank of a q-polynomial should be 0 or positive")
158 self.max_rank=max_rank
159 self.pq=Polynomial(max_rank)
160
161
162 self.rep_dict = {'sub_prefix':self.sub_prefix,
163 'proc_prefix':self.proc_prefix,
164 'mp_prefix':self.mp_prefix,
165 'coef_format':self.coef_format}
166
168 """ A daughter class to output the subroutine in the fortran format"""
169
171 """ Writes a fortran90 module that defined polynomial constants objects."""
172
173
174 polynomial_constant_lines = []
175 polynomial_constant_lines.append(
176 """MODULE %sPOLYNOMIAL_CONSTANTS
177 implicit none
178 include 'coef_specs.inc'
179 include 'loop_max_coefs.inc'
180 """%self.sub_prefix)
181
182 polynomial_constant_lines.append(
183 'C Map associating a rank to each coefficient position')
184 polynomial_constant_lines.append(
185 'INTEGER COEFTORANK_MAP(0:LOOPMAXCOEFS-1)')
186 for rank in range(self.max_rank+1):
187 start = get_number_of_coefs_for_rank(rank-1)
188 end = get_number_of_coefs_for_rank(rank)-1
189 polynomial_constant_lines.append(
190 'DATA COEFTORANK_MAP(%(start)d:%(end)d)/%(n_entries)d*%(rank)d/'%
191 {'start': start,'end': end,'n_entries': end-start+1,'rank': rank})
192
193 polynomial_constant_lines.append(
194 '\nC Map defining the number of coefficients for a symmetric tensor of a given rank')
195 polynomial_constant_lines.append(
196 """INTEGER NCOEF_R(0:%(max_rank)d)
197 DATA NCOEF_R/%(ranks)s/"""%{'max_rank':self.max_rank,'ranks':','.join([
198 str(get_number_of_coefs_for_rank(r)) for r in range(0,self.max_rank+1)])})
199 polynomial_constant_lines.append(
200 '\nC Map defining the coef position resulting from the multiplication of two lower rank coefs.')
201 mult_matrix = [[
202 self.pq.get_coef_position(self.pq.get_coef_at_position(coef_a)+
203 self.pq.get_coef_at_position(coef_b))
204 for coef_b in range(0,get_number_of_coefs_for_rank(self.updater_max_rank))]
205 for coef_a in range(0,get_number_of_coefs_for_rank(self.max_rank))]
206
207 polynomial_constant_lines.append(
208 'INTEGER COMB_COEF_POS(0:LOOPMAXCOEFS-1,0:%(max_updater_rank)d)'\
209 %{'max_updater_rank':(get_number_of_coefs_for_rank(self.updater_max_rank)-1)})
210
211 for j, line in enumerate(mult_matrix):
212 chunk_size = 20
213 for k in range(0, len(line), chunk_size):
214 polynomial_constant_lines.append(
215 "DATA COMB_COEF_POS(%3r,%3r:%3r) /%s/" % \
216 (j, k, min(k + chunk_size, len(line))-1,
217 ','.join(["%3r" % i for i in line[k:k + chunk_size]])))
218
219 polynomial_constant_lines.append(
220 "\nEND MODULE %sPOLYNOMIAL_CONSTANTS\n"%self.sub_prefix)
221
222 return '\n'.join(polynomial_constant_lines)
223
224
226 """ Returns a fortran subroutine which fills in the array of integral reduction
227 coefficients following MadLoop standards using pjfry++ coefficients."""
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242 def format_power(pow):
243 b, e = pow
244
245 if e == 1:
246 return str(b)
247 else:
248 return "%s^%d" % (b, e)
249
250
251 def get_coef_position(indices_list):
252 new_indices_list=copy.copy(indices_list)
253 new_indices_list.sort()
254 r=len(new_indices_list)
255 if r == 0:
256 pos=0
257 else:
258 pos=get_number_of_coefs_for_rank(r-1)
259 for i,mu in enumerate(new_indices_list):
260 num = mu
261 den = 1
262 if mu > 0 and i > 0:
263 for j in range(2,i+2):
264 num *= (mu+j-1)
265 den *= j
266 pos += num/den
267 return pos
268
269 lines = []
270 lines.append(
271 """SUBROUTINE %(sub_prefix)sCONVERT_PJFRY_COEFFS(RANK,PJCOEFS,TIRCOEFS)
272 C GLOABLE VARIABLES
273 include 'coef_specs.inc'
274 include 'loop_max_coefs.inc'
275 C ARGUMENTS
276 INTEGER RANK
277 %(coef_format)s PJCOEFS(0:LOOPMAXCOEFS-1,3)
278 %(coef_format)s TIRCOEFS(0:LOOPMAXCOEFS-1,3)"""
279 %{'sub_prefix':self.sub_prefix,'coef_format':self.coef_format})
280
281 for R in range(self.max_rank+1):
282 Ncoeff=((3+R)*(2+R)*(1+R))/6
283 if R == 0:
284 offset=0
285 else:
286 offset=get_number_of_coefs_for_rank(R-1)
287 for i in range(offset,Ncoeff+offset):
288 indices_list=self.pq.get_coef_at_position(i)
289 sindices = ["q(%d)" % i for i in indices_list]
290 coeff_list = []
291 for j in range(4):
292 qvalue = "q(%d)"%j
293 qpow = sindices.count(qvalue)
294 if qpow > 0:
295 coeff_list.append(format_power([qvalue,qpow]))
296
297 if not coeff_list:
298 coeff_str = "1"
299 else:
300 coeff_str = "*".join(coeff_list)
301
302 pjpos = get_coef_position(indices_list)
303 lines.append("c Reduction Coefficient %s"%coeff_str)
304 lines.append('TIRCOEFS(%d,1:3)=PJCOEFS(%d,1:3)'%(i,pjpos))
305 lines.append('IF(RANK.LE.%d)RETURN'%R)
306
307 lines.append('end')
308
309 return '\n'.join(lines)
310
312 """ Returns a fortran subroutine which fills in the array of integral reduction
313 coefficients following MadLoop standards using IREGI coefficients."""
314
315
316
317
318
319
320
321
322 def format_power(pow):
323 b, e = pow
324
325 if e == 1:
326 return str(b)
327 else:
328 return "%s^%d" % (b, e)
329
330 lines = []
331 lines.append(
332 """SUBROUTINE %(sub_prefix)sCONVERT_IREGI_COEFFS(RANK,IREGICOEFS,TIRCOEFS)
333 C GLOABLE VARIABLES
334 include 'coef_specs.inc'
335 include 'loop_max_coefs.inc'
336 C ARGUMENTS
337 INTEGER RANK
338 %(coef_format)s IREGICOEFS(0:LOOPMAXCOEFS-1,3)
339 %(coef_format)s TIRCOEFS(0:LOOPMAXCOEFS-1,3)"""
340 %{'sub_prefix':self.sub_prefix,'coef_format':self.coef_format})
341
342 iregi_gen = FromIREGIFortranCodeGenerator(self.max_rank)
343 for R in range(self.max_rank+1):
344 Ncoeff=((3+R)*(2+R)*(1+R))//6
345 if R == 0:
346 offset=0
347 else:
348 offset=get_number_of_coefs_for_rank(R-1)
349
350 for i in range(offset,Ncoeff+offset):
351 indices_list=self.pq.get_coef_at_position(i)
352 sindices = ["q(%d)" % i for i in indices_list]
353 coeff_list = []
354 for j in range(4):
355 qvalue = "q(%d)"%j
356 qpow = sindices.count(qvalue)
357 if qpow > 0:
358 coeff_list.append(format_power([qvalue,qpow]))
359
360 if not coeff_list:
361 coeff_str = "1"
362 else:
363 coeff_str = "*".join(coeff_list)
364
365 iregipos = iregi_gen.get_coef_position(indices_list)
366 lines.append("c Reduction Coefficient %s"%coeff_str)
367 lines.append('TIRCOEFS(%d,1:3)=IREGICOEFS(%d,1:3)'%(i,iregipos))
368 lines.append('IF(RANK.LE.%d)RETURN'%R)
369 lines.append('end')
370
371 return '\n'.join(lines)
372
374 """ Returns a list of tuples of the form:
375 [ (COLLIER_ind0, COLLIER_ind1, COLLIER_ind2, COLLIER_ind3), ]
376 where the position in the list is the coef_ID in MadLoop ordering.
377 """
378 res = []
379 for coef_pos in range(0,get_number_of_coefs_for_rank(self.pq.rank)):
380 indices_list = self.pq.get_coef_at_position(coef_pos)
381 res.append((indices_list.count(0),
382 indices_list.count(1),
383 indices_list.count(2),
384 indices_list.count(3)))
385 return res
386
388 """ Returns a fortran subroutine which fills in the array of tensorial
389 coefficients following golem95 standards using MadLoop coefficients."""
390
391 subroutines = []
392
393
394 d = 4
395 golem_max_rank = 6
396
397
398
399 block_info = {}
400 for R in range(1,self.max_rank+1):
401 for k in range(1,min(R,d)+1):
402 LHS, RHS, lst, dic = \
403 FromGolem95FortranCodeGenerator.generate_equations(R, k)
404 block_info[(R,k)] = (lst, dic)
405
406
407 def format_power(pow):
408 b, e = pow
409
410 if e == 1:
411 return str(b)
412 else:
413 return "%s^%d" % (b, e)
414
415
416 for R in range(golem_max_rank+1):
417
418 lines=[]
419
420 if R==0:
421 lines.append(
422 """SUBROUTINE %(sub_prefix)sFILL_GOLEM_COEFFS_0(ML_COEFS,GOLEM_COEFS)
423 use precision_golem, only: ki
424 include 'coef_specs.inc'
425 include 'loop_max_coefs.inc'
426 %(coef_format)s ML_COEFS(0:LOOPMAXCOEFS-1)
427 complex(ki) GOLEM_COEFS"""
428 %{'sub_prefix':self.sub_prefix,'coef_format':self.coef_format})
429 lines.append("GOLEM_COEFS=ML_COEFS(0)")
430 lines.append("end")
431 subroutines.append('\n'.join(lines))
432 continue
433
434
435 lines.append(
436 """SUBROUTINE %(sub_prefix)sFILL_GOLEM_COEFFS_%(rank)d(ML_COEFS,GOLEM_COEFS)
437 use tens_rec, only: coeff_type_%(rank)d
438 include 'coef_specs.inc'
439 include 'loop_max_coefs.inc'
440 %(coef_format)s ML_COEFS(0:LOOPMAXCOEFS-1)
441 type(coeff_type_%(rank)d) GOLEM_COEFS"""
442 %{'sub_prefix':self.sub_prefix,'rank':R,
443 'coef_format':self.coef_format})
444
445 if R > self.max_rank:
446 lines.append('C Dummy routine for %(sub_prefix)sFILL_GOLEM_COEFS_%(rank)d'\
447 %{'sub_prefix':self.sub_prefix,'rank':R,
448 'coef_format':self.coef_format})
449 lines.append("STOP 'ERROR: %d > %d'"%(R,self.max_rank))
450 lines.append('end')
451 subroutines.append('\n'.join(lines))
452 continue
453
454
455 lines.append("c Constant coefficient ")
456 lines.append("GOLEM_COEFS%%c0=ML_COEFS(%d)"\
457 %self.pq.get_coef_position([]))
458
459
460 for k in range(1,min(R,d)+1):
461 lst, dic = block_info[(R,k)]
462 dim = len(lst)
463 lab = 0
464 for indices in FromGolem95FortranCodeGenerator.select(list(range(d)), k):
465 lab += 1
466 sindices = ["q(%d)" % i for i in indices]
467 for i in range(dim):
468 coeff_str = "*".join(map(format_power,list(zip(sindices, lst[i]))))
469 ML_indices = sum(
470 [[ind]*lst[i][j] for j, ind in enumerate(indices)],[])
471 ML_coef_pos = self.pq.get_coef_position(ML_indices)
472 ML_sign_convention = ' ' if len(ML_indices)%2==0 else '-'
473 lines.append("c Coefficient %s"%coeff_str)
474 lines.append("GOLEM_COEFS%%c%d(%d,%d)=%sML_COEFS(%d)"\
475 % (k, lab, i+1, ML_sign_convention, ML_coef_pos))
476
477 subroutines.append('\n'.join(lines+['end']))
478
479 return '\n\n'.join(subroutines)
480
482 """ Give out the subroutine to update a polynomial of rank r_1 with
483 one of rank r_2 """
484
485
486
487
488
489
490
491
492
493
494
495
496 lines=[]
497
498
499 lines.append(
500 """SUBROUTINE %(sub_prefix)sUPDATE_WL_%(r_1)d_%(r_2)d(A,LCUT_SIZE,B,IN_SIZE,OUT_SIZE,OUT)
501 USE %(proc_prefix)sPOLYNOMIAL_CONSTANTS
502 implicit none
503 INTEGER I,J,K,L,M
504 %(coef_format)s A(MAXLWFSIZE,0:LOOPMAXCOEFS-1,MAXLWFSIZE)
505 %(coef_format)s B(MAXLWFSIZE,0:VERTEXMAXCOEFS-1,MAXLWFSIZE)
506 %(coef_format)s OUT(MAXLWFSIZE,0:LOOPMAXCOEFS-1,MAXLWFSIZE)
507 INTEGER LCUT_SIZE,IN_SIZE,OUT_SIZE
508 INTEGER NEW_POSITION
509 %(coef_format)s UPDATER_COEF
510 """%{'sub_prefix':self.sub_prefix,'proc_prefix':self.proc_prefix,
511 'r_1':r_1,'r_2':r_2,'coef_format':self.coef_format})
512
513
514 lines.append("C Welcome to the computational heart of MadLoop...")
515 if loop_over_vertex_coefs_first:
516 lines.append("OUT(:,:,:)=%s"%self.czero)
517 lines.append(
518 """DO J=1,OUT_SIZE
519 DO M=0,%d
520 DO K=1,IN_SIZE
521 UPDATER_COEF = B(J,M,K)
522 IF (UPDATER_COEF.EQ.%s) CYCLE
523 DO L=0,%d
524 NEW_POSITION = COMB_COEF_POS(L,M)
525 DO I=1,LCUT_SIZE
526 OUT(J,NEW_POSITION,I)=OUT(J,NEW_POSITION,I) + A(K,L,I)*UPDATER_COEF
527 ENDDO
528 ENDDO
529 ENDDO
530 ENDDO
531 ENDDO
532 """%(get_number_of_coefs_for_rank(r_2)-1,
533 self.czero,
534 get_number_of_coefs_for_rank(r_1)-1))
535 else:
536 lines.append("OUT(:,:,:)=%s"%self.czero)
537 lines.append(
538 """DO I=1,LCUT_SIZE
539 DO L=0,%d
540 DO K=1,IN_SIZE
541 UPDATER_COEF = A(K,L,I)
542 IF (UPDATER_COEF.EQ.%s) CYCLE
543 DO M=0,%d
544 NEW_POSITION = COMB_COEF_POS(L,M)
545 DO J=1,OUT_SIZE
546 OUT(J,NEW_POSITION,I)=OUT(J,NEW_POSITION,I) + UPDATER_COEF*B(J,M,K)
547 ENDDO
548 ENDDO
549 ENDDO
550 ENDDO
551 ENDDO
552 """%(get_number_of_coefs_for_rank(r_1)-1,
553 self.czero,
554 get_number_of_coefs_for_rank(r_2)-1))
555
556 lines.append("END")
557
558 return '\n'.join(lines)
559
561 """ Give out the subroutine to update a polynomial of rank r_1 with
562 one of rank r_2 """
563
564
565
566
567
568
569
570
571
572
573 lines=[]
574
575
576 lines.append(
577 """SUBROUTINE %(sub_prefix)sUPDATE_WL_%(r_1)d_%(r_2)d(A,LCUT_SIZE,B,IN_SIZE,OUT_SIZE,OUT)
578 USE %(proc_prefix)sPOLYNOMIAL_CONSTANTS
579 INTEGER I,J,K
580 %(coef_format)s A(MAXLWFSIZE,0:LOOPMAXCOEFS-1,MAXLWFSIZE)
581 %(coef_format)s B(MAXLWFSIZE,0:VERTEXMAXCOEFS-1,MAXLWFSIZE)
582 %(coef_format)s OUT(MAXLWFSIZE,0:LOOPMAXCOEFS-1,MAXLWFSIZE)
583 INTEGER LCUT_SIZE,IN_SIZE,OUT_SIZE
584 """%{'sub_prefix':self.sub_prefix,'proc_prefix':self.proc_prefix,
585 'r_1':r_1,'r_2':r_2,'coef_format':self.coef_format})
586
587
588 lines.append("DO I=1,LCUT_SIZE")
589 lines.append(" DO J=1,OUT_SIZE")
590 lines.append(" DO K=0,%d"%(get_number_of_coefs_for_rank(r_2+r_1)-1))
591 lines.append(" OUT(J,K,I)=%s"%self.czero)
592 lines.append(" ENDDO")
593 lines.append(" DO K=1,IN_SIZE")
594
595
596
597
598
599
600 coef_expressions={}
601 for coef_a in range(0,get_number_of_coefs_for_rank(r_1)):
602 for coef_b in range(0,get_number_of_coefs_for_rank(r_2)):
603 ind_list=self.pq.get_coef_at_position(coef_a)+\
604 self.pq.get_coef_at_position(coef_b)
605 new_term="A(K,%d,I)*B(J,%d,K)"%(coef_a,coef_b)
606 new_position=self.pq.get_coef_position(ind_list)
607 try:
608 coef_expressions[new_position].append(new_term)
609 except KeyError:
610 coef_expressions[new_position]=[new_term,]
611 keys = sorted(list(coef_expressions.keys()))
612 for coef in keys:
613 value = coef_expressions[coef]
614 split=0
615 while split<len(value):
616 lines.append("OUT(J,%d,I)=OUT(J,%d,I)+"%(coef,coef)+\
617 '+'.join(value[split:split+self.line_split]))
618 split=split+self.line_split
619
620
621 lines.append(" ENDDO")
622 lines.append(" ENDDO")
623 lines.append("ENDDO")
624 lines.append("END")
625
626
627 return '\n'.join(lines)
628
630 """ Give out the subroutine to evaluate a polynomial of a rank up to
631 the maximal one specified when initializing the FortranPolynomialRoutines
632 object. """
633 lines=[]
634
635
636 lines.append("""SUBROUTINE %(sub_prefix)sEVAL_POLY(C,R,Q,OUT)
637 USE %(proc_prefix)sPOLYNOMIAL_CONSTANTS
638 %(coef_format)s C(0:LOOPMAXCOEFS-1)
639 INTEGER R
640 %(coef_format)s Q(0:3)
641 %(coef_format)s OUT
642 """%self.rep_dict)
643
644
645 lines.append("OUT=C(0)")
646
647 for r in range(1,self.max_rank+1):
648 lines.append("IF (R.GE.%d) then"%r)
649 terms=[]
650 for coef_num in range(get_number_of_coefs_for_rank(r-1)
651 ,get_number_of_coefs_for_rank(r)):
652 coef_inds=self.pq.get_coef_at_position(coef_num)
653 terms.append('*'.join(['C(%d)'%coef_num,]+
654 ['Q(%d)'%ind for ind in coef_inds]))
655 split=0
656 while split<len(terms):
657 lines.append("OUT=OUT+"+\
658 '+'.join(terms[split:split+self.line_split]))
659 split=split+self.line_split
660 lines.append("ENDIF")
661 lines.append("END")
662
663 return '\n'.join(lines)
664
666 """ Give out the subroutine to merge the components of a final loop
667 wavefunction of a loop to create the coefficients of the polynomial
668 representing the numerator, while multiplying each of them by 'const'."""
669 lines=[]
670
671
672 lines.append(
673 """SUBROUTINE %(sub_prefix)sMERGE_WL(WL,R,LCUT_SIZE,CONST,OUT)
674 USE %(proc_prefix)sPOLYNOMIAL_CONSTANTS
675 INTEGER I,J
676 %(coef_format)s WL(MAXLWFSIZE,0:LOOPMAXCOEFS-1,MAXLWFSIZE)
677 INTEGER R,LCUT_SIZE
678 %(coef_format)s CONST
679 %(coef_format)s OUT(0:LOOPMAXCOEFS-1)
680 """%self.rep_dict)
681
682
683 lines.append("DO I=1,LCUT_SIZE")
684 lines.append(" DO J=0,NCOEF_R(R)-1")
685 lines.append(" OUT(J)=OUT(J)+WL(I,J,I)*CONST")
686 lines.append(" ENDDO")
687 lines.append("ENDDO")
688 lines.append("END")
689
690 return '\n'.join(lines)
691
693 """ Give out the subroutine to simply add together the coefficients
694 of two loop polynomials of rank R1 and R2 storing the result in the
695 first polynomial given in the arguments."""
696 lines=[]
697
698
699 lines.append("""SUBROUTINE %(sub_prefix)sADD_COEFS(A,RA,B,RB)
700 USE %(proc_prefix)sPOLYNOMIAL_CONSTANTS
701 INTEGER I
702 %(coef_format)s A(0:LOOPMAXCOEFS-1),B(0:LOOPMAXCOEFS-1)
703 INTEGER RA,RB
704 """%self.rep_dict)
705
706
707 lines.append("DO I=0,NCOEF_R(RB)-1")
708 lines.append(" A(I)=A(I)+B(I)")
709 lines.append("ENDDO")
710 lines.append("END")
711
712 return '\n'.join(lines)
713
715 """ Back up of the class Polynomial, which uses the same coefficeints orders with IREGI.
716 It is useful in the case that the order of MadLoop coefficients changes in the future."""
717
719
720 assert rank > -1, "The rank of a q-polynomial should be 0 or positive"
721 self.rank=rank
722 self.init_coef_list()
723
725 """ Creates a list whose elements are arrays being the coefficient
726 indices sorted in growing order and the value is their position in a
727 one-dimensional vector. For example the position of the coefficient
728 C_01032 will be placed in the list under array.array('i',(0,0,1,3,2)).
729 """
730 self.coef_list=[]
731 self.coef_list.append(array.array('i',()))
732
733 if self.rank==0:
734 return
735
736 tmp_coef_list=[array.array('i',(0,)),array.array('i',(1,)),
737 array.array('i',(2,)),array.array('i',(3,))]
738 self.coef_list.extend(tmp_coef_list)
739
740 for i in range(1,self.rank):
741 new_tmp_coef_list=[]
742 for coef in tmp_coef_list:
743 for val in range(coef[-1],4):
744 new_coef=copy.copy(coef)
745 new_coef.append(val)
746 new_tmp_coef_list.append(new_coef)
747 tmp_coef_list=new_tmp_coef_list
748 self.coef_list.extend(tmp_coef_list)
749
751 """ Returns the canonical position for a coefficient characterized
752 by the value of the indices of the loop momentum q it multiplies,
753 that is for example C_01032 multiplying q_0*q_1*q_0*q_3*q_2 """
754
755 new_indices_list=copy.copy(indices_list)
756 new_indices_list.sort()
757 try:
758 return self.coef_list.index(array.array('i',new_indices_list))
759 except ValueError:
760 raise PolynomialError("The index %s looked for could not be found"%str(indices_list))
761
763 """ Returns the coefficient at position pos in the one dimensional
764 vector """
765 return list(self.coef_list[pos])
766
769 """ Just a container class with helper functions taken from the script
770 tens.py of golem which generates most of the golem95 tens_rec.f fortran
771 code."""
772
773 PRIMES = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29,
774 31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
775 73, 79, 83, 89, 97, 101, 103, 107, 109, 113,
776 127, 131, 137, 139, 149, 151, 157, 163, 167, 173,
777 179, 181, 191, 193, 197, 199, 211, 223, 227, 229,
778 233, 239, 241, 251, 257, 263, 269, 271, 277, 281,
779 283, 293, 307, 311, 313, 317, 331, 337, 347, 349,
780 353, 359, 367, 373, 379, 383, 389, 397, 401, 409,
781 419, 421, 431, 433, 439, 443, 449, 457, 461, 463,
782 467, 479, 487, 491, 499, 503, 509, 521, 523, 541,
783 547, 557, 563, 569, 571, 577, 587, 593, 599, 601,
784 607, 613, 617, 619, 631, 641, 643, 647, 653, 659,
785 661, 673, 677, 683, 691, 701, 709, 719, 727, 733,
786 739, 743, 751, 757, 761, 769, 773, 787, 797, 809,
787 811, 821, 823, 827, 829, 839, 853, 857, 859, 863,
788 877, 881, 883, 887, 907, 911, 919, 929, 937, 941,
789 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013,
790 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069,
791 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151,
792 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223,
793 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291,
794 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373]
795
796 @classmethod
798 """
799 Calculates the binomial coefficient (n atop k).
800 """
801 if k < 0 or k > n:
802 return 0
803 else:
804 num = 1
805 den = 1
806 for i in range(1, k+1):
807 num *= n-i+1
808 den *= i
809 return num/den
810
811 @classmethod
813 """
814 Generates a mapping from tensor components \hat{C}(a_1, ..., a_k)
815 into a one dimensional array.
816
817 PARAMETER
818
819 R -- rank
820 k -- number of non-zero components of q
821
822 RETURN
823
824 (lst, dic)
825
826 lst -- list of (a_1, ..., a_k)
827 dic -- mapping from (a_1, ..., a_k) -> int
828
829 lst[dic[X]] = X if X in dic
830 """
831
832 def rec_generator(k, R):
833 if k == 0:
834 yield []
835 elif k <= R:
836 for a_1 in range(1, R - (k - 1) + 1):
837 if k > 1:
838 for tail in rec_generator(k - 1, R - a_1):
839 yield [a_1] + tail
840 else:
841 yield [a_1]
842
843 lst = []
844 dic = {}
845 i = 0
846 for indices in rec_generator(k, R):
847 t = tuple(indices)
848 lst.append(t)
849 dic[t] = i
850 i += 1
851
852 assert i == cls.combinat(R, k), \
853 "len(%s) != %d, R=%d,k=%d" % (lst,cls.combinat(R, k),R,k)
854 return lst, dic
855
856 @classmethod
858 """
859 Generates a set of equations for a given number of non-zero
860 components and fixed maximum rank.
861
862 PARAMETER
863
864 R -- rank
865 k -- number of non-zero components of q
866
867 RETURN
868
869 (LHS, RHS)
870
871 LHS -- a matrix (i.e. list of lists) of coefficients
872 RHS -- a list of values of q
873 """
874
875 lst, dic = cls.generate_mapping(R, k)
876 l = len(lst)
877 LHS = []
878 RHS = []
879 for num_eq in range(l):
880 q = [cls.PRIMES[i] for i in lst[num_eq]]
881 coeffs = [
882 reduce(lambda x,y: x*y, [b_e[0]**b_e[1] for b_e in zip(q, term)], 1)
883 for term in lst]
884 LHS.append(coeffs)
885 RHS.append(q)
886
887 return LHS, RHS, lst, dic
888
889 @classmethod
891 """
892 Iterator over all selections of k elements from a given list.
893
894 PARAMETER
895
896 items -- list of elements to choose from (no repetitions)
897 k -- number of elements to select.
898 """
899 n = len(items)
900
901
902 if k == n:
903 yield items[:]
904 elif k == 0:
905 yield []
906 elif 0 < k and k < n:
907 head = items[0:1]
908 tail = items[1:]
909 for result in cls.select(tail, k-1):
910 yield head + result
911 for result in cls.select(tail, k):
912 yield result
913
914 if __name__ == '__main__':
915 """I test here the write_golem95_mapping function"""
916
917 P=Polynomial(7)
918 print("Coef (6,0,0,0) is at pos %s"%P.get_coef_position([0,0,0,0,0,0]))
919 print("Coef (1,1,2,2) is at pos %s"%P.get_coef_position([0,1,2,2,3,3]))
920 print("Coef (7,0,0,0) is at pos %s"%P.get_coef_position([0,0,0,0,0,0,0]))
921 print("Coef (1,2,2,2) is at pos %s"%P.get_coef_position([0,1,1,2,2,3,3]))
922
923 sys.exit(0)
924
925 max_rank=6
926 FPR=FortranPolynomialRoutines(max_rank)
927 print("Output of write_golem95_mapping function for max_rank=%d:\n\n"%max_rank)
928
929 import os
930 import sys
931 root_path = os.path.split(os.path.dirname(os.path.realpath( __file__ )))[0]
932 sys.path.insert(0, os.path.join(root_path,os.path.pardir))
933 import madgraph.iolibs.file_writers as writers
934 FWriter = writers.FortranWriter("GOLEM95_interface.f")
935 FWriter.writelines(FPR.write_golem95_mapping())
936