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