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 fortran subroutine which fills in the array of tensorial
367 coefficients following golem95 standards using MadLoop coefficients."""
368
369 subroutines = []
370
371
372 d = 4
373 golem_max_rank = 6
374
375
376
377 block_info = {}
378 for R in range(1,self.max_rank+1):
379 for k in range(1,min(R,d)+1):
380 LHS, RHS, lst, dic = \
381 FromGolem95FortranCodeGenerator.generate_equations(R, k)
382 block_info[(R,k)] = (lst, dic)
383
384
385 def format_power(pow):
386 b, e = pow
387
388 if e == 1:
389 return str(b)
390 else:
391 return "%s^%d" % (b, e)
392
393
394 for R in range(golem_max_rank+1):
395
396 lines=[]
397
398 if R==0:
399 lines.append(
400 """SUBROUTINE %(sub_prefix)sFILL_GOLEM_COEFFS_0(ML_COEFS,GOLEM_COEFS)
401 use precision_golem, only: ki
402 include 'coef_specs.inc'
403 include 'loop_max_coefs.inc'
404 %(coef_format)s ML_COEFS(0:LOOPMAXCOEFS-1)
405 complex(ki) GOLEM_COEFS"""
406 %{'sub_prefix':self.sub_prefix,'coef_format':self.coef_format})
407 lines.append("GOLEM_COEFS=ML_COEFS(0)")
408 lines.append("end")
409 subroutines.append('\n'.join(lines))
410 continue
411
412
413 lines.append(
414 """SUBROUTINE %(sub_prefix)sFILL_GOLEM_COEFFS_%(rank)d(ML_COEFS,GOLEM_COEFS)
415 use tens_rec, only: coeff_type_%(rank)d
416 include 'coef_specs.inc'
417 include 'loop_max_coefs.inc'
418 %(coef_format)s ML_COEFS(0:LOOPMAXCOEFS-1)
419 type(coeff_type_%(rank)d) GOLEM_COEFS"""
420 %{'sub_prefix':self.sub_prefix,'rank':R,
421 'coef_format':self.coef_format})
422
423 if R > self.max_rank:
424 lines.append('C Dummy routine for %(sub_prefix)sFILL_GOLEM_COEFS_%(rank)d'\
425 %{'sub_prefix':self.sub_prefix,'rank':R,
426 'coef_format':self.coef_format})
427 lines.append("STOP 'ERROR: %d > %d'"%(R,self.max_rank))
428 lines.append('end')
429 subroutines.append('\n'.join(lines))
430 continue
431
432
433 lines.append("c Constant coefficient ")
434 lines.append("GOLEM_COEFS%%c0=ML_COEFS(%d)"\
435 %self.pq.get_coef_position([]))
436
437
438 for k in range(1,min(R,d)+1):
439 lst, dic = block_info[(R,k)]
440 dim = len(lst)
441 lab = 0
442 for indices in FromGolem95FortranCodeGenerator.select(range(d), k):
443 lab += 1
444 sindices = map(lambda i: "q(%d)" % i, indices)
445 for i in range(dim):
446 coeff_str = "*".join(map(format_power,zip(sindices, lst[i])))
447 ML_indices = sum(
448 [[ind]*lst[i][j] for j, ind in enumerate(indices)],[])
449 ML_coef_pos = self.pq.get_coef_position(ML_indices)
450 ML_sign_convention = ' ' if len(ML_indices)%2==0 else '-'
451 lines.append("c Coefficient %s"%coeff_str)
452 lines.append("GOLEM_COEFS%%c%d(%d,%d)=%sML_COEFS(%d)"\
453 % (k, lab, i+1, ML_sign_convention, ML_coef_pos))
454
455 subroutines.append('\n'.join(lines+['end']))
456
457 return '\n\n'.join(subroutines)
458
460 """ Give out the subroutine to update a polynomial of rank r_1 with
461 one of rank r_2 """
462
463
464
465
466
467
468
469
470
471
472
473
474 lines=[]
475
476
477 lines.append(
478 """SUBROUTINE %(sub_prefix)sUPDATE_WL_%(r_1)d_%(r_2)d(A,LCUT_SIZE,B,IN_SIZE,OUT_SIZE,OUT)
479 USE %(proc_prefix)sPOLYNOMIAL_CONSTANTS
480 implicit none
481 INTEGER I,J,K,L,M
482 %(coef_format)s A(MAXLWFSIZE,0:LOOPMAXCOEFS-1,MAXLWFSIZE)
483 %(coef_format)s B(MAXLWFSIZE,0:VERTEXMAXCOEFS-1,MAXLWFSIZE)
484 %(coef_format)s OUT(MAXLWFSIZE,0:LOOPMAXCOEFS-1,MAXLWFSIZE)
485 INTEGER LCUT_SIZE,IN_SIZE,OUT_SIZE
486 INTEGER NEW_POSITION
487 %(coef_format)s UPDATER_COEF
488 """%{'sub_prefix':self.sub_prefix,'proc_prefix':self.proc_prefix,
489 'r_1':r_1,'r_2':r_2,'coef_format':self.coef_format})
490
491
492 lines.append("C Welcome to the computational heart of MadLoop...")
493 if loop_over_vertex_coefs_first:
494 lines.append("OUT(:,:,:)=%s"%self.czero)
495 lines.append(
496 """DO J=1,OUT_SIZE
497 DO M=0,%d
498 DO K=1,IN_SIZE
499 UPDATER_COEF = B(J,M,K)
500 IF (UPDATER_COEF.EQ.%s) CYCLE
501 DO L=0,%d
502 NEW_POSITION = COMB_COEF_POS(L,M)
503 DO I=1,LCUT_SIZE
504 OUT(J,NEW_POSITION,I)=OUT(J,NEW_POSITION,I) + A(K,L,I)*UPDATER_COEF
505 ENDDO
506 ENDDO
507 ENDDO
508 ENDDO
509 ENDDO
510 """%(get_number_of_coefs_for_rank(r_2)-1,
511 self.czero,
512 get_number_of_coefs_for_rank(r_1)-1))
513 else:
514 lines.append("OUT(:,:,:)=%s"%self.czero)
515 lines.append(
516 """DO I=1,LCUT_SIZE
517 DO L=0,%d
518 DO K=1,IN_SIZE
519 UPDATER_COEF = A(K,L,I)
520 IF (UPDATER_COEF.EQ.%s) CYCLE
521 DO M=0,%d
522 NEW_POSITION = COMB_COEF_POS(L,M)
523 DO J=1,OUT_SIZE
524 OUT(J,NEW_POSITION,I)=OUT(J,NEW_POSITION,I) + UPDATER_COEF*B(J,M,K)
525 ENDDO
526 ENDDO
527 ENDDO
528 ENDDO
529 ENDDO
530 """%(get_number_of_coefs_for_rank(r_1)-1,
531 self.czero,
532 get_number_of_coefs_for_rank(r_2)-1))
533
534 lines.append("END")
535
536 return '\n'.join(lines)
537
539 """ Give out the subroutine to update a polynomial of rank r_1 with
540 one of rank r_2 """
541
542
543
544
545
546
547
548
549
550
551 lines=[]
552
553
554 lines.append(
555 """SUBROUTINE %(sub_prefix)sUPDATE_WL_%(r_1)d_%(r_2)d(A,LCUT_SIZE,B,IN_SIZE,OUT_SIZE,OUT)
556 USE %(proc_prefix)sPOLYNOMIAL_CONSTANTS
557 INTEGER I,J,K
558 %(coef_format)s A(MAXLWFSIZE,0:LOOPMAXCOEFS-1,MAXLWFSIZE)
559 %(coef_format)s B(MAXLWFSIZE,0:VERTEXMAXCOEFS-1,MAXLWFSIZE)
560 %(coef_format)s OUT(MAXLWFSIZE,0:LOOPMAXCOEFS-1,MAXLWFSIZE)
561 INTEGER LCUT_SIZE,IN_SIZE,OUT_SIZE
562 """%{'sub_prefix':self.sub_prefix,'proc_prefix':self.proc_prefix,
563 'r_1':r_1,'r_2':r_2,'coef_format':self.coef_format})
564
565
566 lines.append("DO I=1,LCUT_SIZE")
567 lines.append(" DO J=1,OUT_SIZE")
568 lines.append(" DO K=0,%d"%(get_number_of_coefs_for_rank(r_2+r_1)-1))
569 lines.append(" OUT(J,K,I)=%s"%self.czero)
570 lines.append(" ENDDO")
571 lines.append(" DO K=1,IN_SIZE")
572
573
574
575
576
577
578 coef_expressions={}
579 for coef_a in range(0,get_number_of_coefs_for_rank(r_1)):
580 for coef_b in range(0,get_number_of_coefs_for_rank(r_2)):
581 ind_list=self.pq.get_coef_at_position(coef_a)+\
582 self.pq.get_coef_at_position(coef_b)
583 new_term="A(K,%d,I)*B(J,%d,K)"%(coef_a,coef_b)
584 new_position=self.pq.get_coef_position(ind_list)
585 try:
586 coef_expressions[new_position].append(new_term)
587 except KeyError:
588 coef_expressions[new_position]=[new_term,]
589 for coef, value in coef_expressions.items():
590 split=0
591 while split<len(value):
592 lines.append("OUT(J,%d,I)=OUT(J,%d,I)+"%(coef,coef)+\
593 '+'.join(value[split:split+self.line_split]))
594 split=split+self.line_split
595
596
597 lines.append(" ENDDO")
598 lines.append(" ENDDO")
599 lines.append("ENDDO")
600 lines.append("END")
601
602
603 return '\n'.join(lines)
604
606 """ Give out the subroutine to evaluate a polynomial of a rank up to
607 the maximal one specified when initializing the FortranPolynomialRoutines
608 object. """
609 lines=[]
610
611
612 lines.append("""SUBROUTINE %(sub_prefix)sEVAL_POLY(C,R,Q,OUT)
613 USE %(proc_prefix)sPOLYNOMIAL_CONSTANTS
614 %(coef_format)s C(0:LOOPMAXCOEFS-1)
615 INTEGER R
616 %(coef_format)s Q(0:3)
617 %(coef_format)s OUT
618 """%self.rep_dict)
619
620
621 lines.append("OUT=C(0)")
622
623 for r in range(1,self.max_rank+1):
624 lines.append("IF (R.GE.%d) then"%r)
625 terms=[]
626 for coef_num in range(get_number_of_coefs_for_rank(r-1)
627 ,get_number_of_coefs_for_rank(r)):
628 coef_inds=self.pq.get_coef_at_position(coef_num)
629 terms.append('*'.join(['C(%d)'%coef_num,]+
630 ['Q(%d)'%ind for ind in coef_inds]))
631 split=0
632 while split<len(terms):
633 lines.append("OUT=OUT+"+\
634 '+'.join(terms[split:split+self.line_split]))
635 split=split+self.line_split
636 lines.append("ENDIF")
637 lines.append("END")
638
639 return '\n'.join(lines)
640
642 """ Give out the subroutine to merge the components of a final loop
643 wavefunction of a loop to create the coefficients of the polynomial
644 representing the numerator, while multiplying each of them by 'const'."""
645 lines=[]
646
647
648 lines.append(
649 """SUBROUTINE %(sub_prefix)sMERGE_WL(WL,R,LCUT_SIZE,CONST,OUT)
650 USE %(proc_prefix)sPOLYNOMIAL_CONSTANTS
651 INTEGER I,J
652 %(coef_format)s WL(MAXLWFSIZE,0:LOOPMAXCOEFS-1,MAXLWFSIZE)
653 INTEGER R,LCUT_SIZE
654 %(coef_format)s CONST
655 %(coef_format)s OUT(0:LOOPMAXCOEFS-1)
656 """%self.rep_dict)
657
658
659 lines.append("DO I=1,LCUT_SIZE")
660 lines.append(" DO J=0,NCOEF_R(R)-1")
661 lines.append(" OUT(J)=OUT(J)+WL(I,J,I)*CONST")
662 lines.append(" ENDDO")
663 lines.append("ENDDO")
664 lines.append("END")
665
666 return '\n'.join(lines)
667
669 """ Give out the subroutine to simply add together the coefficients
670 of two loop polynomials of rank R1 and R2 storing the result in the
671 first polynomial given in the arguments."""
672 lines=[]
673
674
675 lines.append("""SUBROUTINE %(sub_prefix)sADD_COEFS(A,RA,B,RB)
676 USE %(proc_prefix)sPOLYNOMIAL_CONSTANTS
677 INTEGER I
678 %(coef_format)s A(0:LOOPMAXCOEFS-1),B(0:LOOPMAXCOEFS-1)
679 INTEGER RA,RB
680 """%self.rep_dict)
681
682
683 lines.append("DO I=0,NCOEF_R(RB)-1")
684 lines.append(" A(I)=A(I)+B(I)")
685 lines.append("ENDDO")
686 lines.append("END")
687
688 return '\n'.join(lines)
689
691 """ Back up of the class Polynomial, which uses the same coefficeints orders with IREGI.
692 It is useful in the case that the order of MadLoop coefficients changes in the future."""
693
695
696 assert rank > -1, "The rank of a q-polynomial should be 0 or positive"
697 self.rank=rank
698 self.init_coef_list()
699
701 """ Creates a list whose elements are arrays being the coefficient
702 indices sorted in growing order and the value is their position in a
703 one-dimensional vector. For example the position of the coefficient
704 C_01032 will be placed in the list under array.array('i',(0,0,1,3,2)).
705 """
706 self.coef_list=[]
707 self.coef_list.append(array.array('i',()))
708
709 if self.rank==0:
710 return
711
712 tmp_coef_list=[array.array('i',(0,)),array.array('i',(1,)),
713 array.array('i',(2,)),array.array('i',(3,))]
714 self.coef_list.extend(tmp_coef_list)
715
716 for i in range(1,self.rank):
717 new_tmp_coef_list=[]
718 for coef in tmp_coef_list:
719 for val in range(coef[-1],4):
720 new_coef=copy.copy(coef)
721 new_coef.append(val)
722 new_tmp_coef_list.append(new_coef)
723 tmp_coef_list=new_tmp_coef_list
724 self.coef_list.extend(tmp_coef_list)
725
727 """ Returns the canonical position for a coefficient characterized
728 by the value of the indices of the loop momentum q it multiplies,
729 that is for example C_01032 multiplying q_0*q_1*q_0*q_3*q_2 """
730
731 new_indices_list=copy.copy(indices_list)
732 new_indices_list.sort()
733 try:
734 return self.coef_list.index(array.array('i',new_indices_list))
735 except ValueError:
736 raise PolynomialError,\
737 "The index %s looked for could not be found"%str(indices_list)
738
740 """ Returns the coefficient at position pos in the one dimensional
741 vector """
742 return list(self.coef_list[pos])
743
746 """ Just a container class with helper functions taken from the script
747 tens.py of golem which generates most of the golem95 tens_rec.f fortran
748 code."""
749
750 PRIMES = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29,
751 31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
752 73, 79, 83, 89, 97, 101, 103, 107, 109, 113,
753 127, 131, 137, 139, 149, 151, 157, 163, 167, 173,
754 179, 181, 191, 193, 197, 199, 211, 223, 227, 229,
755 233, 239, 241, 251, 257, 263, 269, 271, 277, 281,
756 283, 293, 307, 311, 313, 317, 331, 337, 347, 349,
757 353, 359, 367, 373, 379, 383, 389, 397, 401, 409,
758 419, 421, 431, 433, 439, 443, 449, 457, 461, 463,
759 467, 479, 487, 491, 499, 503, 509, 521, 523, 541,
760 547, 557, 563, 569, 571, 577, 587, 593, 599, 601,
761 607, 613, 617, 619, 631, 641, 643, 647, 653, 659,
762 661, 673, 677, 683, 691, 701, 709, 719, 727, 733,
763 739, 743, 751, 757, 761, 769, 773, 787, 797, 809,
764 811, 821, 823, 827, 829, 839, 853, 857, 859, 863,
765 877, 881, 883, 887, 907, 911, 919, 929, 937, 941,
766 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013,
767 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069,
768 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151,
769 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223,
770 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291,
771 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373]
772
773 @classmethod
775 """
776 Calculates the binomial coefficient (n atop k).
777 """
778 if k < 0 or k > n:
779 return 0
780 else:
781 num = 1
782 den = 1
783 for i in range(1, k+1):
784 num *= n-i+1
785 den *= i
786 return num/den
787
788 @classmethod
790 """
791 Generates a mapping from tensor components \hat{C}(a_1, ..., a_k)
792 into a one dimensional array.
793
794 PARAMETER
795
796 R -- rank
797 k -- number of non-zero components of q
798
799 RETURN
800
801 (lst, dic)
802
803 lst -- list of (a_1, ..., a_k)
804 dic -- mapping from (a_1, ..., a_k) -> int
805
806 lst[dic[X]] = X if X in dic
807 """
808
809 def rec_generator(k, R):
810 if k == 0:
811 yield []
812 elif k <= R:
813 for a_1 in range(1, R - (k - 1) + 1):
814 if k > 1:
815 for tail in rec_generator(k - 1, R - a_1):
816 yield [a_1] + tail
817 else:
818 yield [a_1]
819
820 lst = []
821 dic = {}
822 i = 0
823 for indices in rec_generator(k, R):
824 t = tuple(indices)
825 lst.append(t)
826 dic[t] = i
827 i += 1
828
829 assert i == cls.combinat(R, k), \
830 "len(%s) != %d, R=%d,k=%d" % (lst,cls.combinat(R, k),R,k)
831 return lst, dic
832
833 @classmethod
835 """
836 Generates a set of equations for a given number of non-zero
837 components and fixed maximum rank.
838
839 PARAMETER
840
841 R -- rank
842 k -- number of non-zero components of q
843
844 RETURN
845
846 (LHS, RHS)
847
848 LHS -- a matrix (i.e. list of lists) of coefficients
849 RHS -- a list of values of q
850 """
851
852 lst, dic = cls.generate_mapping(R, k)
853 l = len(lst)
854 LHS = []
855 RHS = []
856 for num_eq in range(l):
857 q = map(lambda i: cls.PRIMES[i], lst[num_eq])
858 coeffs = [
859 reduce(lambda x,y: x*y, map(lambda (b,e): b**e, zip(q, term)), 1)
860 for term in lst]
861 LHS.append(coeffs)
862 RHS.append(q)
863
864 return LHS, RHS, lst, dic
865
866 @classmethod
868 """
869 Iterator over all selections of k elements from a given list.
870
871 PARAMETER
872
873 items -- list of elements to choose from (no repetitions)
874 k -- number of elements to select.
875 """
876 n = len(items)
877
878
879 if k == n:
880 yield items[:]
881 elif k == 0:
882 yield []
883 elif 0 < k and k < n:
884 head = items[0:1]
885 tail = items[1:]
886 for result in cls.select(tail, k-1):
887 yield head + result
888 for result in cls.select(tail, k):
889 yield result
890
891 if __name__ == '__main__':
892 """I test here the write_golem95_mapping function"""
893
894 P=Polynomial(7)
895 print "Coef (6,0,0,0) is at pos %s"%P.get_coef_position([0,0,0,0,0,0])
896 print "Coef (1,1,2,2) is at pos %s"%P.get_coef_position([0,1,2,2,3,3])
897 print "Coef (7,0,0,0) is at pos %s"%P.get_coef_position([0,0,0,0,0,0,0])
898 print "Coef (1,2,2,2) is at pos %s"%P.get_coef_position([0,1,1,2,2,3,3])
899
900 sys.exit(0)
901
902 max_rank=6
903 FPR=FortranPolynomialRoutines(max_rank)
904 print "Output of write_golem95_mapping function for max_rank=%d:\n\n"%max_rank
905
906 import os
907 import sys
908 root_path = os.path.split(os.path.dirname(os.path.realpath( __file__ )))[0]
909 sys.path.insert(0, os.path.join(root_path,os.path.pardir))
910 import madgraph.iolibs.file_writers as writers
911 FWriter = writers.FortranWriter("GOLEM95_interface.f")
912 FWriter.writelines(FPR.write_golem95_mapping())
913