1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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
57 precision_cut = 1e-14
58
59 USE_TAG=set()
60
61 depth=-1
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
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
84
85
86
87
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
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
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
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
125 """Define the Equality of two Object"""
126
127 return (self.numerator == obj.numerator) and \
128 (self.denominator == obj.denominator)
129
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
142 """Deal with division"""
143
144
145 return FracVariable(self.numerator * 1, self.denominator * obj)
146
147
148
149 __truediv__ = __div__
150
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
166 if self.vartype == 4:
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
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
187 """ A list of Variable/ConstantObject/... This object represent the operation
188 between those object."""
189
190
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
198 list.__init__(self, old_data)
199
201 """ return a deep copy of the object"""
202 return self.__class__(self, self.prefactor)
203
205 """ apply rule of simplification """
206
207
208 if len(self) == 1:
209 return self.prefactor * self[0].simplify()
210
211 if short:
212 return self
213
214
215 constant = 0
216
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
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
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
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
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'):
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:
287 new = AddVariable()
288 for term in self:
289 new += term * obj
290 return new
291 else:
292
293 return NotImplemented
294
325
327 """ Implement division"""
328
329 if not hasattr(obj, 'vartype'):
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
346
348 return self + (-1) * obj
349
350 __radd__ = __add__
351 __iadd__ = __add__
352 __rmul__ = __mul__
353 __truediv__ = __div__
354 __rtruediv__ = __rdiv__
355
357 return (-1) * self + obj
358
360 """ add a newVariable in the Multiplication list """
361 if obj.prefactor:
362 list.append(self, obj)
363
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
381 return True
382
384 """Define the unequality"""
385 return not self.__eq__(obj)
386
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
398
399
400 count = {}
401 max, maxvar = 0, None
402 for term in self:
403 if term.vartype == 2:
404 for var in term:
405 count[var.variable] = count.setdefault(var.variable, 0) + 1
406 if count[var.variable] > max:
407
408 max, maxvar = max + 1, var
409 else:
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
417 """ try to factorize as much as possible the expression """
418
419
420
421 max, maxvar = self.count_term()
422 maxvar = maxvar.__class__(maxvar.variable)
423 if max <= 1:
424
425
426 return self
427 else:
428
429
430 newadd = AddVariable()
431 constant = AddVariable()
432
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 :
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
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
469 else:
470
471 newadd = newadd[0]
472
473
474
475
476 if maxvar.power > 1:
477 maxvar = maxvar.copy()
478 maxvar.power = 1
479
480
481
482 if newadd.vartype == 2:
483 newadd.append(maxvar)
484 else:
485 newadd = MultVariable([maxvar, newadd])
486
487
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
496
497 return AddVariable([newadd, constant])
498 else:
499 if constant.vartype == 5 and constant != 0:
500
501 return AddVariable([newadd, constant])
502
503
504 return newadd
505
510 """ A list of Variable with multiplication as operator between themselves.
511 """
512
513 add_class = AddVariable
514 vartype = 2
515
516 - def __init__(self, old_data=[], prefactor=1):
517 """ initialization of the object with default value """
518
519 self.prefactor = prefactor
520
521 list.__init__(self, old_data)
522
524 """ return a copy """
525 return self.__class__(self, self.prefactor)
526
528 """ simplify the product"""
529
530
531 self[:] = [fact.simplify() for fact in self]
532
533
534
535 if len(self) == 1:
536 return self.prefactor * self[0]
537 return self
538
540 """Try to factorize this (nothing to do)"""
541 return self
542
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
554 """Define the multiplication with different object"""
555
556 if not hasattr(obj, 'vartype'):
557 return self.__class__(self, self.prefactor * obj)
558
559 elif not obj.vartype:
560 return NotImplemented
561
562 elif obj.vartype == 2:
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:
570 new = self.add_class(obj, obj.prefactor)
571 new[:] = [data.__mul__(self) for data in new]
572 return new
573
574 else:
575
576 return NotImplemented
577
578
580 """ define the adition with different object"""
581
582 if not obj:
583 return self
584
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:
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
599 return NotImplemented
600
602 return self + (-1) * obj
603
606
608 return (-1) * self + obj
609
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
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
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
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
663 """ Define when two Multvariable are not identical"""
664 return not self.__eq__(obj)
665
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
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
689 add_class = AddVariable
690 vartype = 0
691 contract_first = 0
692
693
694
696 """class for error in Variable object"""
697 pass
698
699 - def __init__(self, prefactor=1, variable='x', power=1):
705
711
713 """Define How to simplify this object."""
714 return self
715
717 """Return a more basic representation of this variable."""
718 return self
719
721 """ try to factorize this"""
722 return self
723
724
726 """ How to multiply object together
727 product of Variable -> MultVariable
728 """
729
730 if not hasattr(obj, 'vartype'):
731 if not obj:
732 return 0
733 out = self.copy()
734 out.prefactor *= obj
735 return out
736
737 elif not obj.vartype:
738 new = self.mult_class()
739 new.append(self.copy())
740 new.append(obj.copy())
741 return new
742
743 elif obj.vartype == 2:
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:
753 new = AddVariable()
754
755 for term in obj:
756 new += self * term
757 return new
758 else:
759
760 return NotImplemented
761
767
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:
779 new = self.add_class()
780 new.append(self.copy())
781 new.append(ConstantObject(obj))
782 return new
783
784
785 if not type:
786 new = self.add_class()
787 new.append(self.copy())
788 new.append(obj.copy())
789 return new
790
791 elif type == 2:
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:
798 new = self.add_class(obj, obj.prefactor)
799 new.append(self.copy())
800 return new
801 else:
802
803 return NotImplemented
804
806 return self + -1 * obj
807
809 return (-1) * self + obj
810
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
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
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
850
851 __repr__ = __str__
852
857 """ A concrete symbolic scalar variable
858 """
859
860 - def __init__(self, variable_name, prefactor=1, power=1):
864
865
870
871
872
873
874
875
876
877
878
879
880 -class MultLorentz(MultVariable):
881 """Specific class for LorentzObject Multiplication"""
882
883 add_class = AddVariable
884
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
892 for i, fact in enumerate(self):
893
894 for j in range(len(fact.lorentz_ind)):
895
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
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
914 for i, fact in enumerate(self):
915
916 for j in range(len(fact.spin_ind)):
917
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
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[:]
936
937 basic_end_point = [var for var in self if var.contract_first]
938 product_term = []
939 current = None
940
941 while self.unused:
942
943 if not current:
944
945 try:
946
947 current = basic_end_point.pop()
948 except:
949
950 current = self.unused.pop()
951 else:
952
953 if current not in self.unused:
954 current = None
955 continue
956
957 self.unused.remove(current)
958
959
960 product_term.append(current.expand())
961
962
963 var = self.neighboor(current)
964
965
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
975 out = self.prefactor
976 for fact in product_term:
977 out *= fact
978 return out
979
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
993 if self[i].__class__ != obj[j].__class__:
994 return False
995
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
1006 if map.has_key(i):
1007 if map[i] != j:
1008
1009 return False
1010 elif j in map.values():
1011
1012 return False
1013
1014
1015
1016
1017
1018
1019 for k in range(len(self[i].lorentz_ind)):
1020
1021 if self[i].lorentz_ind[k] == obj[j].lorentz_ind[k]:
1022 continue
1023
1024 if (i, k) not in lorentzcontractself or \
1025 (j, k) not in lorentzcontractobj:
1026 return False
1027
1028
1029 i2, k2 = lorentzcontractself[(i, k)]
1030 j2, l2 = lorentzcontractobj[(j, k)]
1031
1032
1033 if k2 != l2:
1034 return False
1035
1036
1037 if self[i2].__class__ != obj[j2].__class__:
1038 return False
1039
1040
1041 if map.has_key(i2) and map[i2] != j2:
1042 if map[i2] != j2:
1043 return False
1044 else:
1045
1046 map[i2] = j2
1047
1048
1049
1050 for k in range(len(self[i].spin_ind)):
1051
1052 if self[i].spin_ind[k] == obj[j].spin_ind[k]:
1053 continue
1054
1055 if (i, k) not in spincontractself or \
1056 (j, k) not in spincontractobj:
1057
1058 return False
1059
1060
1061 i2, k2 = spincontractself[(i, k)]
1062 j2, l2 = spincontractobj[(j, k)]
1063
1064
1065 if k2 != l2:
1066 return False
1067
1068
1069 if self[i2].__class__ != obj[j2].__class__:
1070 return False
1071
1072
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
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
1105
1106
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
1114
1115 spin_contract_self = self.find_spincontraction()
1116 spin_contract_obj = obj.find_spincontraction()
1117
1118
1119
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
1126 if len(lorentz_contract_self) != len(lorentz_contract_obj):
1127 return False
1128
1129
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
1140 """ A symbolic Object for All Helas object. All Helas Object Should
1141 derivated from this class"""
1142
1143 mult_class = MultLorentz
1144 add_class = AddVariable
1145
1146 - def __init__(self, lorentz_indices, spin_indices, prefactor=1, other_indices=[],
1147 variable=''):
1167
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
1197
1221
1223 raise self.VariableError("This Object %s doesn't have define representation" % self.__class__.__name__)
1224
1232
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
1251 """Class needed for the iterator"""
1252
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
1258 if len:
1259
1260
1261 self.data = [-1] + [0] * (len - 1)
1262 else:
1263
1264 self.data = 0
1265 self.next = self.nextscalar
1266
1269
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
1280 if self.data:
1281 raise StopIteration
1282 else:
1283 self.data = 1
1284 return [0]
1285
1290 """A concrete representation of the LorentzObject."""
1291
1292 vartype = 4
1293
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
1301 self.nb_lor = len(lorentz_indices)
1302 self.spin_ind = spin_indices
1303 self.nb_spin = len(spin_indices)
1304 self.nb_ind = self.nb_lor + self.nb_spin
1305
1306
1307
1308
1309 if self.lorentz_ind or self.spin_ind:
1310 dict.__init__(self, representation)
1311 else:
1312 self[(0,)] = representation
1313
1316
1318 assert(obj.vartype == 4 == self.vartype)
1319
1320 if self.lorentz_ind != obj.lorentz_ind or self.spin_ind != obj.spin_ind:
1321
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
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
1350 new = LorentzObjectRepresentation({}, obj.lorentz_ind, obj.spin_ind)
1351
1352
1353 if fact == 1:
1354 for ind in self.listindices():
1355 value = obj.get_rep(ind) + self.get_rep(switch(ind))
1356
1357 new.set_rep(ind, value)
1358 else:
1359 for ind in self.listindices():
1360
1361 value = self.get_rep(switch(ind)) + fact * obj.get_rep(ind)
1362
1363 new.set_rep(ind, value)
1364
1365 return new
1366
1367 __iadd__ = __add__
1368
1370 return self.__add__(obj, fact= -1)
1371
1373 return obj.__add__(self, fact= -1)
1374
1376 return self.__add__(obj, fact= -1)
1377
1378
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
1397
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
1404 return self.tensor_product(obj)
1405
1406
1407
1408 new_object = LorentzObjectRepresentation({}, l_ind, s_ind)
1409
1410 for indices in new_object.listindices():
1411
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
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
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
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
1437 are_unique = []
1438 are_sum = []
1439
1440 for indice in list1:
1441 if indice in list2:
1442 are_sum.append(indice)
1443 else:
1444 are_unique.append(indice)
1445
1446 for indice in list2:
1447 if indice not in are_sum:
1448 are_unique.append(indice)
1449
1450
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
1460 len_l = len(l_sum)
1461 len_s = len(s_sum)
1462
1463
1464
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
1469 s_dict.update(self.pass_ind_in_dict(s_value, s_sum))
1470
1471
1472 self_ind = self.combine_indices(l_dict, s_dict)
1473 obj_ind = obj.combine_indices(l_dict, s_dict)
1474
1475
1476 factor = self.get_rep(self_ind)
1477 factor *= obj.get_rep(obj_ind)
1478
1479
1480 if factor:
1481
1482 factor *= (-1) ** (len(l_value) - l_value.count(0))
1483 out += factor
1484 return out
1485
1487 """return the indices in the correct order following the dicts rules"""
1488
1489 out = []
1490
1491 for value in self.lorentz_ind:
1492 out.append(l_dict[value])
1493
1494 for value in self.spin_ind:
1495 out.append(s_dict[value])
1496
1497 return out
1498
1500 """ return the tensorial product of the object"""
1501 assert(obj.vartype == 4)
1502
1503 new_object = LorentzObjectRepresentation({}, \
1504 self.lorentz_ind + obj.lorentz_ind, \
1505 self.spin_ind + obj.spin_ind)
1506
1507
1508 lor1 = self.nb_lor
1509 lor2 = obj.nb_lor
1510 spin1 = self.nb_spin
1511 spin2 = obj.nb_spin
1512
1513
1514 if lor1 == 0 == spin1:
1515
1516 selfind = lambda indices: [0]
1517 else:
1518 selfind = lambda indices: indices[:lor1] + \
1519 indices[lor1 + lor2: lor1 + lor2 + spin1]
1520
1521
1522 if lor2 == 0 == spin2:
1523
1524 objind = lambda indices: [0]
1525 else:
1526 objind = lambda indices: indices[lor1: lor1 + lor2] + \
1527 indices[lor1 + lor2 + spin1:]
1528
1529
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
1552
1553 __rmul__ = __mul__
1554 __imul__ = __mul__
1555 __truediv__ = __div__
1556 __rtruediv__ = __div__
1557 __rdiv__ = __div__
1558
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
1567 """Check if we can simplify the object (check for non treated Sum)"""
1568
1569
1570 for ind, term in self.items():
1571 if hasattr(term, 'vartype'):
1572 self[ind] = term.simplify()
1573
1574
1575 return self
1576
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
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
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
1621 return True
1622
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
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
1638
1639 vartype = 5
1640 lorentz_ind = []
1641 spin_ind = []
1642 nb_ind = 0
1643
1644 variable = '0'
1645 prefactor = 1
1646 power = 1
1647
1649
1650 self.value = var
1651 if var:
1652 self.variable = str(var)
1653
1654
1656 """ return a copy of the object """
1657 return ConstantObject(self.value)
1658
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
1683 return NotImplemented
1684 else:
1685 return obj
1686
1687 __radd__ = __add__
1688 __iadd__ = __add__
1689
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
1700 """return representation"""
1701 return self.value
1702
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
1715
1717 return str(self.value)
1718