Package madgraph :: Package various :: Module q_polynomial
[hide private]
[frames] | no frames]

Source Code for Module madgraph.various.q_polynomial

  1  import array 
  2  import copy 
  3  import math 
4 5 -class PolynomialError(Exception): pass
6
7 -def get_number_of_coefs_for_rank(r):
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
12 -class Polynomial(object):
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
17 - def __init__(self, rank):
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
23 - def init_coef_list(self):
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
37 - def get_coef_position(self, indices_list):
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
60 - def get_coef_at_position(self, pos):
61 """ Returns the coefficient at position pos in the one dimensional 62 vector """ 63 return list(self.coef_list[pos])
64
65 -class Polynomial_naive_ordering(object):
66 """ A class to represent a polynomial in the loop momentum (4-vector) q""" 67
68 - def __init__(self, rank):
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
74 - def init_coef_list(self):
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
100 - def get_coef_position(self, indices_list):
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
113 - def get_coef_at_position(self, pos):
114 """ Returns the coefficient at position pos in the one dimensional 115 vector """ 116 return list(self.coef_list[pos])
117
118 -class PolynomialRoutines(object):
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 # A useful replacement dictionary 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
160 -class FortranPolynomialRoutines(PolynomialRoutines):
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 # Start with the polynomial constants module header 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 # Add the N coef for rank 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
218 - def write_pjfry_mapping(self):
219 """ Returns a fortran subroutine which fills in the array of integral reduction 220 coefficients following MadLoop standards using pjfry++ coefficients.""" 221 222 # THE OUTPUT OF COEFS FROM PJFRY++ IS 223 # RANK=0: (,) 224 # RANK=1: (0,),(1,),(2,),(3,) 225 # RANK=2: (0,0),(0,1),(1,1),(0,2),(1,2),(2,2),(0,3),(1,3),(2,3),(3,3) 226 # ... 227 # THE OUTPUT OF COEFS FROM MADLOOP IS 228 # RANK=0: (,) 229 # RANK=1: (0,),(1,),(2,),(3,) 230 # RANK=2: (0,0),(0,1),(0,2),(0,3),(1,1),(2,1),(3,1),(2,2),(2,3),(3,3) 231 # ... 232 233 234 # Helper function 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
304 - def write_iregi_mapping(self):
305 """ Returns a fortran subroutine which fills in the array of integral reduction 306 coefficients following MadLoop standards using IREGI coefficients.""" 307 308 # THE OUTPUT OF COEFS FROM IREGI IS 309 # RANK=0: (,) 310 # RANK=1: (0,),(1,),(2,),(3,) 311 # RANK=2: (0,0),(0,1),(0,2),(0,3),(1,1),(2,1),(3,1),(2,2),(2,3),(3,3) 312 # ... 313 314 # Helper function 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
365 - def get_COLLIER_mapping(self):
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
379 - def write_golem95_mapping(self):
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 # Set number of space-time dimensions to 4 here 386 d = 4 387 golem_max_rank = 6 388 389 # First generate the block_info which contains information about the 390 # about the block structure of the system 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 # Helper function 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 # Write out one subroutine per rank 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 # Start by writing out the header: 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 # The constant coefficient is treated separately 447 lines.append("c Constant coefficient ") 448 lines.append("GOLEM_COEFS%%c0=ML_COEFS(%d)"\ 449 %self.pq.get_coef_position([])) 450 451 # Now write out the explicit mapping 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
473 - def write_compact_wl_updater(self,r_1,r_2,loop_over_vertex_coefs_first=True):
474 """ Give out the subroutine to update a polynomial of rank r_1 with 475 one of rank r_2 """ 476 477 # The update is basically given by 478 # OUT(j,coef,i) = A(k,*,i) x B(j,*,k) 479 # with k a summed index and the 'x' operation is equivalent to 480 # putting together two regular polynomial in q with scalar coefficients 481 # The complexity of this subroutine is therefore 482 # MAXLWFSIZE**3 * NCoef(r_1) * NCoef(r_2) 483 # Which is for example 22'400 when updating a rank 4 loop wavefunction 484 # with a rank 1 updater. 485 # The situation is slightly improved by a smarter handling of the 486 # coefficients equal to zero 487 488 lines=[] 489 490 # Start by writing out the header: 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 # Start the loop on the elements i,j of the vector OUT(i,coef,j) 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 # return the subroutine 550 return '\n'.join(lines)
551
552 - def write_expanded_wl_updater(self,r_1,r_2):
553 """ Give out the subroutine to update a polynomial of rank r_1 with 554 one of rank r_2 """ 555 556 # The update is basically given by 557 # OUT(j,coef,i) = A(k,*,i) x B(j,*,k) 558 # with k a summed index and the 'x' operation is equivalent to 559 # putting together two regular polynomial in q with scalar coefficients 560 # The complexity of this subroutine is therefore 561 # MAXLWFSIZE**3 * NCoef(r_1) * NCoef(r_2) 562 # Which is for example 22'400 when updating a rank 4 loop wavefunction 563 # with a rank 1 updater. 564 565 lines=[] 566 567 # Start by writing out the header: 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 # Start the loop on the elements i,j of the vector OUT(i,coef,j) 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 # Now we write the lines defining the coefs of OUT(j,*,i) from those 588 # of A(k,*,i) and B(j,*,k) 589 # The dictionary below stores the position of the new coefficient 590 # derived as keys and the list of the buidling blocks expressing 591 # them as values 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 # And now we simply close the enddo. 611 lines.append(" ENDDO") 612 lines.append(" ENDDO") 613 lines.append("ENDDO") 614 lines.append("END") 615 616 # return the subroutine 617 return '\n'.join(lines)
618
619 - def write_polynomial_evaluator(self):
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 # Start by writing out the header: 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 # Start by the trivial coefficient of order 0. 635 lines.append("OUT=C(0)") 636 # Now scan them all progressively 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
655 - def write_wl_merger(self):
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 # Start by writing out the header: 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 # Now scan them all progressively 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
682 - def write_add_coefs(self):
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 # Start by writing out the header: 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 # Now scan them all progressively 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
704 -class FromIREGIFortranCodeGenerator():
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
708 - def __init__(self, rank):
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
714 - def init_coef_list(self):
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
740 - def get_coef_position(self, indices_list):
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
753 - def get_coef_at_position(self, pos):
754 """ Returns the coefficient at position pos in the one dimensional 755 vector """ 756 return list(self.coef_list[pos])
757
758 759 -class FromGolem95FortranCodeGenerator():
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
788 - def combinat(cls, n, k):
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
803 - def generate_mapping(cls, R, k):
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
848 - def generate_equations(cls, R, k):
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
881 - def select(cls, items, k):
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 # We use the fact that 892 # (n choose k) = (1 choose 1)(n-1 choose k-1)+(1 choose 0)(n-1 choose k) 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