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