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 write_golem95_mapping(self):
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 # Set number of space-time dimensions to 4 here 372 d = 4 373 golem_max_rank = 6 374 375 # First generate the block_info which contains information about the 376 # about the block structure of the system 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 # Helper function 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 # Write out one subroutine per rank 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 # Start by writing out the header: 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 # The constant coefficient is treated separately 433 lines.append("c Constant coefficient ") 434 lines.append("GOLEM_COEFS%%c0=ML_COEFS(%d)"\ 435 %self.pq.get_coef_position([])) 436 437 # Now write out the explicit mapping 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
459 - def write_compact_wl_updater(self,r_1,r_2,loop_over_vertex_coefs_first=True):
460 """ Give out the subroutine to update a polynomial of rank r_1 with 461 one of rank r_2 """ 462 463 # The update is basically given by 464 # OUT(j,coef,i) = A(k,*,i) x B(j,*,k) 465 # with k a summed index and the 'x' operation is equivalent to 466 # putting together two regular polynomial in q with scalar coefficients 467 # The complexity of this subroutine is therefore 468 # MAXLWFSIZE**3 * NCoef(r_1) * NCoef(r_2) 469 # Which is for example 22'400 when updating a rank 4 loop wavefunction 470 # with a rank 1 updater. 471 # The situation is slightly improved by a smarter handling of the 472 # coefficients equal to zero 473 474 lines=[] 475 476 # Start by writing out the header: 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 # Start the loop on the elements i,j of the vector OUT(i,coef,j) 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 # return the subroutine 536 return '\n'.join(lines)
537
538 - def write_expanded_wl_updater(self,r_1,r_2):
539 """ Give out the subroutine to update a polynomial of rank r_1 with 540 one of rank r_2 """ 541 542 # The update is basically given by 543 # OUT(j,coef,i) = A(k,*,i) x B(j,*,k) 544 # with k a summed index and the 'x' operation is equivalent to 545 # putting together two regular polynomial in q with scalar coefficients 546 # The complexity of this subroutine is therefore 547 # MAXLWFSIZE**3 * NCoef(r_1) * NCoef(r_2) 548 # Which is for example 22'400 when updating a rank 4 loop wavefunction 549 # with a rank 1 updater. 550 551 lines=[] 552 553 # Start by writing out the header: 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 # Start the loop on the elements i,j of the vector OUT(i,coef,j) 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 # Now we write the lines defining the coefs of OUT(j,*,i) from those 574 # of A(k,*,i) and B(j,*,k) 575 # The dictionary below stores the position of the new coefficient 576 # derived as keys and the list of the buidling blocks expressing 577 # them as values 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 # And now we simply close the enddo. 597 lines.append(" ENDDO") 598 lines.append(" ENDDO") 599 lines.append("ENDDO") 600 lines.append("END") 601 602 # return the subroutine 603 return '\n'.join(lines)
604
605 - def write_polynomial_evaluator(self):
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 # Start by writing out the header: 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 # Start by the trivial coefficient of order 0. 621 lines.append("OUT=C(0)") 622 # Now scan them all progressively 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
641 - def write_wl_merger(self):
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 # Start by writing out the header: 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 # Now scan them all progressively 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
668 - def write_add_coefs(self):
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 # Start by writing out the header: 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 # Now scan them all progressively 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
690 -class FromIREGIFortranCodeGenerator():
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
694 - def __init__(self, rank):
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
700 - def init_coef_list(self):
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
726 - def get_coef_position(self, indices_list):
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
739 - def get_coef_at_position(self, pos):
740 """ Returns the coefficient at position pos in the one dimensional 741 vector """ 742 return list(self.coef_list[pos])
743
744 745 -class FromGolem95FortranCodeGenerator():
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
774 - def combinat(cls, n, k):
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
789 - def generate_mapping(cls, R, k):
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
834 - def generate_equations(cls, R, k):
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
867 - def select(cls, items, k):
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 # We use the fact that 878 # (n choose k) = (1 choose 1)(n-1 choose k-1)+(1 choose 0)(n-1 choose k) 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