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

Source Code for Module madgraph.various.q_polynomial

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