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 canonical = None
611 immutable = None
612
613 - def __init__(self, init_list=[],
614 coeff=fractions.Fraction(1, 1),
615 is_imaginary=False, Nc_power=0):
616 """Overrides norm list constructor to implement easy modification
617 of coeff, is_imaginary and Nc_power"""
618
619 if init_list:
620 for obj in init_list:
621 assert type(obj) != array.array
622 self.extend(init_list)
623 self.coeff = coeff
624 self.is_imaginary = is_imaginary
625 self.Nc_power = Nc_power
626
628 """Returns a standard string representation based on color object
629 representations"""
630
631 coeff_str = str(self.coeff)
632 if self.is_imaginary:
633 coeff_str += ' I'
634 if self.Nc_power > 0:
635 coeff_str += ' Nc^%i' % self.Nc_power
636 elif self.Nc_power < 0:
637 coeff_str += ' 1/Nc^%i' % abs(self.Nc_power)
638 return '%s %s' % (coeff_str,
639 ' '.join([str(col_obj) for col_obj in self]))
640
641 __repr__ = __str__
642
662
664 """Simplify the current ColorString by applying simplify rules on
665 each element and building a new ColorFactor to return if necessary"""
666
667
668 for i1, col_obj1 in enumerate(self):
669 res = col_obj1.simplify()
670
671 if res:
672
673 res_col_factor = ColorFactor()
674
675
676 for second_col_str in res:
677 first_col_str = copy.copy(self)
678 del first_col_str[i1]
679 first_col_str.product(second_col_str)
680
681
682 first_col_str.sort()
683 res_col_factor.append(first_col_str)
684
685 return res_col_factor
686
687
688 for i1, col_obj1 in enumerate(self):
689
690 for i2, col_obj2 in enumerate(self[i1 + 1:]):
691 res = col_obj1.pair_simplify(col_obj2)
692
693 if not res:
694 res = col_obj2.pair_simplify(col_obj1)
695 if res:
696 res_col_factor = ColorFactor()
697 for second_col_str in res:
698 first_col_str = copy.copy(self)
699 del first_col_str[i1]
700 del first_col_str[i1 + i2]
701 first_col_str.product(second_col_str)
702 first_col_str.sort()
703 res_col_factor.append(first_col_str)
704 return res_col_factor
705
706 return None
707
708 - def add(self, other):
709 """Add string other to current string. ONLY USE WITH SIMILAR STRINGS!"""
710
711 self.coeff = self.coeff + other.coeff
712
724
726 """Returns an immutable object summarizing the color structure of the
727 current color string. Format is ((name1,indices1),...) where name is the
728 class name of the color object and indices a tuple corresponding to its
729 indices. An immutable object, in Python, is built on tuples, strings and
730 numbers, i.e. objects which cannot be modified. Their crucial property
731 is that they can be used as dictionary keys!"""
732
733 if self.immutable:
734 return self.immutable
735
736 ret_list = [(col_obj.__class__.__name__, tuple(col_obj)) \
737 for col_obj in self]
738
739 if not ret_list and self.coeff:
740 ret_list=[("ColorOne",tuple([]))]
741
742 ret_list.sort()
743 self.immutable = tuple(ret_list)
744
745 return self.immutable
746
748 """Fill the current object with Color Objects created using an immutable
749 representation."""
750
751 del self[:]
752
753 for col_tuple in immutable_rep:
754 self.append(globals()[col_tuple[0]](*col_tuple[1]))
755
757 """Replace current indices following the rules listed in the replacement
758 dictionary written as {old_index:new_index,...}, does that for ALL
759 color objects."""
760
761 map(lambda col_obj: col_obj.replace_indices(repl_dict), self)
762
776
777 __copy__ = create_copy
778
780 """Returns a tuple, with the first entry being the string coefficient
781 with Nc replaced (by default by 3), and the second one being True
782 or False if the coefficient is imaginary or not. Raise an error if there
783 are still non trivial color objects."""
784
785 if self:
786 raise ValueError, \
787 "String %s cannot be simplified to a number!" % str(self)
788
789 if self.Nc_power >= 0:
790 return (self.coeff * fractions.Fraction(\
791 int(Nc ** self.Nc_power), 1),
792 self.is_imaginary)
793 else:
794 return (self.coeff * fractions.Fraction(\
795 1, int(Nc ** abs(self.Nc_power))),
796 self.is_imaginary)
797
799 """Force a specific order for the summation indices
800 in case we have Clebsch Gordan coefficients K6's or K6Bar's
801 This is necessary to correctly recognize later on the equivalent
802 color strings (otherwise the color basis is degenerate)
803 The new ordering is as follow:
804 1. put K and KBar Clebsch Gordan coefficients at the end of the list of color factors
805 the other factors are re-arranged in the reversed order compared with immutable
806 2. rename the summation indices so that they are increasing (starting from 10000)
807 from left to right
808 3. finally, after the summation indices have been renamed, replace
809 K6(a,i,j) by K6(a,j,i) and K6Bar(a,i,j) by K6Bar(a,j,i) IF j>i
810 """
811
812 if not immutable:
813 immutable = self.to_immutable()
814
815
816
817 immutable_order2=[]
818 go_further=0
819 for elem in immutable:
820 if elem[0]=="K6" or elem[0]=="K6Bar" :
821 immutable_order2.append(elem)
822 go_further=1
823 else: immutable_order2.insert(0,elem)
824
825 if go_further==0: return
826
827
828
829 replaced_indices = {}
830 curr_ind = 10000
831 return_list = []
832
833 for elem in immutable_order2:
834 can_elem = [elem[0], []]
835 for index in elem[1]:
836 if index>9999:
837 try:
838 new_index = replaced_indices[index]
839 except KeyError:
840 new_index = curr_ind
841 curr_ind += 1
842 replaced_indices[index] = new_index
843 else: new_index=index
844 can_elem[1].append(new_index)
845
846 if (can_elem[0]=="K6" or can_elem[0]=="K6Bar"):
847 if can_elem[1][2]>can_elem[1][1]: can_elem[1]=[can_elem[1][0], can_elem[1][2], can_elem[1][1] ]
848 return_list.append((can_elem[0], tuple(can_elem[1])))
849 return_list.sort()
850
851 self.from_immutable(return_list)
852 self.immutable=None
853
854 return
855
857 """Returns the canonical representation of the immutable representation
858 (i.e., first index is 1, ...). This allow for an easy comparison of
859 two color strings, i.e. independently of the actual index names (only
860 relative positions matter). Also returns the conversion dictionary.
861 If no immutable representation is given, use the one build from self."""
862
863 if not immutable:
864 immutable = self.to_immutable()
865
866 if self.canonical:
867 return self.canonical
868
869 replaced_indices = {}
870 curr_ind = 1
871 return_list = []
872
873 for elem in immutable:
874 can_elem = [elem[0], []]
875 for index in elem[1]:
876 try:
877 new_index = replaced_indices[index]
878 except KeyError:
879 new_index = curr_ind
880 curr_ind += 1
881 replaced_indices[index] = new_index
882 can_elem[1].append(new_index)
883 return_list.append((can_elem[0], tuple(can_elem[1])))
884
885 return_list.sort()
886
887 self.canonical = (tuple(return_list), replaced_indices)
888 return self.canonical
889
898
900 """Logical opposite of ea"""
901
902 return not self.__eq__(col_str)
903
911
913 """Check if two color strings are equivalent looking only at
914 the color objects (used in color flow string calculation)"""
915
916 if len(self.to_canonical()) != len(col_str.to_canonical()):
917 return False
918
919 return all([co1[0] == co2[0] and sorted(co1[1]) == sorted(co2[1]) \
920 for (co1,co2) in zip(self.to_canonical()[0],
921 col_str.to_canonical()[0])])
922
923
924
925
927 """ColorFactor objects are list of ColorString with an implicit summation.
928 They can be simplified by simplifying all their elements."""
929
931 """Returns a nice string for printing"""
932
933 return '+'.join(['(%s)' % str(col_str) for col_str in self])
934
936 """Special append taking care of adding new string to strings already
937 existing with the same structure."""
938
939 for col_str in self:
940
941
942
943 if col_str.is_similar(new_str):
944
945 col_str.add(new_str)
946 return True
947
948
949 self.append(new_str)
950 return False
951
953 """Special extend taking care of adding new strings to strings already
954 existing with the same structure."""
955
956
957 self.canonical = None
958 self.immutable = None
959
960 for col_str in new_col_fact:
961 self.append_str(col_str)
962
964 """Returns a new color factor where each color string has been
965 simplified once and similar strings have been added."""
966
967 new_col_factor = ColorFactor()
968
969 for col_str in self:
970 res = col_str.simplify()
971 if res:
972 new_col_factor.extend_str(res)
973 else:
974 new_col_factor.append_str(col_str)
975
976
977 return ColorFactor([col_str for col_str in \
978 new_col_factor if col_str.coeff != 0])
979
981 """Simplify the current color factor until the result is stable"""
982
983 result = copy.copy(self)
984 while(True):
985 ref = copy.copy(result)
986 result = result.simplify()
987 if result == ref:
988 return result
989
991 """Returns a tuple containing real and imaginary parts of the current
992 color factor, when Nc is replaced (3 by default)."""
993
994 return (sum([cs.set_Nc(Nc)[0] for cs in self if not cs.is_imaginary]),
995 sum([cs.set_Nc(Nc)[0] for cs in self if cs.is_imaginary]))
996
997
999 """Replace current indices following the rules listed in the replacement
1000 dictionary written as {old_index:new_index,...}, does that for ALL
1001 color strings."""
1002
1003 map(lambda col_str:col_str.replace_indices(repl_dict), self)
1004
1006 """Returns a real copy of self, non trivial because bug in
1007 copy.deepcopy"""
1008
1009 res = ColorFactor()
1010 for col_str in self:
1011 res.append(col_str.create_copy())
1012
1013 return res
1014
1015 __copy__ = create_copy
1016