1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 """Classes and methods required for all calculations related to SU(N) color
17 algebra."""
18
19 import array
20 import copy
21 import fractions
22 import itertools
23 import madgraph.various.misc as misc
29 """Parent class for all color objects like T, Tr, f, d, ... Any new color
30 object MUST inherit from this class!"""
31
33 """Create a new ColorObject, assuming an integer array"""
34 return super(ColorObject, cls).__new__(cls, 'i', args)
35
37 """Special method needed to pickle color objects correctly"""
38 return (self.__class__, tuple([i for i in self]))
39
41 """Returns a standard string representation."""
42
43 return '%s(%s)' % (self.__class__.__name__,
44 ','.join([str(i) for i in self]))
45
46 __repr__ = __str__
47
49 """Simplification rules, to be overwritten for each new color object!
50 Should return a color factor or None if no simplification is possible"""
51 return None
52
54 """Pair simplification rules, to be overwritten for each new color
55 object! Should return a color factor or None if no simplification
56 is possible"""
57 return None
58
60 """Complex conjugation. By default, the ordering of color index is
61 reversed. Can be overwritten for specific color objects like T,..."""
62
63 self.reverse()
64 return self
65
67 """Replace current indices following the rules listed in the replacement
68 dictionary written as {old_index:new_index,...}. Deals correctly with
69 the replacement by allowing only one single replacement."""
70
71 for i, index in enumerate(self):
72 try:
73 self[i] = repl_dict[index]
74 except KeyError:
75 continue
76
78 """Return a real copy of the current object."""
79 return globals()[self.__class__.__name__](*self)
80
81 __copy__ = create_copy
82
83
84
85
86
87 -class Tr(ColorObject):
88 """The trace color object"""
89
91 """Implement simple trace simplifications and cyclicity, and
92 Tr(a,x,b,x,c) = 1/2(Tr(a,c)Tr(b)-1/Nc Tr(a,b,c))"""
93
94
95 if len(self) == 1:
96 col_str = ColorString()
97 col_str.coeff = fractions.Fraction(0, 1)
98 return ColorFactor([col_str])
99
100
101 if len(self) == 0:
102 col_str = ColorString()
103 col_str.Nc_power = 1
104 return ColorFactor([col_str])
105
106
107 if self[0] != min(self):
108 pos = self.index(min(self))
109 new = self[pos:] + self[:pos]
110 return ColorFactor([ColorString([Tr(*new)])])
111
112
113 for i1, index1 in enumerate(self):
114 for i2, index2 in enumerate(self[i1 + 1:]):
115 if index1 == index2:
116 a = self[:i1]
117 b = self[i1 + 1:i1 + i2 + 1]
118 c = self[i1 + i2 + 2:]
119 col_str1 = ColorString([Tr(*(a + c)), Tr(*b)])
120 col_str2 = ColorString([Tr(*(a + b + c))])
121 col_str1.coeff = fractions.Fraction(1, 2)
122 col_str2.coeff = fractions.Fraction(-1, 2)
123 col_str2.Nc_power = -1
124 return ColorFactor([col_str1, col_str2])
125
126 return None
127
129 """Implement Tr product simplification:
130 Tr(a,x,b)Tr(c,x,d) = 1/2(Tr(a,d,c,b)-1/Nc Tr(a,b)Tr(c,d)) and
131 Tr(a,x,b)T(c,x,d,i,j) = 1/2(T(c,b,a,d,i,j)-1/Nc Tr(a,b)T(c,d,i,j))"""
132
133
134 if isinstance(col_obj, Tr):
135 for i1, index1 in enumerate(self):
136 for i2, index2 in enumerate(col_obj):
137 if index1 == index2:
138 a = self[:i1]
139 b = self[i1 + 1:]
140 c = col_obj[:i2]
141 d = col_obj[i2 + 1:]
142 col_str1 = ColorString([Tr(*(a + d + c + b))])
143 col_str2 = ColorString([Tr(*(a + b)), Tr(*(c + d))])
144 col_str1.coeff = fractions.Fraction(1, 2)
145 col_str2.coeff = fractions.Fraction(-1, 2)
146 col_str2.Nc_power = -1
147 return ColorFactor([col_str1, col_str2])
148
149
150 if isinstance(col_obj, T):
151 for i1, index1 in enumerate(self):
152 for i2, index2 in enumerate(col_obj[:-2]):
153 if index1 == index2:
154 a = self[:i1]
155 b = self[i1 + 1:]
156 c = col_obj[:i2]
157 d = col_obj[i2 + 1:-2]
158 ij = col_obj[-2:]
159 col_str1 = ColorString([T(*(c + b + a + d + ij))])
160 col_str2 = ColorString([Tr(*(a + b)), T(*(c + d) + ij)])
161 col_str1.coeff = fractions.Fraction(1, 2)
162 col_str2.coeff = fractions.Fraction(-1, 2)
163 col_str2.Nc_power = -1
164 return ColorFactor([col_str1, col_str2])
165
166 return None
167
168
169
170
171 -class ColorOne(ColorObject):
172 """The one of the color object"""
173
175 """Check for no index"""
176
177 assert len(args) == 0 , "ColorOne objects must have no index!"
178
179 super(ColorOne, self).__init__()
180
182 """"""
183 assert len(self)==0, "There is argument(s) in color object ColorOne."
184 col_str = ColorString()
185 col_str.coeff = fractions.Fraction(1, 1)
186 return ColorFactor([col_str])
187
188
190 """Implement ColorOne product simplification"""
191
192 if any(isinstance(col_obj, c_type) for c_type in [Tr,T,f,d,ColorOne]):
193 col_str = ColorString([col_obj])
194 return ColorFactor([col_str])
195 return None
196
197
198
199
200
201 -class T(ColorObject):
202 """The T color object. Last two indices have a special meaning"""
203
205 """Check for at least two indices"""
206
207 assert len(args) > 1 , "T objects must have at least two indices!"
208
209 super(T, self).__init__()
210
212 """Implement T(a,b,c,...,i,i) = Tr(a,b,c,...) and
213 T(a,x,b,x,c,i,j) = 1/2(T(a,c,i,j)Tr(b)-1/Nc T(a,b,c,i,j))"""
214
215
216 if self[-2] == self[-1]:
217 return ColorFactor([ColorString([Tr(*self[:-2])])])
218
219
220 for i1, index1 in enumerate(self[:-2]):
221 for i2, index2 in enumerate(self[i1 + 1:-2]):
222 if index1 == index2:
223 a = self[:i1]
224 b = self[i1 + 1:i1 + i2 + 1]
225 c = self[i1 + i2 + 2:-2]
226 ij = self[-2:]
227 col_str1 = ColorString([T(*(a + c + ij)), Tr(*b)])
228 col_str2 = ColorString([T(*(a + b + c + ij))])
229 col_str1.coeff = fractions.Fraction(1, 2)
230 col_str2.coeff = fractions.Fraction(-1, 2)
231 col_str2.Nc_power = -1
232 return ColorFactor([col_str1, col_str2])
233
234 return None
235
237 """Implement T(a,...,i,j)T(b,...,j,k) = T(a,...,b,...,i,k)
238 and T(a,x,b,i,j)T(c,x,d,k,l) = 1/2(T(a,d,i,l)T(c,b,k,j)
239 -1/Nc T(a,b,i,j)T(c,d,k,l))."""
240
241 if isinstance(col_obj, T):
242 ij1 = self[-2:]
243 ij2 = col_obj[-2:]
244
245
246 if ij1[1] == ij2[0]:
247 return ColorFactor([ColorString([T(*(self[:-2] + \
248 col_obj[:-2] + \
249 array.array('i', [ij1[0],
250 ij2[1]])))])])
251
252
253
254 for i1, index1 in enumerate(self[:-2]):
255 for i2, index2 in enumerate(col_obj[:-2]):
256 if index1 == index2:
257 a = self[:i1]
258 b = self[i1 + 1:-2]
259 c = col_obj[:i2]
260 d = col_obj[i2 + 1:-2]
261 col_str1 = ColorString([T(*(a + d + \
262 array.array('i',
263 [ij1[0], ij2[1]]))),
264 T(*(c + b + \
265 array.array('i',
266 [ij2[0], ij1[1]])))])
267 col_str2 = ColorString([T(*(a + b + \
268 array.array('i',
269 [ij1[0], ij1[1]]))),
270 T(*(c + d + \
271 array.array('i',
272 [ij2[0], ij2[1]])))])
273 col_str1.coeff = fractions.Fraction(1, 2)
274 col_str2.coeff = fractions.Fraction(-1, 2)
275 col_str2.Nc_power = -1
276 return ColorFactor([col_str1, col_str2])
277
279 """Complex conjugation. Overwritten here because the two last indices
280 should be treated differently"""
281
282
283 l1 = self[:-2]
284 l1.reverse()
285 l2 = self[-2:]
286 l2.reverse()
287 self[:] = l1 + l2
288 return self
289
290
291
292
293 -class f(ColorObject):
294 """The f color object"""
295
297 """Ensure f and d objects have strictly 3 indices"""
298
299 assert len(args) == 3, "f and d objects must have three indices!"
300
301 super(f, self).__init__()
302
303
305 """Implement only the replacement rule
306 f(a,b,c)=-2ITr(a,b,c)+2ITr(c,b,a)"""
307
308 indices = self[:]
309 col_str1 = ColorString([Tr(*indices)])
310 indices.reverse()
311 col_str2 = ColorString([Tr(*indices)])
312
313 col_str1.coeff = fractions.Fraction(-2, 1)
314 col_str2.coeff = fractions.Fraction(2, 1)
315
316 col_str1.is_imaginary = True
317 col_str2.is_imaginary = True
318
319 return ColorFactor([col_str1, col_str2])
320
321
322
323
324 -class d(f):
325 """The d color object"""
326
328 """Implement only the replacement rule
329 d(a,b,c)=2Tr(a,b,c)+2Tr(c,b,a)"""
330
331 indices = self[:]
332 col_str1 = ColorString([Tr(*indices)])
333 indices.reverse()
334 col_str2 = ColorString([Tr(*indices)])
335
336 col_str1.coeff = fractions.Fraction(2, 1)
337 col_str2.coeff = fractions.Fraction(2, 1)
338
339 return ColorFactor([col_str1, col_str2])
340
341
342
343
344
345 -class Epsilon(ColorObject):
346 """Epsilon_ijk color object for three triplets"""
347
349 """Ensure e_ijk objects have strictly 3 indices"""
350
351 super(Epsilon, self).__init__()
352 assert len(args) == 3, "Epsilon objects must have three indices!"
353
354 @staticmethod
356 '''\
357 Given a permutation of the digits 0..N in order as a list,
358 returns its parity (or sign): +1 for even parity; -1 for odd.
359 '''
360 lst = lst[:]
361 sort =lst[:]
362 if not order:
363 order = lst[:]
364 order.sort()
365 parity = 1
366 for i in range(0,len(lst)-1):
367 if lst[i] != order[i]:
368 parity *= -1
369 mn = lst.index(order[i])
370 lst[i],lst[mn] = lst[mn],lst[i]
371 return parity
372
374 """Implement epsilon(i,k,j) = -epsilon(i,j,k) i<j<k"""
375
376
377
378
379 order_list = list(self[:])
380 order_list.sort()
381
382 if list(self[:]) != order_list:
383 col_str1 = ColorString([Epsilon(*order_list)])
384 col_str1.coeff = self.perm_parity(self[:], order_list)
385 return ColorFactor([col_str1])
386
388 """Implement e_ijk ae_ilm = T(j,l)T(k,m) - T(j,m)T(k,l) and
389 e_ijk T(l,k) = e_ikl"""
390
391
392 if isinstance(col_obj, EpsilonBar):
393
394 incommon = False
395 eps_indices = self[:]
396 aeps_indices = col_obj[:]
397 for i in self:
398 if i in col_obj:
399 incommon = True
400 com_index_eps = self.index(i)
401 com_index_aeps = col_obj.index(i)
402
403 if incommon:
404 eps_indices = self[com_index_eps:] + self[:com_index_eps]
405 aeps_indices = col_obj[com_index_aeps:] + col_obj[:com_index_aeps]
406 col_str1 = ColorString([T(eps_indices[1], aeps_indices[1]),
407 T(eps_indices[2], aeps_indices[2])])
408 col_str2 = ColorString([T(eps_indices[1], aeps_indices[2]),
409 T(eps_indices[2], aeps_indices[1])])
410
411 col_str2.coeff = fractions.Fraction(-1, 1)
412
413 return ColorFactor([col_str1, col_str2])
414
415
416 if isinstance(col_obj, T) and len(col_obj) == 2 and col_obj[1] in self:
417
418 com_index = self.index(col_obj[1])
419 new_self = copy.copy(self)
420 new_self[com_index] = col_obj[0]
421
422 return ColorFactor([ColorString([new_self])])
423
424
426 """Complex conjugation. Overwritten here because complex conjugation
427 interchange triplets and antitriplets."""
428
429 return EpsilonBar(*self)
430
433 """Epsilon_ijk color object for three antitriplets"""
434
436 """Ensure e_ijk objects have strictly 3 indices"""
437
438 super(EpsilonBar, self).__init__()
439 assert len(args) == 3, "EpsilonBar objects must have three indices!"
440
442 """Implement ebar_ijk T(k,l) = e_ikl"""
443
444
445 if isinstance(col_obj, T) and len(col_obj) == 2 and col_obj[0] in self:
446
447 com_index = self.index(col_obj[0])
448 new_self = copy.copy(self)
449 new_self[com_index] = col_obj[1]
450
451 return ColorFactor([ColorString([new_self])])
452
454 """Implement epsilon(i,k,j) = -epsilon(i,j,k) i<j<k"""
455
456
457 order_list = list(self[:])
458 order_list.sort()
459
460 if list(self[:]) != order_list:
461 col_str1 = ColorString([EpsilonBar(*order_list)])
462 col_str1.coeff = Epsilon.perm_parity(self[:], order_list)
463 return ColorFactor([col_str1])
464
466 """Complex conjugation. Overwritten here because complex conjugation
467 interchange triplets and antitriplets."""
468
469 return Epsilon(*self)
470
471
472
473
474
475
476
477
478 -class K6(ColorObject):
479 """K6, the symmetry clebsch coefficient, mapping into the symmetric
480 tensor."""
481
483 """Ensure sextet color objects have strictly 3 indices"""
484
485 super(K6, self).__init__()
486 assert len(args) == 3, "sextet color objects must have three indices!"
487
489 """Implement the replacement rules
490 K6(m,i,j)K6Bar(m,k,l) = 1/2(delta3(l,i)delta3(k,j)
491 + delta3(k,i)delta3(l,j))
492 = 1/2(T(l,i)T(k,j) + T(k,i)T(l,j))
493 K6(m,i,j)K6Bar(n,j,i) = delta6(m,n)
494 K6(m,i,j)K6Bar(n,i,j) = delta6(m,n)
495 delta3(i,j)K6(m,i,k) = K6(m,j,k)
496 delta3(i,k)K6(m,j,i) = K6(m,j,k)."""
497
498 if isinstance(col_obj, K6Bar):
499
500 m = self[0]
501 n = col_obj[0]
502
503 ij1 = self[-2:]
504 ij2 = col_obj[-2:]
505
506
507
508 if m == n:
509 col_str1 = ColorString([T(ij2[1], ij1[0]),
510 T(ij2[0], ij1[1])])
511 col_str2 = ColorString([T(ij2[0], ij1[0]),
512 T(ij2[1], ij1[1])])
513 col_str1.coeff = fractions.Fraction(1, 2)
514 col_str2.coeff = fractions.Fraction(1, 2)
515
516 return ColorFactor([col_str1, col_str2])
517
518
519 if ij1[1] == ij2[0] and ij1[0] == ij2[1]:
520 return ColorFactor([ColorString([T6(m, n)])])
521
522
523 if ij1[0] == ij2[0] and ij1[1] == ij2[1]:
524 return ColorFactor([ColorString([T6(m, n)])])
525
526 if isinstance(col_obj, T) and len(col_obj) == 2:
527
528
529 if col_obj[0] in self[-2:]:
530 index1 = self[-2:].index(col_obj[0])
531 return ColorFactor([ColorString([K6(self[0],
532 self[2-index1],
533 col_obj[1])])])
534
536 """Complex conjugation. By default, the ordering of color index is
537 reversed. Can be overwritten for specific color objects like T,..."""
538
539 return K6Bar(*self)
540
541
542 -class K6Bar(ColorObject):
543 """K6Bar, the barred symmetry clebsch coefficient, mapping into the symmetric
544 tensor."""
545
547 """Ensure sextet color objects have strictly 3 indices"""
548
549 super(K6Bar, self).__init__()
550 assert len(args) == 3, "sextet color objects must have three indices!"
551
553 """Implement the replacement rules
554 delta3(i,j)K6Bar(m,j,k) = K6Bar(m,i,k)
555 delta3(k,j)K6Bar(m,i,j) = K6Bar(m,i,k)."""
556
557 if isinstance(col_obj, T) and len(col_obj) == 2:
558
559
560 if col_obj[1] in self[-2:]:
561 index1 = self[-2:].index(col_obj[1])
562 return ColorFactor([ColorString([K6Bar(self[0],
563 self[2-index1],
564 col_obj[0])])])
565
567 """Complex conjugation. By default, the ordering of color index is
568 reversed. Can be overwritten for specific color objects like T,..."""
569
570 return K6(*self)
571
572 -class T6(ColorObject):
573 """The T6 sextet trace color object."""
574
575 new_index = 10000
576
578 """Check for exactly three indices"""
579
580 super(T6, self).__init__()
581 assert len(args) >= 2 and len(args) <= 3, \
582 "T6 objects must have two or three indices!"
583
585 """Implement delta6(i,i) = 1/2 Nc(Nc+1),
586 T6(a,i,j) = 2(K6(i,ii,jj)T(a,jj,kk)K6Bar(j,kk,ii))"""
587
588
589 if len(self) == 2 and self[0] == self[1]:
590 col_str1 = ColorString()
591 col_str1.Nc_power = 2
592 col_str1.coeff = fractions.Fraction(1, 2)
593 col_str2 = ColorString()
594 col_str2.Nc_power = 1
595 col_str2.coeff = fractions.Fraction(1, 2)
596 return ColorFactor([col_str1, col_str2])
597
598 if len(self) == 2:
599 return
600
601
602 ii = T6.new_index
603 jj = ii + 1
604 kk = jj + 1
605 T6.new_index += 3
606
607 col_string = ColorString([K6(self[1], ii, jj),
608 T(self[0], jj, kk),
609 K6Bar(self[2], kk, ii)])
610 col_string.coeff = fractions.Fraction(2, 1)
611 return ColorFactor([col_string])
612
614 """Implement the replacement rules
615 delta6(i,j)delta6(j,k) = delta6(i,k)
616 delta6(m,n)K6(n,i,j) = K6(m,i,j)
617 delta6(m,n)K6Bar(m,i,j) = K6Bar(n,i,j)."""
618
619 if len(self) == 3:
620 return
621
622 if isinstance(col_obj, T6) and len(col_obj) == 2:
623
624 if col_obj[0] == self[1]:
625 return ColorFactor([ColorString([T6(self[0],
626 col_obj[1])])])
627
628 if isinstance(col_obj, K6):
629
630 if col_obj[0] == self[1]:
631 return ColorFactor([ColorString([K6(self[0],
632 col_obj[1],
633 col_obj[2])])])
634
635
636 if isinstance(col_obj, K6Bar):
637
638 if col_obj[0] == self[0]:
639 return ColorFactor([ColorString([K6Bar(self[1],
640 col_obj[1],
641 col_obj[2])])])
642
647 """A list of ColorObjects with an implicit multiplication between,
648 together with a Fraction coefficient and a tag
649 to indicate if the coefficient is real or imaginary. ColorStrings can be
650 simplified, by simplifying their elements."""
651
652 coeff = fractions.Fraction(1, 1)
653 is_imaginary = False
654 Nc_power = 0
655
656
657
658 loop_Nc_power = 0
659 canonical = None
660 immutable = None
661
662 - def __init__(self, init_list=[],
663 coeff=fractions.Fraction(1, 1),
664 is_imaginary=False, Nc_power=0, loop_Nc_power=0):
676
678 """Returns a standard string representation based on color object
679 representations"""
680
681 coeff_str = str(self.coeff)
682 if self.is_imaginary:
683 coeff_str += ' I'
684 if self.Nc_power > 0:
685 coeff_str += ' Nc^%i' % self.Nc_power
686 elif self.Nc_power < 0:
687 coeff_str += ' 1/Nc^%i' % abs(self.Nc_power)
688 return '%s %s' % (coeff_str,
689 ' '.join([str(col_obj) for col_obj in self]))
690
691 __repr__ = __str__
692
712
714 """Simplify the current ColorString by applying simplify rules on
715 each element and building a new ColorFactor to return if necessary"""
716
717
718 for i1, col_obj1 in enumerate(self):
719 res = col_obj1.simplify()
720
721 if res:
722
723 res_col_factor = ColorFactor()
724
725
726 for second_col_str in res:
727 first_col_str = copy.copy(self)
728 del first_col_str[i1]
729 first_col_str.product(second_col_str)
730
731
732 first_col_str.sort()
733 res_col_factor.append(first_col_str)
734
735 return res_col_factor
736
737
738 for i1, col_obj1 in enumerate(self):
739
740 for i2, col_obj2 in enumerate(self[i1 + 1:]):
741 res = col_obj1.pair_simplify(col_obj2)
742
743 if not res:
744 res = col_obj2.pair_simplify(col_obj1)
745 if res:
746 res_col_factor = ColorFactor()
747 for second_col_str in res:
748 first_col_str = copy.copy(self)
749 del first_col_str[i1]
750 del first_col_str[i1 + i2]
751 first_col_str.product(second_col_str)
752 first_col_str.sort()
753 res_col_factor.append(first_col_str)
754 return res_col_factor
755
756 return None
757
758 - def add(self, other):
759 """Add string other to current string. ONLY USE WITH SIMILAR STRINGS!"""
760
761 self.coeff = self.coeff + other.coeff
762
774
776 """Returns an immutable object summarizing the color structure of the
777 current color string. Format is ((name1,indices1),...) where name is the
778 class name of the color object and indices a tuple corresponding to its
779 indices. An immutable object, in Python, is built on tuples, strings and
780 numbers, i.e. objects which cannot be modified. Their crucial property
781 is that they can be used as dictionary keys!"""
782
783 if self.immutable:
784 return self.immutable
785
786 ret_list = [(col_obj.__class__.__name__, tuple(col_obj)) \
787 for col_obj in self]
788
789 if not ret_list and self.coeff:
790 ret_list=[("ColorOne",tuple([]))]
791
792 ret_list.sort()
793 self.immutable = tuple(ret_list)
794
795 return self.immutable
796
798 """Fill the current object with Color Objects created using an immutable
799 representation."""
800
801 del self[:]
802
803 for col_tuple in immutable_rep:
804 self.append(globals()[col_tuple[0]](*col_tuple[1]))
805
807 """Replace current indices following the rules listed in the replacement
808 dictionary written as {old_index:new_index,...}, does that for ALL
809 color objects."""
810
811 map(lambda col_obj: col_obj.replace_indices(repl_dict), self)
812
826
827 __copy__ = create_copy
828
830 """Returns a tuple, with the first entry being the string coefficient
831 with Nc replaced (by default by 3), and the second one being True
832 or False if the coefficient is imaginary or not. Raise an error if there
833 are still non trivial color objects."""
834
835 if self:
836 raise ValueError, \
837 "String %s cannot be simplified to a number!" % str(self)
838
839 if self.Nc_power >= 0:
840 return (self.coeff * fractions.Fraction(\
841 int(Nc ** self.Nc_power), 1),
842 self.is_imaginary)
843 else:
844 return (self.coeff * fractions.Fraction(\
845 1, int(Nc ** abs(self.Nc_power))),
846 self.is_imaginary)
847
849 """Force a specific order for the summation indices
850 in case we have Clebsch Gordan coefficients K6's or K6Bar's
851 This is necessary to correctly recognize later on the equivalent
852 color strings (otherwise the color basis is degenerate).
853 The new ordering is as follow:
854 1. put K and KBar Clebsch Gordan coefficients at the end of the list of color factors
855 the other factors are re-arranged in the reversed order compared with immutable
856 2. rename the summation indices so that they are increasing (starting from 10000)
857 from left to right
858 3. finally, after the summation indices have been renamed, replace
859 K6(a,i,j) by K6(a,j,i) and K6Bar(a,i,j) by K6Bar(a,j,i) IF j>i
860 """
861
862 if not immutable:
863 immutable = self.to_immutable()
864
865
866
867 immutable_order2=[]
868 go_further=0
869 for elem in immutable:
870 if elem[0]=="K6" or elem[0]=="K6Bar" :
871 immutable_order2.append(elem)
872 go_further=1
873 else: immutable_order2.insert(0,elem)
874
875 if go_further==0: return
876
877
878
879 replaced_indices = {}
880 curr_ind = 10000
881 return_list = []
882
883 for elem in immutable_order2:
884 can_elem = [elem[0], []]
885 for index in elem[1]:
886 if index>9999:
887 try:
888 new_index = replaced_indices[index]
889 except KeyError:
890 new_index = curr_ind
891 curr_ind += 1
892 replaced_indices[index] = new_index
893 else: new_index=index
894 can_elem[1].append(new_index)
895
896 if (can_elem[0]=="K6" or can_elem[0]=="K6Bar"):
897 if can_elem[1][2]>can_elem[1][1]: can_elem[1]=[can_elem[1][0], can_elem[1][2], can_elem[1][1] ]
898 return_list.append((can_elem[0], tuple(can_elem[1])))
899 return_list.sort()
900
901 self.from_immutable(return_list)
902 self.immutable=None
903
904 return
905
907 """Returns the canonical representation of the immutable representation
908 (i.e., first index is 1, ...). This allow for an easy comparison of
909 two color strings, i.e. independently of the actual index names (only
910 relative positions matter). Also returns the conversion dictionary.
911 If no immutable representation is given, use the one build from self."""
912
913 if not immutable:
914 immutable = self.to_immutable()
915
916 if self.canonical:
917 return self.canonical
918
919 replaced_indices = {}
920 curr_ind = 1
921 return_list = []
922
923 for elem in immutable:
924 can_elem = [elem[0], []]
925 for index in elem[1]:
926 try:
927 new_index = replaced_indices[index]
928 except KeyError:
929 new_index = curr_ind
930 curr_ind += 1
931 replaced_indices[index] = new_index
932 can_elem[1].append(new_index)
933 return_list.append((can_elem[0], tuple(can_elem[1])))
934
935 return_list.sort()
936
937 self.canonical = (tuple(return_list), replaced_indices)
938 return self.canonical
939
948
950 """Logical opposite of ea"""
951
952 return not self.__eq__(col_str)
953
961
963 """Check if two color strings are equivalent looking only at
964 the color objects (used in color flow string calculation)"""
965
966 if len(self.to_canonical()) != len(col_str.to_canonical()):
967 return False
968
969 return all([co1[0] == co2[0] and sorted(co1[1]) == sorted(co2[1]) \
970 for (co1,co2) in zip(self.to_canonical()[0],
971 col_str.to_canonical()[0])])
972
977 """ColorFactor objects are list of ColorString with an implicit summation.
978 They can be simplified by simplifying all their elements."""
979
981 """Returns a nice string for printing"""
982
983 return '+'.join(['(%s)' % str(col_str) for col_str in self])
984
986 """Special append taking care of adding new string to strings already
987 existing with the same structure."""
988
989 for col_str in self:
990
991
992
993 if col_str.is_similar(new_str):
994
995 col_str.add(new_str)
996 return True
997
998
999 self.append(new_str)
1000 return False
1001
1003 """Special extend taking care of adding new strings to strings already
1004 existing with the same structure."""
1005
1006
1007 self.canonical = None
1008 self.immutable = None
1009
1010 for col_str in new_col_fact:
1011 self.append_str(col_str)
1012
1014 """Returns a new color factor where each color string has been
1015 simplified once and similar strings have been added."""
1016
1017 new_col_factor = ColorFactor()
1018
1019 for col_str in self:
1020 res = col_str.simplify()
1021 if res:
1022 new_col_factor.extend_str(res)
1023 else:
1024 new_col_factor.append_str(col_str)
1025
1026
1027 return ColorFactor([col_str for col_str in \
1028 new_col_factor if col_str.coeff != 0])
1029
1031 """Simplify the current color factor until the result is stable"""
1032
1033 result = copy.copy(self)
1034 while(True):
1035 ref = copy.copy(result)
1036 result = result.simplify()
1037 if result == ref:
1038 return result
1039
1041 """Returns a tuple containing real and imaginary parts of the current
1042 color factor, when Nc is replaced (3 by default)."""
1043
1044 return (sum([cs.set_Nc(Nc)[0] for cs in self if not cs.is_imaginary]),
1045 sum([cs.set_Nc(Nc)[0] for cs in self if cs.is_imaginary]))
1046
1047
1049 """Replace current indices following the rules listed in the replacement
1050 dictionary written as {old_index:new_index,...}, does that for ALL
1051 color strings."""
1052
1053 map(lambda col_str:col_str.replace_indices(repl_dict), self)
1054
1056 """Returns a real copy of self, non trivial because bug in
1057 copy.deepcopy"""
1058
1059 res = ColorFactor()
1060 for col_str in self:
1061 res.append(col_str.create_copy())
1062
1063 return res
1064
1065 __copy__ = create_copy
1066