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