Package aloha :: Module aloha_lib
[hide private]
[frames] | no frames]

Source Code for Module aloha.aloha_lib

   1  ################################################################################ 
   2  # 
   3  # Copyright (c) 2010 The MadGraph Development team and Contributors 
   4  # 
   5  # This file is a part of the MadGraph 5 project, an application which  
   6  # automatically generates Feynman diagrams and matrix elements for arbitrary 
   7  # high-energy processes in the Standard Model and beyond. 
   8  # 
   9  # It is subject to the MadGraph license which should accompany this  
  10  # distribution. 
  11  # 
  12  # For more information, please visit: http://madgraph.phys.ucl.ac.be 
  13  # 
  14  ################################################################################ 
  15  ##   Diagram of Class 
  16  ## 
  17  ##    Variable (vartype:0)<--- ScalarVariable  
  18  ##                          | 
  19  ##                          +- LorentzObject  
  20  ##                                 
  21  ## 
  22  ##    list <--- AddVariable (vartype :1)    
  23  ##           | 
  24  ##           +- MultVariable  <--- MultLorentz (vartype:2)  
  25  ##            
  26  ##    list <--- LorentzObjectRepresentation (vartype :4) <-- ConstantObject 
  27  ##                                                               (vartype:5) 
  28  ## 
  29  ##    FracVariable (vartype:3) 
  30  ## 
  31  ################################################################################ 
  32  """This module develop basic structure for the symbolic treatment of the Helas 
  33  Amplitude. 
  34   
  35  The Symbolic treatment are based on a series of (scalar) variable of the form 
  36  a * x. 'a' is a (complex) number and x is an abstract variable. 
  37  Those variable can be multiply/add to each other and will then create a list of  
  38  those variable in 'MultVariable','AddVariable'.  
  39   
  40  As We will work on two different level, we have two concrete representation of 
  41  Variable:  
  42      - 'ScalarVariable' in order to represent a number (mass, component of  
  43          impulsion,... 
  44      - 'LorentzObject' in order to store HighLevel object with lorentz/spin  
  45          indices (as Gamma, Impulsion,...) 
  46   
  47  In order to pass from HighLevel Object (deriving from LorentzObject) to concrete 
  48  definition based on ScalarVariable, we define a new class  
  49  'LorentzObjectRepresentation'  
  50   
  51  Each class defines the attribute "typevar" which is unique, this fastenize the  
  52  type recognition of the object.""" 
  53  from __future__ import division 
  54  from numbers import Number 
  55   
  56  #number below this number will be consider as ZERO 
  57  precision_cut = 1e-14 
  58   
  59  USE_TAG=set() #global to check which tag are used 
  60   
  61  depth=-1 
