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