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