62 63 #=============================================================================== 64 # FracVariable 65 #=============================================================================== 66 -class FracVariable(object):
67 """A representation of a fraction. This object simply have 68 - a numerator (self.numerator) 69 - a denominator (self.denominator) 70 The numerator/denominator can be of any type of Object. 71 72 All call function simply retranslate the call on the numerator/denominator 73 """ 74 75 # In order to fastenize type 76 vartype = 3 77
78 - def __init__(self, numerator, denominator, *opt):
79 """ initialize the frac variable """ 80 81 self.numerator = numerator 82 self.denominator = denominator
83 #if isinstance(self.numerator, Number): 84 # self.tag = self.denominator.tag 85 #else: 86 # self.tag = self.numerator.tag.union(self.denominator.tag) 87
88 - def copy(self):
89 """return a copy of the frac variable""" 90 num = self.numerator.copy() 91 den = self.denominator.copy() 92 return FracVariable(num,den)
93 94 95
96 - def simplify(self):
97 """apply rule of simplification""" 98 99 if not isinstance(self.numerator, Number): 100 self.numerator = self.numerator.simplify() 101 self.denominator = self.denominator.simplify() 102 103 if isinstance(self.denominator, ConstantObject): 104 self.numerator /= self.denominator.constant_term 105 return self.numerator 106 else: 107 return self
108
109 - def factorize(self):
110 """made the factorization""" 111 if hasattr(self.numerator, 'vartype'): 112 self.numerator = self.numerator.factorize() 113 self.denominator = self.denominator.factorize() 114 return self
115 116
117 - def expand(self):
118 """Expand the content information""" 119 120 if isinstance(self.numerator, Number): 121 return FracVariable(self.numerator, self.denominator.expand()) 122 return FracVariable(self.numerator.expand(), self.denominator.expand())
123
124 - def __eq__(self, obj):
125 """Define the Equality of two Object""" 126 127 return (self.numerator == obj.numerator) and \ 128 (self.denominator == obj.denominator)
129
130 - def __mul__(self, obj):
131 """multiply by an object""" 132 133 if isinstance(obj, FracVariable): 134 return FracVariable(self.numerator * obj.numerator, \ 135 self.denominator * obj.denominator) 136 else: 137 return FracVariable(self.numerator * obj, self.denominator)
138 139 __rmul__ = __mul__ 140
141 - def __div__(self, obj):
142 """Deal with division""" 143 # Multiply the denominator by one to ensure that the new object didn't 144 #have a pointer through the old one 145 return FracVariable(self.numerator * 1, self.denominator * obj)
146 147 148 149 __truediv__ = __div__ 150
151 - def __add__(self, obj):
152 """We don't need to deal with addition-substraction on this type of Object""" 153 if isinstance(obj, Number): 154 if obj: 155 self.numerator += obj * self.denominator 156 return self 157 assert(obj.vartype == 3) 158 159 if self.denominator != obj.denominator: 160 return NotImplemented('The Denominator should be the Same') 161 else: 162 new = FracVariable(self.numerator + obj.numerator, self.denominator) 163 return new
164
165 - def __str__(self):
166 if self.vartype == 4: #isinstance(self.numerator, LorentzObjectRepresentation): 167 text = 'number of lorentz index :' + str(len(self.numerator.lorentz_ind)) + '\n' 168 text += str(self.numerator.lorentz_ind) 169 text += 'number of spin index :' + str(len(self.numerator.spin_ind)) + '\n' 170 #text += 'other info ' + str(self.numerator.tag) + '\n' 171 for ind in self.numerator.listindices(): 172 ind = tuple(ind) 173 text += str(ind) + ' --> ' 174 if self.numerator.get_rep(ind) == 0: 175 text += '0\n' 176 else: 177 text += '[ ' + str(self.numerator.get_rep(ind)) + ' ] / [ ' + \ 178 str(self.denominator.get_rep([0])) + ']\n' 179 return text 180 else: 181 return '%s / %s' % (self.numerator, self.denominator)
182
183 #=============================================================================== 184 # AddVariable 185 #=============================================================================== 186 -class AddVariable(list):
187 """ A list of Variable/ConstantObject/... This object represent the operation 188 between those object.""" 189 190 #variable to fastenize class recognition 191 vartype = 1 192
193 - def __init__(self, old_data=[], prefactor=1):
194 """ initialization of the object with default value """ 195 196 self.prefactor = prefactor 197 #self.tag = set() 198 list.__init__(self, old_data)
199
200 - def copy(self):
201 """ return a deep copy of the object""" 202 return self.__class__(self, self.prefactor)
203
204 - def simplify(self, short=False):
205 """ apply rule of simplification """ 206 207 # deal with one length object 208 if len(self) == 1: 209 return self.prefactor * self[0].simplify() 210 211 if short: 212 return self 213 214 # check if more than one constant object 215 constant = 0 216 # simplify complex number/Constant object 217 for term in self[:]: 218 if not hasattr(term, 'vartype'): 219 constant += term 220 self.remove(term) 221 elif term.vartype == 5: 222 constant += term.prefactor * term.value 223 self.remove(term) 224 225 226 # contract identical term and suppress null term 227 varlen = len(self) 228 i = -1 229 while i > -varlen: 230 j = i - 1 231 while j >= -varlen: 232 if self[i] == self[j]: 233 self[i].prefactor += self[j].prefactor 234 del self[j] 235 varlen -= 1 236 else: 237 j -= 1 238 if abs(self[i].prefactor) < precision_cut: 239 del self[i] 240 varlen -= 1 241 else: 242 i -= 1 243 244 if constant: 245 self.append(ConstantObject(constant)) 246 varlen += 1 247 248 # deal with one/zero length object 249 if varlen == 1: 250 return self.prefactor * self[0].simplify() 251 elif varlen == 0: 252 return ConstantObject() 253 254 255 256 return self
257
258 - def expand(self):
259 """Pass from High level object to low level object""" 260 261 if not self: 262 return self 263 264 new = self[0].expand() 265 for item in self[1:]: 266 obj = item.expand() 267 new += obj 268 269 return new
270 271
272 - def __mul__(self, obj):
273 """define the multiplication of 274 - a AddVariable with a number 275 - a AddVariable with an AddVariable 276 other type of multiplication are define via the symmetric operation base 277 on the obj class.""" 278 279 if not hasattr(obj, 'vartype'): # obj is a number 280 if not obj: 281 return 0 282 new = self.__class__([], self.prefactor) 283 new[:] = [obj * term for term in self] 284 return new 285 286 elif obj.vartype == 1: # obj is an AddVariable 287 new = AddVariable() 288 for term in self: 289 new += term * obj 290 return new 291 else: 292 #force the program to look at obj + self 293 return NotImplemented
294
295 - def __add__(self, obj):
296 """Define all the different addition.""" 297 298 299 if not obj: # obj is zero 300 return self 301 #DECOMENT FOR SPIN2 PROPAGATOR COMPUTATION 302 elif isinstance(obj, Number): 303 obj = ConstantObject(obj) 304 new = AddVariable(self, self.prefactor) 305 new.append(obj) 306 return new 307 elif not obj.vartype: # obj is a Variable 308 new = AddVariable(self, self.prefactor) 309 obj = obj.copy() 310 new.append(obj) 311 return new 312 313 elif obj.vartype == 2: # obj is a MultVariable 314 new = AddVariable(self, self.prefactor) 315 obj = obj.__class__(obj, obj.prefactor) 316 new.append(obj) 317 return new 318 319 elif obj.vartype == 1: # obj is a AddVariable 320 new = AddVariable(list.__add__(self, obj)) 321 return new 322 else: 323 #force to look at obj + self 324 return NotImplemented
325
326 - def __div__(self, obj):
327 """ Implement division""" 328 329 if not hasattr(obj, 'vartype'): #obj is a Number 330 factor = 1 / obj 331 return factor * self 332 else: 333 new_num = AddVariable(self, self.prefactor) 334 new_denom = obj.copy() 335 336 return FracVariable(new_num, new_denom)
337
338 - def __rdiv__(self, obj):
339 """Deal division in a inverse way""" 340 341 new = AddVariable(self, self.prefactor) 342 if not hasattr(obj, 'vartype'): 343 return FracVariable(obj, new) 344 else: 345 return NotImplemented
346
347 - def __sub__(self, obj):
348 return self + (-1) * obj
349 350 __radd__ = __add__ 351 __iadd__ = __add__ 352 __rmul__ = __mul__ 353 __truediv__ = __div__ 354 __rtruediv__ = __rdiv__ 355
356 - def __rsub__(self, obj):
357 return (-1) * self + obj
358
359 - def append(self, obj):
360 """ add a newVariable in the Multiplication list """ 361 if obj.prefactor: 362 list.append(self, obj)
363
364 - def __eq__(self, obj):
365 """Define The Equality""" 366 367 if self.__class__ != obj.__class__: 368 return False 369 370 for term in self: 371 self_prefactor = [term2.prefactor for term2 in self if term2 == term] 372 obj_prefactor = [term2.prefactor for term2 in obj if term2 == term] 373 if len(self_prefactor) != len(obj_prefactor): 374 return False 375 self_prefactor.sort() 376 obj_prefactor.sort() 377 if self_prefactor != obj_prefactor: 378 return False 379 380 #Pass all the test 381 return True
382
383 - def __ne__(self, obj):
384 """Define the unequality""" 385 return not self.__eq__(obj)
386
387 - def __str__(self):
388 text = '' 389 if self.prefactor != 1: 390 text += str(self.prefactor) + ' * ' 391 text += '( ' 392 text += ' + '.join([str(item) for item in self]) 393 text += ' )' 394 return text
395 396
397 - def count_term(self):
398 # Count the number of appearance of each variable and find the most 399 #present one in order to factorize her 400 count = {} 401 max, maxvar = 0, None 402 for term in self: 403 if term.vartype == 2: # term is MultVariable -> look inside 404 for var in term: 405 count[var.variable] = count.setdefault(var.variable, 0) + 1 406 if count[var.variable] > max: 407 #update the maximum if reached 408 max, maxvar = max + 1, var 409 else: #term is Varible -> direct update 410 count[term.variable] = count.setdefault(term.variable, 0) + 1 411 if count[term.variable] > max: 412 max, maxvar = max + 1, term 413 414 return max, maxvar
415
416 - def factorize(self):
417 """ try to factorize as much as possible the expression """ 418 419 #import aloha 420 #aloha.depth += 1 #global variable for debug 421 max, maxvar = self.count_term() 422 maxvar = maxvar.__class__(maxvar.variable) 423 if max <= 1: 424 #no factorization possible 425 #aloha.depth -=1 426 return self 427 else: 428 # split in MAXVAR * NEWADD + CONSTANT 429 #print " " * 4 * aloha.depth + "start fact", self 430 newadd = AddVariable() 431 constant = AddVariable() 432 #fill NEWADD and CONSTANT 433 for term in self: 434 if maxvar == term: 435 term = term.copy() 436 term.power -= 1 437 if term.power: 438 newadd.append(term.simplify()) 439 else: 440 newadd.append(ConstantObject(term.prefactor)) 441 elif term.vartype == 2 : #isinstance(term, MultVariable): 442 if maxvar in term: 443 newterm = MultVariable([], term.prefactor) 444 for fact in term: 445 if fact == maxvar: 446 if fact.power > 1: 447 newfact = fact.copy() 448 newfact.power -= 1 449 newterm.append(newfact) 450 else: 451 newterm.append(fact) 452 newadd.append(newterm.simplify()) 453 else: 454 constant.append(term) 455 else: 456 constant.append(term) 457 458 #factorize the result 459 try: 460 cur_len = len(newadd) 461 except: 462 cur_len = 0 463 if cur_len > 1: 464 try: 465 newadd = newadd.factorize() 466 except Exception, error: 467 raise 468 #raise Exception('fail to factorize: %s' % error) 469 else: 470 #take away the useless AddVariable to going back to a Variable class 471 newadd = newadd[0] 472 473 474 # recombine the factor. First ensure that the power of the object is 475 #one. Then recombine 476 if maxvar.power > 1: 477 maxvar = maxvar.copy() 478 maxvar.power = 1 479 480 481 482 if newadd.vartype == 2: # isinstance(newadd, MultVariable): 483 newadd.append(maxvar) 484 else: 485 newadd = MultVariable([maxvar, newadd]) 486 487 #simplify structure: 488 if len(constant) == 1: 489 constant = constant[0] 490 if len(newadd) == 1: 491 newadd = newadd[0] 492 493 if constant: 494 constant = constant.factorize() 495 #aloha.depth -=1 496 # ' ' * 4 * aloha.depth + 'return', AddVariable([newadd, constant]) 497 return AddVariable([newadd, constant]) 498 else: 499 if constant.vartype == 5 and constant != 0: 500 #aloha.depth -=1 501 return AddVariable([newadd, constant]) 502 #aloha.depth -=1 503 #print ' ' * 4 * aloha.depth + 'return:', newadd 504 return newadd
505
506 #=============================================================================== 507 # MultVariable 508 #=============================================================================== 509 -class MultVariable(list):
510 """ A list of Variable with multiplication as operator between themselves. 511 """ 512 513 add_class = AddVariable # define the class for addition of MultClass 514 vartype = 2 # for istance check optimization 515
516 - def __init__(self, old_data=[], prefactor=1):
517 """ initialization of the object with default value """ 518 519 self.prefactor = prefactor 520 #self.tag = set() 521 list.__init__(self, old_data)
522
523 - def copy(self):
524 """ return a copy """ 525 return self.__class__(self, self.prefactor)
526
527 - def simplify(self):
528 """ simplify the product""" 529 530 #Ask to Simplify each term 531 self[:] = [fact.simplify() for fact in self] 532 533 #Check that we have at least two different factor if not returning 534 #the content of the MultVariable 535 if len(self) == 1: 536 return self.prefactor * self[0] 537 return self
538
539 - def factorize(self):
540 """Try to factorize this (nothing to do)""" 541 return self
542
543 - def expand(self):
544 """Pass from High Level object to low level object """ 545 546 out = self[0].expand() 547 for fact in self[1:]: 548 out *= fact.expand() 549 out *= self.prefactor 550 return out
551 552 #Defining rule of Multiplication
553 - def __mul__(self, obj):
554 """Define the multiplication with different object""" 555 556 if not hasattr(obj, 'vartype'): # should be a number 557 return self.__class__(self, self.prefactor * obj) 558 559 elif not obj.vartype: # obj is a Variable 560 return NotImplemented # Use the one ov Variable 561 562 elif obj.vartype == 2: # obj is a MultVariable 563 new = self.__class__(self, self.prefactor) 564 for fact in obj: 565 new.append(fact) 566 new.prefactor *= obj.prefactor 567 return new 568 569 elif obj.vartype == 1: # obj is an AddVariable 570 new = self.add_class(obj, obj.prefactor) 571 new[:] = [data.__mul__(self) for data in new] 572 return new 573 574 else: 575 #look at obj * self 576 return NotImplemented
577 578
579 - def __add__(self, obj):
580 """ define the adition with different object""" 581 582 if not obj: 583 return self 584 #DECOMENT FOR SPIN2 PROPAGATOR COMPUTATION 585 elif isinstance(obj, Number): 586 obj = ConstantObject(obj) 587 self.add_class() 588 new = self.add_class() 589 new.append(obj) 590 new.append(self.__class__(self, self.prefactor)) 591 return new 592 elif obj.vartype == 2: # obj is MultVariable 593 new = self.add_class() 594 new.append(self.__class__(self, self.prefactor)) 595 new.append(self.__class__(obj, obj.prefactor)) 596 return new 597 else: 598 #call the implementation of addition implemented in obj 599 return NotImplemented
600
601 - def __sub__(self, obj):
602 return self + (-1) * obj
603
604 - def __neg__(self):
605 return (-1) * self
606
607 - def __rsub__(self, obj):
608 return (-1) * self + obj
609
610 - def __div__(self, obj):
611 """ define the division """ 612 if not hasattr(obj, 'vartype'): 613 factor = 1 / obj 614 return factor * self 615 else: 616 return FracVariable(1 * self, 1 * obj)
617
618 - def __rdiv__(self, obj):
619 """Deal division in a inverse way""" 620 621 new = self.__class__(self, self.prefactor) 622 if not hasattr(obj, 'vartype'): 623 return FracVariable(obj, new) 624 else: 625 return NotImplemented
626 627 __radd__ = __add__ 628 __iadd__ = __add__ 629 __rmul__ = __mul__ 630 __truediv__ = __div__ 631 __rtruediv__ = __rdiv__ 632 633
634 - def append(self, obj):
635 """ add a newVariable in the Multiplication list and look for her power 636 """ 637 638 self.prefactor *= obj.prefactor 639 if obj in self: 640 index = self.index(obj) 641 self[index] = self[index].copy() 642 self[index].power += obj.power 643 else: 644 obj.prefactor = 1 645 list.append(self, obj)
646
647 - def __eq__(self, obj):
648 """Define When two MultVariable are identical""" 649 650 try: 651 if obj.vartype !=2 or len(self) != len(obj): 652 return False 653 except: 654 return False 655 else: 656 l1=[(var.variable, var.power) for var in self] 657 for var in obj: 658 if not (var.variable, var.power) in l1: 659 return False 660 return True
661
662 - def __ne__(self, obj):
663 """ Define when two Multvariable are not identical""" 664 return not self.__eq__(obj)
665
666 - def __str__(self):
667 """ String representation """ 668 669 text = '' 670 if self.prefactor != 1: 671 text += str(self.prefactor) + ' * ' 672 text += '( ' 673 text += ' * '.join([str(item) for item in self]) 674 text += ' )' 675 return text
676 677 __rep__ = __str__
678
679 #=============================================================================== 680 # Variable 681 #=============================================================================== 682 -class Variable(object):
683 """This is the standard object for all the variable linked to expression. 684 the variable 'X' is associte to a prefactor and a constant term. Such that 685 this object can be reprensentet mathematicaly by a * X + b 686 """ 687 688 mult_class = MultVariable # Which class for multiplication with Variable 689 add_class = AddVariable #which class for addition with Variable 690 vartype = 0 # optimization for instance class recognition 691 contract_first = 0 # Optimization for the order of the contracting object 692 #object defining contract first to 1 are the starting point 693 #of a chain of contraction following indices. 694
695 - class VariableError(Exception):
696 """class for error in Variable object""" 697 pass
698
699 - def __init__(self, prefactor=1, variable='x', power=1):
700 """ [prefactor] * Variable ** [power]""" 701 702 self.prefactor = prefactor 703 self.variable = variable 704 self.power = power
705
706 - def copy(self):
707 """provide an indenpedant copy of the object""" 708 709 new = Variable(self.prefactor, self.variable, self.power) 710 return new
711
712 - def simplify(self):
713 """Define How to simplify this object.""" 714 return self
715
716 - def expand(self):
717 """Return a more basic representation of this variable.""" 718 return self
719
720 - def factorize(self):
721 """ try to factorize this""" 722 return self
723 724 # Define basic operation (multiplication, addition, soustraction)
725 - def __mul__(self, obj):
726 """ How to multiply object together 727 product of Variable -> MultVariable 728 """ 729 730 if not hasattr(obj, 'vartype'): # obj is a number 731 if not obj: 732 return 0 733 out = self.copy() 734 out.prefactor *= obj 735 return out 736 737 elif not obj.vartype: # obj is a Variable 738 new = self.mult_class() 739 new.append(self.copy()) 740 new.append(obj.copy()) 741 return new 742 743 elif obj.vartype == 2: #obj is a MultVariable 744 out = self.mult_class() 745 746 for factor in obj: 747 out.append(factor.copy()) 748 out.append(self.copy()) 749 out.prefactor *= obj.prefactor 750 return out 751 752 elif obj.vartype == 1: # obj is a AddVariable 753 new = AddVariable() 754 755 for term in obj: 756 new += self * term 757 return new 758 else: 759 #apply obj * self 760 return NotImplemented
761
762 - def __pow__(self,power):
763 """define power""" 764 copy = self.copy() 765 copy.power = self.power * power 766 return copy
767
768 - def __add__(self, obj):
769 """ How to make an addition 770 Addition of Variable -> AddVariable 771 """ 772 773 if not obj: 774 return self 775 776 try: 777 type = obj.vartype 778 except: #float 779 new = self.add_class() 780 new.append(self.copy()) 781 new.append(ConstantObject(obj)) 782 return new 783 784 785 if not type: # obj is a Variable 786 new = self.add_class() 787 new.append(self.copy()) 788 new.append(obj.copy()) 789 return new 790 791 elif type == 2: # obj is a MultVariable 792 new = self.add_class() 793 new.append(self.copy()) 794 new.append(self.mult_class(obj, obj.prefactor)) 795 return new 796 797 elif type == 1: # obj is an AddVariable 798 new = self.add_class(obj, obj.prefactor) 799 new.append(self.copy()) 800 return new 801 else: 802 # apply obj + self 803 return NotImplemented
804
805 - def __sub__(self, obj):
806 return self + -1 * obj
807
808 - def __rsub__(self, obj):
809 return (-1) * self + obj
810
811 - def __div__(self, obj):
812 """ define the division """ 813 814 if not hasattr(obj, 'vartype'): 815 factor = 1 / obj 816 return factor * self 817 else: 818 return FracVariable(1 * self, 1 * obj)
819
820 - def __rdiv__(self, obj):
821 """Deal division in a inverse way""" 822 823 new = self.copy() 824 if not hasattr(obj, 'vartype'): 825 return FracVariable(obj, new) 826 else: 827 return NotImplemented
828 829 __radd__ = __add__ 830 __iadd__ = __add__ 831 __rmul__ = __mul__ 832 __truediv__ = __div__ 833 __rtruediv__ = __rdiv__ 834
835 - def __eq__(self, obj):
836 """ identical if the variable is the same """ 837 if hasattr(obj,'vartype'): 838 return not obj.vartype and self.variable == obj.variable 839 else: 840 return False
841
842 - def __str__(self):
843 text = '' 844 if self.prefactor != 1: 845 text += str(self.prefactor) + ' * ' 846 text += str(self.variable) 847 if self.power != 1: 848 text += '**%s' % self.power 849 return text
850 851 __repr__ = __str__
852
853 #=============================================================================== 854 # ScalarVariable 855 #=============================================================================== 856 -class ScalarVariable(Variable):
857 """ A concrete symbolic scalar variable 858 """ 859
860 - def __init__(self, variable_name, prefactor=1, power=1):
861 """ initialization of the object with default value """ 862 863 Variable.__init__(self, prefactor, variable_name, power)
864 865
866 - def copy(self):
867 """ Define a independant copy of the object""" 868 new = ScalarVariable(self.variable, self.prefactor, self.power) 869 return new
870
871 #=============================================================================== 872 # AddLorentz 873 #=============================================================================== 874 # Not needed at present stage 875 876 877 #=============================================================================== 878 # MultLorentz 879 #=============================================================================== 880 -class MultLorentz(MultVariable):
881 """Specific class for LorentzObject Multiplication""" 882 883 add_class = AddVariable # Define which class describe the addition 884
885 - def find_lorentzcontraction(self):
886 """return of (pos_object1, indice1) ->(pos_object2,indices2) definng 887 the contraction in this Multiplication.""" 888 889 out = {} 890 len_mult = len(self) 891 # Loop over the element 892 for i, fact in enumerate(self): 893 # and over the indices of this element 894 for j in range(len(fact.lorentz_ind)): 895 # in order to compare with the other element of the multiplication 896 for k in range(i+1,len_mult): 897 fact2 = self[k] 898 try: 899 l = fact2.lorentz_ind.index(fact.lorentz_ind[j]) 900 except: 901 pass 902 else: 903 out[(i, j)] = (k, l) 904 out[(k, l)] = (i, j) 905 return out
906
907 - def find_spincontraction(self):
908 """return of (pos_object1, indice1) ->(pos_object2,indices2) defining 909 the contraction in this Multiplication.""" 910 911 out = {} 912 len_mult = len(self) 913 # Loop over the element 914 for i, fact in enumerate(self): 915 # and over the indices of this element 916 for j in range(len(fact.spin_ind)): 917 # in order to compare with the other element of the multiplication 918 for k in range(i+1, len_mult): 919 fact2 = self[k] 920 try: 921 l = fact2.spin_ind.index(fact.spin_ind[j]) 922 except: 923 pass 924 else: 925 out[(i, j)] = (k, l) 926 out[(k, l)] = (i, j) 927 928 return out
929
930 - def expand(self):
931 """ expand each part of the product and combine them. 932 Try to use a smart order in order to minimize the number of uncontracted indices. 933 """ 934 935 self.unused = self[:] # list of not expanded 936 # made in a list the intersting starting point for the computation 937 basic_end_point = [var for var in self if var.contract_first] 938 product_term = [] #store result of intermediate chains 939 current = None # current point in the working chain 940 941 while self.unused: 942 #Loop untill we have expand everything 943 if not current: 944 # First we need to have a starting point 945 try: 946 # look in priority in basic_end_point (P/S/fermion/...) 947 current = basic_end_point.pop() 948 except: 949 #take one of the remaining 950 current = self.unused.pop() 951 else: 952 #check that this one is not already use 953 if current not in self.unused: 954 current = None 955 continue 956 #remove of the unuse (usualy done in the pop) 957 self.unused.remove(current) 958 959 # initialize the new chain 960 product_term.append(current.expand()) 961 962 # We have a point -> find the next one 963 var = self.neighboor(current) 964 # provide one term which is contracted with current and which is not 965 #yet expanded. 966 if var: 967 product_term[-1] *= var.expand() 968 current = var 969 self.unused.remove(current) 970 continue 971 972 current = None 973 974 # Multiply all those current 975 out = self.prefactor 976 for fact in product_term: 977 out *= fact 978 return out
979
980 - def neighboor(self, home):
981 """return one variable which are contracted with var and not yet expanded""" 982 983 for var in self.unused: 984 if var.has_component(home.lorentz_ind, home.spin_ind): 985 return var 986 return None
987
988 - def check_equivalence(self, obj, i, j, lorentzcontractself, lorentzcontractobj, \ 989 spincontractself, spincontractobj, map):
990 """check if i and j are compatible up to sum up indices""" 991 992 # Fail if not the same class 993 if self[i].__class__ != obj[j].__class__: 994 return False 995 # Fail if not linked to the same particle 996 if hasattr(self[i], 'particle') or hasattr(obj[j], 'particle'): 997 try: 998 samepart = (self[i].particle == obj[j].particle) 999 except: 1000 return False 1001 1002 if not samepart: 1003 return False 1004 1005 # Check if an assignement already exist for any of the factor consider 1006 if map.has_key(i): 1007 if map[i] != j: 1008 # The self factor does't point on the obj factor under focus 1009 return False 1010 elif j in map.values(): 1011 # the obj factor is already mapped by another variable 1012 return False 1013 1014 # Check if the tag information is identical 1015 #if self[i].tag != obj[j].tag: 1016 # return False 1017 1018 # Check all lorentz indices 1019 for k in range(len(self[i].lorentz_ind)): 1020 # Check if the same indices 1021 if self[i].lorentz_ind[k] == obj[j].lorentz_ind[k]: 1022 continue 1023 # Check if those indices are contracted 1024 if (i, k) not in lorentzcontractself or \ 1025 (j, k) not in lorentzcontractobj: 1026 return False 1027 1028 #return object-indices of contraction 1029 i2, k2 = lorentzcontractself[(i, k)] 1030 j2, l2 = lorentzcontractobj[(j, k)] 1031 1032 # Check that both contract at same position 1033 if k2 != l2: 1034 return False 1035 1036 # Check that both object are the same type 1037 if self[i2].__class__ != obj[j2].__class__: 1038 return False 1039 1040 # Check if one of the term is already map 1041 if map.has_key(i2) and map[i2] != j2: 1042 if map[i2] != j2: 1043 return False 1044 else: 1045 # if not mapped, map it 1046 map[i2] = j2 1047 1048 1049 # Do the same but for spin indices 1050 for k in range(len(self[i].spin_ind)): 1051 # Check if the same indices 1052 if self[i].spin_ind[k] == obj[j].spin_ind[k]: 1053 continue 1054 #if not check if this indices is sum 1055 if (i, k) not in spincontractself or \ 1056 (j, k) not in spincontractobj: 1057 1058 return False 1059 1060 #return correspondance 1061 i2, k2 = spincontractself[(i, k)] 1062 j2, l2 = spincontractobj[(j, k)] 1063 1064 # Check that both contract at same position 1065 if k2 != l2: 1066 return False 1067 1068 # Check that both object are the same type 1069 if self[i2].__class__ != obj[j2].__class__: 1070 return False 1071 1072 # Check if one of the term is already map 1073 if map.has_key(i2) and map[i2] != j2: 1074 if map[i2] != j2: 1075 return False 1076 else: 1077 map[i2] = j2 1078 1079 # If pass all the test then this is a possibility 1080 return True
1081
1082 - def find_equivalence(self, obj, pos, lorentzcontractself, lorentzcontractobj, \ 1083 spincontractself, spincontractobj, map):
1084 """Try to achieve to have a mapping between the two representations""" 1085 possibility = [] 1086 1087 for pos2 in range(len(obj)): 1088 init_map = dict(map) 1089 if self.check_equivalence(obj, pos, pos2, lorentzcontractself, \ 1090 lorentzcontractobj, spincontractself, \ 1091 spincontractobj, init_map): 1092 init_map[pos] = pos2 1093 possibility.append(init_map) 1094 1095 if pos + 1 == len(self) and possibility: 1096 return True 1097 for map in possibility: 1098 if self.find_equivalence(obj, pos + 1, lorentzcontractself, \ 1099 lorentzcontractobj, spincontractself, \ 1100 spincontractobj, map): 1101 return True 1102 return False
1103
1104 - def __eq__(self, obj):
1105 1106 # Check Standard Equality 1107 if MultVariable.__eq__(self, obj): 1108 return True 1109 1110 if self.__class__ != obj.__class__ or len(self) != len(obj): 1111 return False 1112 1113 # Check that the number and the type of contraction are identical both 1114 #for spin and lorentz indices 1115 spin_contract_self = self.find_spincontraction() 1116 spin_contract_obj = obj.find_spincontraction() 1117 1118 1119 #check basic consitency 1120 if len(spin_contract_self) != len(spin_contract_obj): 1121 return False 1122 1123 lorentz_contract_self = self.find_lorentzcontraction() 1124 lorentz_contract_obj = obj.find_lorentzcontraction() 1125 #check basic consitency 1126 if len(lorentz_contract_self) != len(lorentz_contract_obj): 1127 return False 1128 1129 # Try to achieve to have a mapping between the two representations 1130 mapping = {} 1131 a = self.find_equivalence(obj, 0, lorentz_contract_self, \ 1132 lorentz_contract_obj, spin_contract_self, \ 1133 spin_contract_obj, mapping) 1134 return a
1135
1136 #=============================================================================== 1137 # LorentzObject 1138 #=============================================================================== 1139 -class LorentzObject(Variable):
1140 """ A symbolic Object for All Helas object. All Helas Object Should 1141 derivated from this class""" 1142 1143 mult_class = MultLorentz # The class for the multiplication 1144 add_class = AddVariable # The class for the addition 1145
1146 - def __init__(self, lorentz_indices, spin_indices, prefactor=1, other_indices=[], 1147 variable=''):
1148 """ initialization of the object with default value """ 1149 1150 self.lorentz_ind = lorentz_indices 1151 self.spin_ind = spin_indices 1152 USE_TAG.update(set(other_indices)) 1153 1154 # Automatic variable_name creation. (interesting for debugging) and 1155 #help to compare object 1156 if not variable: 1157 variable = self.__class__.__name__ 1158 if hasattr(self, 'particle'): 1159 variable += str(self.particle) 1160 if lorentz_indices: 1161 variable += '^{%s}' % ','.join([str(ind) for ind in lorentz_indices]) 1162 if spin_indices: 1163 variable += '_{%s}' % ','.join([str(ind) for ind in spin_indices]) 1164 1165 #call the initialization of the basic class 1166 Variable.__init__(self, prefactor, variable)
1167
1168 - def __pow__(self, power):
1169 """ definition of an auto-contracted object """ 1170 1171 assert power == 2, "Lorentz object cann't have power higher than two" 1172 1173 new = MultLorentz() 1174 new.append(self) 1175 new.append(self.copy()) 1176 return new
1177 1178
1179 - def copy(self):
1180 """return a shadow copy of the object. This is performed in calling 1181 again the __init__ instance""" 1182 1183 #computing of the argument depending of the class 1184 if self.__class__ == LorentzObject: 1185 arg = [self.lorentz_ind] + [self.spin_ind, self.prefactor ] 1186 elif hasattr(self, 'particle'): 1187 arg = self.lorentz_ind + self.spin_ind + [self.particle] + \ 1188 [self.prefactor] 1189 else: 1190 arg = self.lorentz_ind + self.spin_ind + \ 1191 [self.prefactor] 1192 1193 #call the init routine 1194 new = self.__class__(*arg) 1195 new.power = self.power 1196 return new
1197
1198 - def expand(self):
1199 """Expand the content information into LorentzObjectRepresentation.""" 1200 1201 try: 1202 self.representation 1203 except: 1204 self.create_representation() 1205 1206 if self.power == 1: 1207 if self.prefactor == 1: 1208 return self.representation 1209 else: 1210 return self.prefactor * self.representation 1211 elif self.power == 2: 1212 # not possible to have power beyon 2 except for scalar object 1213 return self.prefactor * self.representation * self.representation 1214 else: 1215 assert self.lorentz_ind == self.spin_ind == [] 1216 name = self.representation.get_rep([0]).variable 1217 new = ScalarVariable(name, prefactor=self.prefactor, 1218 power=self.power) 1219 return LorentzObjectRepresentation( 1220 new, self.lorentz_ind, self.spin_ind)
1221
1222 - def create_representation(self):
1223 raise self.VariableError("This Object %s doesn't have define representation" % self.__class__.__name__)
1224
1225 - def __eq__(self, obj):
1226 """redifine equality""" 1227 1228 return (self.__class__ == obj.__class__ and \ 1229 self.lorentz_ind == obj.lorentz_ind and \ 1230 self.spin_ind == obj.spin_ind and \ 1231 self.variable == obj.variable)
1232
1233 - def has_component(self, lor_list, spin_list):
1234 """check if this Lorentz Object have some of those indices""" 1235 1236 1237 for i in lor_list: 1238 if i in self.lorentz_ind: 1239 return True 1240 1241 for i in spin_list: 1242 if i in self.spin_ind: 1243 return True
1244
1245 1246 1247 #=============================================================================== 1248 # IndicesIterator 1249 #=============================================================================== 1250 -class IndicesIterator:
1251 """Class needed for the iterator""" 1252
1253 - def __init__(self, len):
1254 """ create an iterator looping over the indices of a list of len "len" 1255 with each value can take value between 0 and 3 """ 1256 1257 self.len = len # number of indices 1258 if len: 1259 # initialize the position. The first position is -1 due to the method 1260 #in place which start by rising an index before returning smtg 1261 self.data = [-1] + [0] * (len - 1) 1262 else: 1263 # Special case for Scalar object 1264 self.data = 0 1265 self.next = self.nextscalar
1266
1267 - def __iter__(self):
1268 return self
1269
1270 - def next(self):
1271 for i in range(self.len): 1272 if self.data[i] < 3: 1273 self.data[i] += 1 1274 return self.data 1275 else: 1276 self.data[i] = 0 1277 raise StopIteration
1278
1279 - def nextscalar(self):
1280 if self.data: 1281 raise StopIteration 1282 else: 1283 self.data = 1 1284 return [0]
1285
1286 #=============================================================================== 1287 # LorentzObjectRepresentation 1288 #=============================================================================== 1289 -class LorentzObjectRepresentation(dict):
1290 """A concrete representation of the LorentzObject.""" 1291 1292 vartype = 4 # Optimization for instance recognition 1293
1294 - class LorentzObjectRepresentationError(Exception):
1295 """Specify error for LorentzObjectRepresentation"""
1296
1297 - def __init__(self, representation, lorentz_indices, spin_indices):
1298 """ initialize the lorentz object representation""" 1299 1300 self.lorentz_ind = lorentz_indices #lorentz indices 1301 self.nb_lor = len(lorentz_indices) #their number 1302 self.spin_ind = spin_indices #spin indices 1303 self.nb_spin = len(spin_indices) #their number 1304 self.nb_ind = self.nb_lor + self.nb_spin #total number of indices 1305 1306 #self.tag = set(other_indices) #some information 1307 1308 #store the representation 1309 if self.lorentz_ind or self.spin_ind: 1310 dict.__init__(self, representation) 1311 else: 1312 self[(0,)] = representation
1313
1314 - def copy(self):
1315 return self
1316
1317 - def __add__(self, obj, fact=1):
1318 assert(obj.vartype == 4 == self.vartype) # are LorentzObjectRepresentation 1319 1320 if self.lorentz_ind != obj.lorentz_ind or self.spin_ind != obj.spin_ind: 1321 # if the order of indices are different compute a mapping 1322 switch_order = [] 1323 for value in self.lorentz_ind: 1324 try: 1325 index = obj.lorentz_ind.index(value) 1326 except: 1327 raise self.LorentzObjectRepresentationError("Invalid" + \ 1328 "addition. Object doen't have the same lorentz indices:" + \ 1329 "%s != %s" % (self.lorentz_ind, obj.lorentz_ind)) 1330 else: 1331 switch_order.append(index) 1332 for value in self.spin_ind: 1333 try: 1334 index = obj.spin_ind.index(value) 1335 except: 1336 raise self.LorentzObjectRepresentationError("Invalid" + \ 1337 "addition. Object doen't have the same indices %s != %s" % (self.spin_ind, obj.spin_ind) ) 1338 else: 1339 switch_order.append(self.nb_lor + index) 1340 switch = lambda ind : tuple([ind[switch_order[i]] for i in range(len(ind))]) 1341 else: 1342 # no mapping needed (define switch as identity) 1343 switch = lambda ind : (ind) 1344 1345 1346 assert tuple(self.lorentz_ind+self.spin_ind) == tuple(switch(obj.lorentz_ind+obj.spin_ind)), '%s!=%s' % (self.lorentz_ind+self.spin_ind, switch(obj.lorentz_ind+self.spin_ind)) 1347 assert tuple(self.lorentz_ind) == tuple(switch(obj.lorentz_ind)), '%s!=%s' % (tuple(self.lorentz_ind), switch(obj.lorentz_ind)) 1348 1349 # define an empty representation 1350 new = LorentzObjectRepresentation({}, obj.lorentz_ind, obj.spin_ind) 1351 1352 # loop over all indices and fullfill the new object 1353 if fact == 1: 1354 for ind in self.listindices(): 1355 value = obj.get_rep(ind) + self.get_rep(switch(ind)) 1356 #value = self.get_rep(ind) + obj.get_rep(switch(ind)) 1357 new.set_rep(ind, value) 1358 else: 1359 for ind in self.listindices(): 1360 #permute index for the second object 1361 value = self.get_rep(switch(ind)) + fact * obj.get_rep(ind) 1362 #value = fact * obj.get_rep(switch(ind)) + self.get_rep(ind) 1363 new.set_rep(ind, value) 1364 1365 return new
1366 1367 __iadd__ = __add__ 1368
1369 - def __sub__(self, obj):
1370 return self.__add__(obj, fact= -1)
1371
1372 - def __rsub__(self, obj):
1373 return obj.__add__(self, fact= -1)
1374
1375 - def __isub__(self, obj):
1376 return self.__add__(obj, fact= -1)
1377 1378
1379 - def __mul__(self, obj):
1380 """multiplication performing directly the einstein/spin sommation. 1381 """ 1382 1383 if not hasattr(obj, 'vartype') or not self.vartype or obj.vartype==5: 1384 out = LorentzObjectRepresentation({}, self.lorentz_ind, self.spin_ind) 1385 for ind in out.listindices(): 1386 out.set_rep(ind, obj * self.get_rep(ind)) 1387 return out 1388 elif obj.vartype == 3 : 1389 out = self * obj.numerator 1390 out /= obj.denominator 1391 return out 1392 1393 1394 assert(obj.__class__ == LorentzObjectRepresentation), '%s is not valid class for this operation' %type(obj) 1395 1396 # compute information on the status of the index (which are contracted/ 1397 #not contracted 1398 l_ind, sum_l_ind = self.compare_indices(self.lorentz_ind, \ 1399 obj.lorentz_ind) 1400 s_ind, sum_s_ind = self.compare_indices(self.spin_ind, \ 1401 obj.spin_ind) 1402 if not(sum_l_ind or sum_s_ind): 1403 # No contraction made a tensor product 1404 return self.tensor_product(obj) 1405 1406 # elsewher made a spin contraction 1407 # create an empty representation but with correct indices 1408 new_object = LorentzObjectRepresentation({}, l_ind, s_ind) 1409 #loop and fullfill the representation 1410 for indices in new_object.listindices(): 1411 #made a dictionary (pos -> index_value) for how call the object 1412 dict_l_ind = self.pass_ind_in_dict(indices[:len(l_ind)], l_ind) 1413 dict_s_ind = self.pass_ind_in_dict(indices[len(l_ind):], s_ind) 1414 #add the new value 1415 new_object.set_rep(indices, \ 1416 self.contraction(obj, sum_l_ind, sum_s_ind, \ 1417 dict_l_ind, dict_s_ind)) 1418 1419 return new_object
1420 1421 @staticmethod
1422 - def pass_ind_in_dict(indices, key):
1423 """made a dictionary (pos -> index_value) for how call the object""" 1424 if not key: 1425 return {} 1426 out = {} 1427 for i, ind in enumerate(indices): 1428 out[key[i]] = ind 1429 return out
1430 1431 @staticmethod
1432 - def compare_indices(list1, list2):
1433 """return two list, the first one contains the position of non summed 1434 index and the second one the position of summed index.""" 1435 1436 #init object 1437 are_unique = [] 1438 are_sum = [] 1439 # loop over the first list and check if they are in the second list 1440 for indice in list1: 1441 if indice in list2: 1442 are_sum.append(indice) 1443 else: 1444 are_unique.append(indice) 1445 # loop over the second list for additional unique item 1446 for indice in list2: 1447 if indice not in are_sum: 1448 are_unique.append(indice) 1449 1450 # return value 1451 return are_unique, are_sum
1452
1453 - def contraction(self, obj, l_sum, s_sum, l_dict, s_dict):
1454 """ make the Lorentz/spin contraction of object self and obj. 1455 l_sum/s_sum are the position of the sum indices 1456 l_dict/s_dict are dict given the value of the fix indices (indices->value) 1457 """ 1458 1459 out = 0 # initial value for the output 1460 len_l = len(l_sum) #store len for optimization 1461 len_s = len(s_sum) # same 1462 1463 # loop over the possibility for the sum indices and update the dictionary 1464 # (indices->value) 1465 for l_value in IndicesIterator(len_l): 1466 l_dict.update(self.pass_ind_in_dict(l_value, l_sum)) 1467 for s_value in IndicesIterator(len_s): 1468 #s_dict_final = s_dict.copy() 1469 s_dict.update(self.pass_ind_in_dict(s_value, s_sum)) 1470 1471 #return the indices in the correct order 1472 self_ind = self.combine_indices(l_dict, s_dict) 1473 obj_ind = obj.combine_indices(l_dict, s_dict) 1474 1475 # call the object 1476 factor = self.get_rep(self_ind) 1477 factor *= obj.get_rep(obj_ind) 1478 1479 1480 if factor: 1481 #compute the prefactor due to the lorentz contraction 1482 factor *= (-1) ** (len(l_value) - l_value.count(0)) 1483 out += factor 1484 return out
1485
1486 - def combine_indices(self, l_dict, s_dict):
1487 """return the indices in the correct order following the dicts rules""" 1488 1489 out = [] 1490 # First for the Lorentz indices 1491 for value in self.lorentz_ind: 1492 out.append(l_dict[value]) 1493 # Same for the spin 1494 for value in self.spin_ind: 1495 out.append(s_dict[value]) 1496 1497 return out
1498
1499 - def tensor_product(self, obj):
1500 """ return the tensorial product of the object""" 1501 assert(obj.vartype == 4) #isinstance(obj, LorentzObjectRepresentation)) 1502 1503 new_object = LorentzObjectRepresentation({}, \ 1504 self.lorentz_ind + obj.lorentz_ind, \ 1505 self.spin_ind + obj.spin_ind) 1506 1507 #some shortcut 1508 lor1 = self.nb_lor 1509 lor2 = obj.nb_lor 1510 spin1 = self.nb_spin 1511 spin2 = obj.nb_spin 1512 1513 #define how to call build the indices first for the first object 1514 if lor1 == 0 == spin1: 1515 #special case for scalar 1516 selfind = lambda indices: [0] 1517 else: 1518 selfind = lambda indices: indices[:lor1] + \ 1519 indices[lor1 + lor2: lor1 + lor2 + spin1] 1520 1521 #then for the second 1522 if lor2 == 0 == spin2: 1523 #special case for scalar 1524 objind = lambda indices: [0] 1525 else: 1526 objind = lambda indices: indices[lor1: lor1 + lor2] + \ 1527 indices[lor1 + lor2 + spin1:] 1528 1529 # loop on the indices and assign the product 1530 for indices in new_object.listindices(): 1531 new_object.set_rep(indices, self.get_rep(tuple(selfind(indices))) * 1532 obj.get_rep(tuple(objind(indices)))) 1533 1534 return new_object
1535 1536
1537 - def __div__(self, obj):
1538 """ define division 1539 Only division by scalar!!!""" 1540 1541 out = LorentzObjectRepresentation({}, self.lorentz_ind, self.spin_ind) 1542 try: 1543 obj.vartype 1544 except: 1545 for ind in out.listindices(): 1546 out.set_rep(ind, self.get_rep(ind) / obj) 1547 else: 1548 for ind in out.listindices(): 1549 out.set_rep(ind, self.get_rep(ind) / obj.get_rep([0])) 1550 1551 return out
1552 1553 __rmul__ = __mul__ 1554 __imul__ = __mul__ 1555 __truediv__ = __div__ 1556 __rtruediv__ = __div__ 1557 __rdiv__ = __div__ 1558
1559 - def factorize(self):
1560 """Try to factorize each component""" 1561 for ind, fact in self.items(): 1562 if fact: 1563 self.set_rep(ind, fact.factorize()) 1564 return self
1565
1566 - def simplify(self):
1567 """Check if we can simplify the object (check for non treated Sum)""" 1568 1569 #Look for internal simplification 1570 for ind, term in self.items(): 1571 if hasattr(term, 'vartype'): 1572 self[ind] = term.simplify() 1573 1574 #no additional simplification 1575 return self
1576
1577 - def listindices(self):
1578 """Return an iterator in order to be able to loop easily on all the 1579 indices of the object.""" 1580 return IndicesIterator(self.nb_ind)
1581
1582 - def get_rep(self, indices):
1583 """return the value/Variable associate to the indices""" 1584 1585 return self[tuple(indices)]
1586
1587 - def set_rep(self, indices, value):
1588 """assign 'value' at the indices position""" 1589 1590 self[tuple(indices)] = value
1591
1592 - def __eq__(self, obj):
1593 """Check that two representation are identical""" 1594 1595 if self.__class__ != obj.__class__: 1596 if self.nb_spin == 0 == self.nb_lor and \ 1597 isinstance(obj, Number): 1598 return self.get_rep([0]) == obj 1599 else: 1600 return False 1601 if len(self.lorentz_ind) != len(obj.lorentz_ind): 1602 return False 1603 if len(self.spin_ind) != len(obj.spin_ind): 1604 return False 1605 1606 for ind in self.listindices(): 1607 self_comp = self.get_rep(ind) 1608 try: 1609 obj_comp = obj.get_rep(ind) 1610 except: 1611 return False 1612 1613 if self_comp != obj_comp: 1614 return False 1615 if hasattr(self_comp, 'vartype'): 1616 if self_comp.prefactor != obj_comp.prefactor: 1617 return False 1618 1619 1620 #Pass all the test 1621 return True
1622
1623 - def __str__(self):
1624 """ string representation """ 1625 text = 'number of lorentz index :' + str(self.nb_lor) + '\n' 1626 text += 'number of spin index :' + str(self.nb_spin) + '\n' 1627 #text += 'other info ' + str(self.tag) + '\n' 1628 for ind in self.listindices(): 1629 ind = tuple(ind) 1630 text += str(ind) + ' --> ' 1631 text += str(self.get_rep(ind)) + '\n' 1632 return text
1633
1634 #=============================================================================== 1635 # ConstantObject 1636 #=============================================================================== 1637 -class ConstantObject(LorentzObjectRepresentation):
1638 1639 vartype = 5 1640 lorentz_ind = [] 1641 spin_ind = [] 1642 nb_ind = 0 1643 #tag = [] 1644 variable = '0' 1645 prefactor = 1 1646 power = 1 1647
1648 - def __init__(self, var=0):
1649 1650 self.value = var 1651 if var: 1652 self.variable = str(var)
1653 # self.vartype = 0 #act as a Variable 1654
1655 - def copy(self):
1656 """ return a copy of the object """ 1657 return ConstantObject(self.value)
1658
1659 - def __add__(self, obj):
1660 """Addition with a constant""" 1661 1662 if not self.value: 1663 return obj 1664 1665 if not hasattr(obj, 'vartype'): 1666 return ConstantObject(self.value + obj) 1667 elif obj.vartype == 0: 1668 new = obj.add_class() 1669 new.append(obj.copy()) 1670 new.append(self) 1671 return new 1672 elif obj.vartype == 5: 1673 return ConstantObject(self.value + obj.value) 1674 elif obj.vartype == 2: 1675 new = obj.add_class() 1676 new.append(obj) 1677 new.append(self) 1678 return new 1679 elif obj.vartype == 1: 1680 new = obj.__class__() 1681 1682 # Define in the symmetric 1683 return NotImplemented 1684 else: 1685 return obj
1686 1687 __radd__ = __add__ 1688 __iadd__ = __add__ 1689
1690 - def __mul__(self, obj):
1691 """Zero is absorbant""" 1692 if self.value: 1693 return self.value * obj 1694 else: 1695 return self
1696 __rmul__ = __mul__ 1697 __imul__ = __mul__ 1698
1699 - def get_rep(self, ind):
1700 """return representation""" 1701 return self.value
1702
1703 - def __eq__(self, obj):
1704 if type(obj) == ConstantObject: 1705 return obj.value == self.value 1706 elif self.value: 1707 return False 1708 elif obj: 1709 return False 1710 else: 1711 return True
1712
1713 - def expand(self):
1714 return self
1715
1716 - def __str__(self):
1717 return str(self.value)
1718