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 if len(args) ==2 and args[0] == 'i' and not args[1]:
185
186 return super(ColorOne, self).__init__()
187
188 assert len(args) == 0 , "ColorOne objects must have no index!"
189
190 super(ColorOne, self).__init__()
191
193 """"""
194 assert len(self)==0, "There is argument(s) in color object ColorOne."
195 col_str = ColorString()
196 col_str.coeff = fractions.Fraction(1, 1)
197 return ColorFactor([col_str])
198
199
201 """Implement ColorOne product simplification"""
202
203 if any(isinstance(col_obj, c_type) for c_type in [Tr,T,f,d,ColorOne]):
204 col_str = ColorString([col_obj])
205 return ColorFactor([col_str])
206 return None
207
208
209
210
211
212 -class T(ColorObject):
213 """The T color object. Last two indices have a special meaning"""
214
216 """Check for at least two indices"""
217
218 assert len(args) > 1 , "T objects must have at least two indices!"
219
220 super(T, self).__init__()
221
223 """Implement T(a,b,c,...,i,i) = Tr(a,b,c,...) and
224 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))"""
225
226
227 if self[-2] == self[-1]:
228 return ColorFactor([ColorString([Tr(*self[:-2])])])
229
230
231 for i1, index1 in enumerate(self[:-2]):
232 for i2, index2 in enumerate(self[i1 + 1:-2]):
233 if index1 == index2:
234 a = self[:i1]
235 b = self[i1 + 1:i1 + i2 + 1]
236 c = self[i1 + i2 + 2:-2]
237 ij = self[-2:]
238 col_str1 = ColorString([T(*(a + c + ij)), Tr(*b)])
239 col_str2 = ColorString([T(*(a + b + c + ij))])
240 col_str1.coeff = fractions.Fraction(1, 2)
241 col_str2.coeff = fractions.Fraction(-1, 2)
242 col_str2.Nc_power = -1
243 return ColorFactor([col_str1, col_str2])
244
245 return None
246
248 """Implement T(a,...,i,j)T(b,...,j,k) = T(a,...,b,...,i,k)
249 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)
250 -1/Nc T(a,b,i,j)T(c,d,k,l))."""
251
252 if isinstance(col_obj, T):
253 ij1 = self[-2:]
254 ij2 = col_obj[-2:]
255
256
257 if ij1[1] == ij2[0]:
258 return ColorFactor([ColorString([T(*(self[:-2] + \
259 col_obj[:-2] + \
260 array.array('i', [ij1[0],
261 ij2[1]])))])])
262
263
264
265 for i1, index1 in enumerate(self[:-2]):
266 for i2, index2 in enumerate(col_obj[:-2]):
267 if index1 == index2:
268 a = self[:i1]
269 b = self[i1 + 1:-2]
270 c = col_obj[:i2]
271 d = col_obj[i2 + 1:-2]
272 col_str1 = ColorString([T(*(a + d + \
273 array.array('i',
274 [ij1[0], ij2[1]]))),
275 T(*(c + b + \
276 array.array('i',
277 [ij2[0], ij1[1]])))])
278 col_str2 = ColorString([T(*(a + b + \
279 array.array('i',
280 [ij1[0], ij1[1]]))),
281 T(*(c + d + \
282 array.array('i',
283 [ij2[0], ij2[1]])))])
284 col_str1.coeff = fractions.Fraction(1, 2)
285 col_str2.coeff = fractions.Fraction(-1, 2)
286 col_str2.Nc_power = -1
287 return ColorFactor([col_str1, col_str2])
288
290 """Complex conjugation. Overwritten here because the two last indices
291 should be treated differently"""
292
293
294 l1 = self[:-2]
295 l1.reverse()
296 l2 = self[-2:]
297 l2.reverse()
298 self[:] = l1 + l2
299 return self
300
301
302
303
304 -class f(ColorObject):
305 """The f color object"""
306
308 """Ensure f and d objects have strictly 3 indices"""
309
310
311 if len(args) !=3 and args[0] == 'i':
312 args = args[1]
313 assert len(args) == 3, "f and d objects must have three indices!"
314
315 super(f, self).__init__()
316
317
319 """Implement only the replacement rule
320 f(a,b,c)=-2ITr(a,b,c)+2ITr(c,b,a)"""
321
322 indices = self[:]
323 col_str1 = ColorString([Tr(*indices)])
324 indices.reverse()
325 col_str2 = ColorString([Tr(*indices)])
326
327 col_str1.coeff = fractions.Fraction(-2, 1)
328 col_str2.coeff = fractions.Fraction(2, 1)
329
330 col_str1.is_imaginary = True
331 col_str2.is_imaginary = True
332
333 return ColorFactor([col_str1, col_str2])
334
335
336
337
338 -class d(f):
339 """The d color object"""
340
342 """Implement only the replacement rule
343 d(a,b,c)=2Tr(a,b,c)+2Tr(c,b,a)"""
344
345 indices = self[:]
346 col_str1 = ColorString([Tr(*indices)])
347 indices.reverse()
348 col_str2 = ColorString([Tr(*indices)])
349
350 col_str1.coeff = fractions.Fraction(2, 1)
351 col_str2.coeff = fractions.Fraction(2, 1)
352
353 return ColorFactor([col_str1, col_str2])
354
355
356
357
358
359 -class Epsilon(ColorObject):
360 """Epsilon_ijk color object for three triplets"""
361
363 """Ensure e_ijk objects have strictly 3 indices"""
364
365 super(Epsilon, self).__init__()
366 assert len(args) == 3, "Epsilon objects must have three indices!"
367
368 @staticmethod
370 '''\
371 Given a permutation of the digits 0..N in order as a list,
372 returns its parity (or sign): +1 for even parity; -1 for odd.
373 '''
374 lst = lst[:]
375 sort =lst[:]
376 if not order:
377 order = lst[:]
378 order.sort()
379 parity = 1
380 for i in range(0,len(lst)-1):
381 if lst[i] != order[i]:
382 parity *= -1
383 mn = lst.index(order[i])
384 lst[i],lst[mn] = lst[mn],lst[i]
385 return parity
386
388 """Implement epsilon(i,k,j) = -epsilon(i,j,k) i<j<k"""
389
390
391
392
393 order_list = list(self[:])
394 order_list.sort()
395
396 if list(self[:]) != order_list:
397 col_str1 = ColorString([Epsilon(*order_list)])
398 col_str1.coeff = self.perm_parity(self[:], order_list)
399 return ColorFactor([col_str1])
400
402 """Implement e_ijk ae_ilm = T(j,l)T(k,m) - T(j,m)T(k,l) and
403 e_ijk T(l,k) = e_ikl"""
404
405
406 if isinstance(col_obj, EpsilonBar):
407
408 incommon = False
409 eps_indices = self[:]
410 aeps_indices = col_obj[:]
411 for i in self:
412 if i in col_obj:
413 incommon = True
414 com_index_eps = self.index(i)
415 com_index_aeps = col_obj.index(i)
416
417 if incommon:
418 eps_indices = self[com_index_eps:] + self[:com_index_eps]
419 aeps_indices = col_obj[com_index_aeps:] + col_obj[:com_index_aeps]
420 col_str1 = ColorString([T(eps_indices[1], aeps_indices[1]),
421 T(eps_indices[2], aeps_indices[2])])
422 col_str2 = ColorString([T(eps_indices[1], aeps_indices[2]),
423 T(eps_indices[2], aeps_indices[1])])
424
425 col_str2.coeff = fractions.Fraction(-1, 1)
426
427 return ColorFactor([col_str1, col_str2])
428
429
430 if isinstance(col_obj, T) and len(col_obj) == 2 and col_obj[1] in self:
431
432 com_index = self.index(col_obj[1])
433 new_self = copy.copy(self)
434 new_self[com_index] = col_obj[0]
435
436 return ColorFactor([ColorString([new_self])])
437
438
440 """Complex conjugation. Overwritten here because complex conjugation
441 interchange triplets and antitriplets."""
442
443 return EpsilonBar(*self)
444
447 """Epsilon_ijk color object for three antitriplets"""
448
450 """Ensure e_ijk objects have strictly 3 indices"""
451
452 super(EpsilonBar, self).__init__()
453 assert len(args) == 3, "EpsilonBar objects must have three indices!"
454
456 """Implement ebar_ijk T(k,l) = e_ikl"""
457
458
459 if isinstance(col_obj, T) and len(col_obj) == 2 and col_obj[0] in self:
460
461 com_index = self.index(col_obj[0])
462 new_self = copy.copy(self)
463 new_self[com_index] = col_obj[1]
464
465 return ColorFactor([ColorString([new_self])])
466
468 """Implement epsilon(i,k,j) = -epsilon(i,j,k) i<j<k"""
469
470
471 order_list = list(self[:])
472 order_list.sort()
473
474 if list(self[:]) != order_list:
475 col_str1 = ColorString([EpsilonBar(*order_list)])
476 col_str1.coeff = Epsilon.perm_parity(self[:], order_list)
477 return ColorFactor([col_str1])
478
480 """Complex conjugation. Overwritten here because complex conjugation
481 interchange triplets and antitriplets."""
482
483 return Epsilon(*self)
484
485
486
487
488
489
490
491
492 -class K6(ColorObject):
493 """K6, the symmetry clebsch coefficient, mapping into the symmetric
494 tensor."""
495
497 """Ensure sextet color objects have strictly 3 indices"""
498
499 super(K6, self).__init__()
500 assert len(args) == 3, "sextet color objects must have three indices!"
501
503 """Implement the replacement rules
504 K6(m,i,j)K6Bar(m,k,l) = 1/2(delta3(l,i)delta3(k,j)
505 + delta3(k,i)delta3(l,j))
506 = 1/2(T(l,i)T(k,j) + T(k,i)T(l,j))
507 K6(m,i,j)K6Bar(n,j,i) = delta6(m,n)
508 K6(m,i,j)K6Bar(n,i,j) = delta6(m,n)
509 delta3(i,j)K6(m,i,k) = K6(m,j,k)
510 delta3(i,k)K6(m,j,i) = K6(m,j,k)."""
511
512 if isinstance(col_obj, K6Bar):
513
514 m = self[0]
515 n = col_obj[0]
516
517 ij1 = self[-2:]
518 ij2 = col_obj[-2:]
519
520
521
522 if m == n:
523 col_str1 = ColorString([T(ij2[1], ij1[0]),
524 T(ij2[0], ij1[1])])
525 col_str2 = ColorString([T(ij2[0], ij1[0]),
526 T(ij2[1], ij1[1])])
527 col_str1.coeff = fractions.Fraction(1, 2)
528 col_str2.coeff = fractions.Fraction(1, 2)
529
530 return ColorFactor([col_str1, col_str2])
531
532
533 if ij1[1] == ij2[0] and ij1[0] == ij2[1]:
534 return ColorFactor([ColorString([T6(m, n)])])
535
536
537 if ij1[0] == ij2[0] and ij1[1] == ij2[1]:
538 return ColorFactor([ColorString([T6(m, n)])])
539
540 if isinstance(col_obj, T) and len(col_obj) == 2:
541
542
543 if col_obj[0] in self[-2:]:
544 index1 = self[-2:].index(col_obj[0])
545 return ColorFactor([ColorString([K6(self[0],
546 self[2-index1],
547 col_obj[1])])])
548
550 """Complex conjugation. By default, the ordering of color index is
551 reversed. Can be overwritten for specific color objects like T,..."""
552
553 return K6Bar(*self)
554
555
556 -class K6Bar(ColorObject):
557 """K6Bar, the barred symmetry clebsch coefficient, mapping into the symmetric
558 tensor."""
559
561 """Ensure sextet color objects have strictly 3 indices"""
562
563 super(K6Bar, self).__init__()
564 assert len(args) == 3, "sextet color objects must have three indices!"
565
567 """Implement the replacement rules
568 delta3(i,j)K6Bar(m,j,k) = K6Bar(m,i,k)
569 delta3(k,j)K6Bar(m,i,j) = K6Bar(m,i,k)."""
570
571 if isinstance(col_obj, T) and len(col_obj) == 2:
572
573
574 if col_obj[1] in self[-2:]:
575 index1 = self[-2:].index(col_obj[1])
576 return ColorFactor([ColorString([K6Bar(self[0],
577 self[2-index1],
578 col_obj[0])])])
579
581 """Complex conjugation. By default, the ordering of color index is
582 reversed. Can be overwritten for specific color objects like T,..."""
583
584 return K6(*self)
585
586 -class T6(ColorObject):
587 """The T6 sextet trace color object."""
588
589 new_index = 10000
590
592 """Check for exactly three indices"""
593
594 super(T6, self).__init__()
595 assert len(args) >= 2 and len(args) <= 3, \
596 "T6 objects must have two or three indices!"
597
599 """Implement delta6(i,i) = 1/2 Nc(Nc+1),
600 T6(a,i,j) = 2(K6(i,ii,jj)T(a,jj,kk)K6Bar(j,kk,ii))"""
601
602
603 if len(self) == 2 and self[0] == self[1]:
604 col_str1 = ColorString()
605 col_str1.Nc_power = 2
606 col_str1.coeff = fractions.Fraction(1, 2)
607 col_str2 = ColorString()
608 col_str2.Nc_power = 1
609 col_str2.coeff = fractions.Fraction(1, 2)
610 return ColorFactor([col_str1, col_str2])
611
612 if len(self) == 2:
613 return
614
615
616 ii = T6.new_index
617 jj = ii + 1
618 kk = jj + 1
619 T6.new_index += 3
620
621 col_string = ColorString([K6(self[1], ii, jj),
622 T(self[0], jj, kk),
623 K6Bar(self[2], kk, ii)])
624 col_string.coeff = fractions.Fraction(2, 1)
625 return ColorFactor([col_string])
626
628 """Implement the replacement rules
629 delta6(i,j)delta6(j,k) = delta6(i,k)
630 delta6(m,n)K6(n,i,j) = K6(m,i,j)
631 delta6(m,n)K6Bar(m,i,j) = K6Bar(n,i,j)."""
632
633 if len(self) == 3:
634 return
635
636 if isinstance(col_obj, T6) and len(col_obj) == 2:
637
638 if col_obj[0] == self[1]:
639 return ColorFactor([ColorString([T6(self[0],
640 col_obj[1])])])
641
642 if isinstance(col_obj, K6):
643
644 if col_obj[0] == self[1]:
645 return ColorFactor([ColorString([K6(self[0],
646 col_obj[1],
647 col_obj[2])])])
648
649
650 if isinstance(col_obj, K6Bar):
651
652 if col_obj[0] == self[0]:
653 return ColorFactor([ColorString([K6Bar(self[1],
654 col_obj[1],
655 col_obj[2])])])
656
661 """A list of ColorObjects with an implicit multiplication between,
662 together with a Fraction coefficient and a tag
663 to indicate if the coefficient is real or imaginary. ColorStrings can be
664 simplified, by simplifying their elements."""
665
666 coeff = fractions.Fraction(1, 1)
667 is_imaginary = False
668 Nc_power = 0
669
670
671
672 loop_Nc_power = 0
673 canonical = None
674 immutable = None
675
676 - def __init__(self, init_list=[],
677 coeff=fractions.Fraction(1, 1),
678 is_imaginary=False, Nc_power=0, loop_Nc_power=0):
690
692 """Returns a standard string representation based on color object
693 representations"""
694
695 coeff_str = str(self.coeff)
696 if self.is_imaginary:
697 coeff_str += ' I'
698 if self.Nc_power > 0:
699 coeff_str += ' Nc^%i' % self.Nc_power
700 elif self.Nc_power < 0:
701 coeff_str += ' 1/Nc^%i' % abs(self.Nc_power)
702 return '%s %s' % (coeff_str,
703 ' '.join([str(col_obj) for col_obj in self]))
704
705 __repr__ = __str__
706
726
728 """Simplify the current ColorString by applying simplify rules on
729 each element and building a new ColorFactor to return if necessary"""
730
731
732 for i1, col_obj1 in enumerate(self):
733 res = col_obj1.simplify()
734
735 if res:
736
737 res_col_factor = ColorFactor()
738
739
740 for second_col_str in res:
741 first_col_str = copy.copy(self)
742 del first_col_str[i1]
743 first_col_str.product(second_col_str)
744
745
746 first_col_str.sort()
747 res_col_factor.append(first_col_str)
748
749 return res_col_factor
750
751
752 for i1, col_obj1 in enumerate(self):
753
754 for i2, col_obj2 in enumerate(self[i1 + 1:]):
755 res = col_obj1.pair_simplify(col_obj2)
756
757 if not res:
758 res = col_obj2.pair_simplify(col_obj1)
759 if res:
760 res_col_factor = ColorFactor()
761 for second_col_str in res:
762 first_col_str = copy.copy(self)
763 del first_col_str[i1]
764 del first_col_str[i1 + i2]
765 first_col_str.product(second_col_str)
766 first_col_str.sort()
767 res_col_factor.append(first_col_str)
768 return res_col_factor
769
770 return None
771
772 - def add(self, other):
773 """Add string other to current string. ONLY USE WITH SIMILAR STRINGS!"""
774
775 self.coeff = self.coeff + other.coeff
776
788
790 """Returns an immutable object summarizing the color structure of the
791 current color string. Format is ((name1,indices1),...) where name is the
792 class name of the color object and indices a tuple corresponding to its
793 indices. An immutable object, in Python, is built on tuples, strings and
794 numbers, i.e. objects which cannot be modified. Their crucial property
795 is that they can be used as dictionary keys!"""
796
797 if self.immutable:
798 return self.immutable
799
800 ret_list = [(col_obj.__class__.__name__, tuple(col_obj)) \
801 for col_obj in self]
802
803 if not ret_list and self.coeff:
804 ret_list=[("ColorOne",tuple([]))]
805
806 ret_list.sort()
807 self.immutable = tuple(ret_list)
808
809 return self.immutable
810
812 """Fill the current object with Color Objects created using an immutable
813 representation."""
814
815 del self[:]
816
817 for col_tuple in immutable_rep:
818 self.append(globals()[col_tuple[0]](*col_tuple[1]))
819
821 """Replace current indices following the rules listed in the replacement
822 dictionary written as {old_index:new_index,...}, does that for ALL
823 color objects."""
824
825 list(map(lambda col_obj: col_obj.replace_indices(repl_dict), self))
826
840
841 __copy__ = create_copy
842
844 """Returns a tuple, with the first entry being the string coefficient
845 with Nc replaced (by default by 3), and the second one being True
846 or False if the coefficient is imaginary or not. Raise an error if there
847 are still non trivial color objects."""
848
849 if self:
850 raise ValueError("String %s cannot be simplified to a number!" % str(self))
851
852 if self.Nc_power >= 0:
853 return (self.coeff * fractions.Fraction(\
854 int(Nc ** self.Nc_power), 1),
855 self.is_imaginary)
856 else:
857 return (self.coeff * fractions.Fraction(\
858 1, int(Nc ** abs(self.Nc_power))),
859 self.is_imaginary)
860
862 """Force a specific order for the summation indices
863 in case we have Clebsch Gordan coefficients K6's or K6Bar's
864 This is necessary to correctly recognize later on the equivalent
865 color strings (otherwise the color basis is degenerate).
866 The new ordering is as follow:
867 1. put K and KBar Clebsch Gordan coefficients at the end of the list of color factors
868 the other factors are re-arranged in the reversed order compared with immutable
869 2. rename the summation indices so that they are increasing (starting from 10000)
870 from left to right
871 3. finally, after the summation indices have been renamed, replace
872 K6(a,i,j) by K6(a,j,i) and K6Bar(a,i,j) by K6Bar(a,j,i) IF j>i
873 """
874
875 if not immutable:
876 immutable = self.to_immutable()
877
878
879
880 immutable_order2=[]
881 go_further=0
882 for elem in immutable:
883 if elem[0]=="K6" or elem[0]=="K6Bar" :
884 immutable_order2.append(elem)
885 go_further=1
886 else: immutable_order2.insert(0,elem)
887
888 if go_further==0: return
889
890
891
892 replaced_indices = {}
893 curr_ind = 10000
894 return_list = []
895
896 for elem in immutable_order2:
897 can_elem = [elem[0], []]
898 for index in elem[1]:
899 if index>9999:
900 try:
901 new_index = replaced_indices[index]
902 except KeyError:
903 new_index = curr_ind
904 curr_ind += 1
905 replaced_indices[index] = new_index
906 else: new_index=index
907 can_elem[1].append(new_index)
908
909 if (can_elem[0]=="K6" or can_elem[0]=="K6Bar"):
910 if can_elem[1][2]>can_elem[1][1]: can_elem[1]=[can_elem[1][0], can_elem[1][2], can_elem[1][1] ]
911 return_list.append((can_elem[0], tuple(can_elem[1])))
912 return_list.sort()
913
914 self.from_immutable(return_list)
915 self.immutable=None
916
917 return
918
920 """Returns the canonical representation of the immutable representation
921 (i.e., first index is 1, ...). This allow for an easy comparison of
922 two color strings, i.e. independently of the actual index names (only
923 relative positions matter). Also returns the conversion dictionary.
924 If no immutable representation is given, use the one build from self."""
925
926 if not immutable:
927 immutable = self.to_immutable()
928
929 if self.canonical:
930 return self.canonical
931
932 replaced_indices = {}
933 curr_ind = 1
934 return_list = []
935
936 for elem in immutable:
937 can_elem = [elem[0], []]
938 for index in elem[1]:
939 try:
940 new_index = replaced_indices[index]
941 except KeyError:
942 new_index = curr_ind
943 curr_ind += 1
944 replaced_indices[index] = new_index
945 can_elem[1].append(new_index)
946 return_list.append((can_elem[0], tuple(can_elem[1])))
947
948 return_list.sort()
949
950 self.canonical = (tuple(return_list), replaced_indices)
951 return self.canonical
952
961
963 """Logical opposite of ea"""
964
965 return not self.__eq__(col_str)
966
974
976 """Check if two color strings are equivalent looking only at
977 the color objects (used in color flow string calculation)"""
978
979 if len(self.to_canonical()) != len(col_str.to_canonical()):
980 return False
981
982 return all([co1[0] == co2[0] and sorted(co1[1]) == sorted(co2[1]) \
983 for (co1,co2) in zip(self.to_canonical()[0],
984 col_str.to_canonical()[0])])
985
990 """ColorFactor objects are list of ColorString with an implicit summation.
991 They can be simplified by simplifying all their elements."""
992
994 """Returns a nice string for printing"""
995
996 return '+'.join(['(%s)' % str(col_str) for col_str in self])
997
999 """Special append taking care of adding new string to strings already
1000 existing with the same structure."""
1001
1002 for col_str in self:
1003
1004
1005
1006 if col_str.is_similar(new_str):
1007
1008 col_str.add(new_str)
1009 return True
1010
1011
1012 self.append(new_str)
1013 return False
1014
1016 """Special extend taking care of adding new strings to strings already
1017 existing with the same structure."""
1018
1019
1020 self.canonical = None
1021 self.immutable = None
1022
1023 for col_str in new_col_fact:
1024 self.append_str(col_str)
1025
1027 """Returns a new color factor where each color string has been
1028 simplified once and similar strings have been added."""
1029
1030 new_col_factor = ColorFactor()
1031
1032 for col_str in self:
1033 res = col_str.simplify()
1034 if res:
1035 new_col_factor.extend_str(res)
1036 else:
1037 new_col_factor.append_str(col_str)
1038
1039
1040 return ColorFactor([col_str for col_str in \
1041 new_col_factor if col_str.coeff != 0])
1042
1044 """Simplify the current color factor until the result is stable"""
1045
1046 result = copy.copy(self)
1047 while(True):
1048 ref = copy.copy(result)
1049 result = result.simplify()
1050 if result == ref:
1051 return result
1052
1054 """Returns a tuple containing real and imaginary parts of the current
1055 color factor, when Nc is replaced (3 by default)."""
1056
1057 return (sum([cs.set_Nc(Nc)[0] for cs in self if not cs.is_imaginary]),
1058 sum([cs.set_Nc(Nc)[0] for cs in self if cs.is_imaginary]))
1059
1060
1062 """Replace current indices following the rules listed in the replacement
1063 dictionary written as {old_index:new_index,...}, does that for ALL
1064 color strings."""
1065
1066 list(map(lambda col_str:col_str.replace_indices(repl_dict), self))
1067
1069 """Returns a real copy of self, non trivial because bug in
1070 copy.deepcopy"""
1071
1072 res = ColorFactor()
1073 for col_str in self:
1074 res.append(col_str.create_copy())
1075
1076 return res
1077
1078 __copy__ = create_copy
1079