d346c44ad3fd4548226c7f147908dd5fa3b11016
[ginac.git] / ginac / clifford.cpp
1 /** @file clifford.cpp
2  *
3  *  Implementation of GiNaC's clifford algebra (Dirac gamma) objects. */
4
5 /*
6  *  GiNaC Copyright (C) 1999-2001 Johannes Gutenberg University Mainz, Germany
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #include "clifford.h"
24 #include "ex.h"
25 #include "idx.h"
26 #include "ncmul.h"
27 #include "print.h"
28 #include "archive.h"
29 #include "debugmsg.h"
30 #include "utils.h"
31
32 #include <stdexcept>
33
34 namespace GiNaC {
35
36 GINAC_IMPLEMENT_REGISTERED_CLASS(clifford, indexed)
37 GINAC_IMPLEMENT_REGISTERED_CLASS(diracone, tensor)
38 GINAC_IMPLEMENT_REGISTERED_CLASS(diracgamma, tensor)
39 GINAC_IMPLEMENT_REGISTERED_CLASS(diracgamma5, tensor)
40
41 //////////
42 // default constructor, destructor, copy constructor assignment operator and helpers
43 //////////
44
45 clifford::clifford() : representation_label(0)
46 {
47         debugmsg("clifford default constructor", LOGLEVEL_CONSTRUCT);
48         tinfo_key = TINFO_clifford;
49 }
50
51 void clifford::copy(const clifford & other)
52 {
53         inherited::copy(other);
54         representation_label = other.representation_label;
55 }
56
57 DEFAULT_DESTROY(clifford)
58 DEFAULT_CTORS(diracone)
59 DEFAULT_CTORS(diracgamma)
60 DEFAULT_CTORS(diracgamma5)
61
62 //////////
63 // other constructors
64 //////////
65
66 /** Construct object without any indices. This constructor is for internal
67  *  use only. Use the dirac_ONE() function instead.
68  *  @see dirac_ONE */
69 clifford::clifford(const ex & b, unsigned char rl) : inherited(b), representation_label(rl)
70 {
71         debugmsg("clifford constructor from ex", LOGLEVEL_CONSTRUCT);
72         tinfo_key = TINFO_clifford;
73 }
74
75 /** Construct object with one Lorentz index. This constructor is for internal
76  *  use only. Use the dirac_gamma() function instead.
77  *  @see dirac_gamma */
78 clifford::clifford(const ex & b, const ex & mu, unsigned char rl) : inherited(b, mu), representation_label(rl)
79 {
80         debugmsg("clifford constructor from ex,ex", LOGLEVEL_CONSTRUCT);
81         GINAC_ASSERT(is_ex_of_type(mu, varidx));
82         tinfo_key = TINFO_clifford;
83 }
84
85 clifford::clifford(unsigned char rl, const exvector & v, bool discardable) : inherited(indexed::unknown, v, discardable), representation_label(rl)
86 {
87         debugmsg("clifford constructor from unsigned char,exvector", LOGLEVEL_CONSTRUCT);
88         tinfo_key = TINFO_clifford;
89 }
90
91 clifford::clifford(unsigned char rl, exvector * vp) : inherited(indexed::unknown, vp), representation_label(rl)
92 {
93         debugmsg("clifford constructor from unsigned char,exvector *", LOGLEVEL_CONSTRUCT);
94         tinfo_key = TINFO_clifford;
95 }
96
97 //////////
98 // archiving
99 //////////
100
101 clifford::clifford(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
102 {
103         debugmsg("clifford constructor from archive_node", LOGLEVEL_CONSTRUCT);
104         unsigned rl;
105         n.find_unsigned("label", rl);
106         representation_label = rl;
107 }
108
109 void clifford::archive(archive_node &n) const
110 {
111         inherited::archive(n);
112         n.add_unsigned("label", representation_label);
113 }
114
115 DEFAULT_UNARCHIVE(clifford)
116 DEFAULT_ARCHIVING(diracone)
117 DEFAULT_ARCHIVING(diracgamma)
118 DEFAULT_ARCHIVING(diracgamma5)
119
120 //////////
121 // functions overriding virtual functions from bases classes
122 //////////
123
124 int clifford::compare_same_type(const basic & other) const
125 {
126         GINAC_ASSERT(other.tinfo() == TINFO_clifford);
127         const clifford &o = static_cast<const clifford &>(other);
128
129         if (representation_label != o.representation_label) {
130                 // different representation label
131                 return representation_label < o.representation_label ? -1 : 1;
132         }
133
134         return inherited::compare_same_type(other);
135 }
136
137 DEFAULT_COMPARE(diracone)
138 DEFAULT_COMPARE(diracgamma)
139 DEFAULT_COMPARE(diracgamma5)
140
141 DEFAULT_PRINT(diracone, "ONE")
142 DEFAULT_PRINT(diracgamma, "gamma")
143 DEFAULT_PRINT(diracgamma5, "gamma5")
144
145 /** Contraction of a gamma matrix with something else. */
146 bool diracgamma::contract_with(exvector::iterator self, exvector::iterator other, exvector & v) const
147 {
148         GINAC_ASSERT(is_ex_of_type(*self, clifford));
149         GINAC_ASSERT(is_ex_of_type(*other, indexed));
150         GINAC_ASSERT(is_ex_of_type(self->op(0), diracgamma));
151         unsigned char rl = ex_to_clifford(*self).get_representation_label();
152
153         if (is_ex_of_type(other->op(0), diracgamma)) {
154
155                 ex dim = ex_to_idx(self->op(1)).get_dim();
156
157                 // gamma~mu*gamma.mu = dim*ONE
158                 if (other - self == 1) {
159                         *self = dim;
160                         *other = dirac_ONE(rl);
161                         return true;
162
163                 // gamma~mu*gamma~alpha*gamma.mu = (2-dim)*gamma~alpha
164                 } else if (other - self == 2
165                         && is_ex_of_type(self[1], clifford)) {
166                         *self = 2 - dim;
167                         *other = _ex1();
168                         return true;
169
170                 // gamma~mu*gamma~alpha*gamma~beta*gamma.mu = 4*g~alpha~beta+(dim-4)*gamam~alpha*gamma~beta
171                 } else if (other - self == 3
172                         && is_ex_of_type(self[1], clifford)
173                         && is_ex_of_type(self[2], clifford)) {
174                         *self = 4 * metric_tensor(self[1].op(1), self[2].op(1)) * dirac_ONE(rl) + (dim - 4) * self[1] * self[2];
175                         self[1] = _ex1();
176                         self[2] = _ex1();
177                         *other = _ex1();
178                         return true;
179
180                 // gamma~mu*gamma~alpha*gamma~beta*gamma~delta*gamma.mu = -2*gamma~delta*gamma~beta*gamma~alpha+(4-dim)*gamma~alpha*gamma~beta*gamma~delta
181                 } else if (other - self == 4
182                         && is_ex_of_type(self[1], clifford)
183                         && is_ex_of_type(self[2], clifford)
184                         && is_ex_of_type(self[3], clifford)) {
185                         *self = -2 * self[3] * self[2] * self[1] + (4 - dim) * self[1] * self[2] * self[3];
186                         self[1] = _ex1();
187                         self[2] = _ex1();
188                         self[3] = _ex1();
189                         *other = _ex1();
190                         return true;
191                 }
192         }
193
194         return false;
195 }
196
197 /** Perform automatic simplification on noncommutative product of clifford
198  *  objects. This removes superfluous ONEs, permutes gamma5's to the front
199  *  and removes squares of gamma objects. */
200 ex clifford::simplify_ncmul(const exvector & v) const
201 {
202         exvector s;
203         s.reserve(v.size());
204         unsigned rl = ex_to_clifford(v[0]).get_representation_label();
205
206         // Remove superfluous ONEs
207         exvector::const_iterator cit = v.begin(), citend = v.end();
208         while (cit != citend) {
209                 if (!is_ex_of_type(cit->op(0), diracone))
210                         s.push_back(*cit);
211                 cit++;
212         }
213
214         bool something_changed = false;
215         int sign = 1;
216
217         // Anticommute gamma5's to the front
218         if (s.size() >= 2) {
219                 exvector::iterator first = s.begin(), next_to_last = s.end() - 2;
220                 while (true) {
221                         exvector::iterator it = next_to_last;
222                         while (true) {
223                                 exvector::iterator it2 = it + 1;
224                                 if (!is_ex_of_type(it->op(0), diracgamma5) && is_ex_of_type(it2->op(0), diracgamma5)) {
225                                         it->swap(*it2);
226                                         sign = -sign;
227                                         something_changed = true;
228                                 }
229                                 if (it == first)
230                                         break;
231                                 it--;
232                         }
233                         if (next_to_last == first)
234                                 break;
235                         next_to_last--;
236                 }
237         }
238
239         // Remove squares of gamma5
240         while (s.size() >= 2 && is_ex_of_type(s[0].op(0), diracgamma5) && is_ex_of_type(s[1].op(0), diracgamma5)) {
241                 s.erase(s.begin(), s.begin() + 2);
242                 something_changed = true;
243         }
244
245         // Remove equal adjacent gammas
246         if (s.size() >= 2) {
247                 exvector::iterator it = s.begin(), itend = s.end() - 1;
248                 while (it != itend) {
249                         ex & a = it[0];
250                         ex & b = it[1];
251                         if (is_ex_of_type(a.op(0), diracgamma) && is_ex_of_type(b.op(0), diracgamma)) {
252                                 const ex & ia = a.op(1);
253                                 const ex & ib = b.op(1);
254                                 if (ia.is_equal(ib)) {
255                                         a = lorentz_g(ia, ib);
256                                         b = dirac_ONE(rl);
257                                         something_changed = true;
258                                 }
259                         }
260                         it++;
261                 }
262         }
263
264         if (s.size() == 0)
265                 return clifford(diracone(), rl) * sign;
266         if (something_changed)
267                 return nonsimplified_ncmul(s) * sign;
268         else
269                 return simplified_ncmul(s) * sign;
270 }
271
272 ex clifford::thisexprseq(const exvector & v) const
273 {
274         return clifford(representation_label, v);
275 }
276
277 ex clifford::thisexprseq(exvector * vp) const
278 {
279         return clifford(representation_label, vp);
280 }
281
282 //////////
283 // global functions
284 //////////
285
286 ex dirac_ONE(unsigned char rl)
287 {
288         return clifford(diracone(), rl);
289 }
290
291 ex dirac_gamma(const ex & mu, unsigned char rl)
292 {
293         if (!is_ex_of_type(mu, varidx))
294                 throw(std::invalid_argument("index of Dirac gamma must be of type varidx"));
295
296         return clifford(diracgamma(), mu, rl);
297 }
298
299 ex dirac_gamma5(unsigned char rl)
300 {
301         return clifford(diracgamma5(), rl);
302 }
303
304 ex dirac_trace(const ex & e, unsigned char rl = 0)
305 {
306         if (is_ex_of_type(e, clifford)) {
307
308                 if (ex_to_clifford(e).get_representation_label() == rl
309                  && is_ex_of_type(e.op(0), diracone))
310                         return _ex4();
311                 else
312                         return _ex0();
313
314         } else if (is_ex_exactly_of_type(e, add)) {
315
316                 // Trace of sum = sum of traces
317                 ex sum = _ex0();
318                 for (unsigned i=0; i<e.nops(); i++)
319                         sum += dirac_trace(e.op(i), rl);
320                 return sum;
321
322         } else if (is_ex_exactly_of_type(e, mul)) {
323
324                 // Trace of product: pull out non-clifford factors
325                 ex prod = _ex1();
326                 for (unsigned i=0; i<e.nops(); i++) {
327                         const ex &o = e.op(i);
328                         if (is_ex_of_type(o, clifford)
329                          && ex_to_clifford(o).get_representation_label() == rl)
330                                 prod *= dirac_trace(o, rl);
331                         else if (is_ex_of_type(o, ncmul)
332                          && is_ex_of_type(o.op(0), clifford)
333                          && ex_to_clifford(o.op(0)).get_representation_label() == rl)
334                                 prod *= dirac_trace(o, rl);
335                         else
336                                 prod *= o;
337                 }
338                 return prod;
339
340         } else if (is_ex_exactly_of_type(e, ncmul)) {
341
342                 if (!is_ex_of_type(e.op(0), clifford)
343                  || ex_to_clifford(e.op(0)).get_representation_label() != rl)
344                         return _ex0();
345
346                 // gamma5 gets moved to the front so this check is enough
347                 bool has_gamma5 = is_ex_of_type(e.op(0).op(0), diracgamma5);
348                 unsigned num = e.nops();
349
350                 if (has_gamma5) {
351
352                         // Trace of gamma5 * odd number of gammas and trace of
353                         // gamma5 * gamma_mu * gamma_nu are zero
354                         if ((num & 1) == 0 || num == 2)
355                                 return _ex0();
356
357                 } else { // no gamma5
358
359                         // Trace of odd number of gammas is zero
360                         if ((num & 1) == 1)
361                                 return _ex0();
362
363                         // Tr gamma_mu gamma_nu = 4 g_mu_nu
364                         if (num == 2)
365                                 return 4 * lorentz_g(e.op(0).op(1), e.op(1).op(1));
366
367                         // Traces of 4 or more gammas are computed recursively:
368                         // Tr gamma_mu1 gamma_mu2 ... gamma_mun =
369                         //   + eta_mu1_mu2 * Tr gamma_mu3 ... gamma_mun
370                         //   - eta_mu1_mu3 * Tr gamma_mu2 gamma_mu4 ... gamma_mun
371                         //   + eta_mu1_mu4 * Tr gamma_mu3 gamma_mu3 gamma_mu5 ... gamma_mun
372                         //   - ...
373                         //   + eta_mu1_mun * Tr gamma_mu2 ... gamma_mu(n-1)
374                         exvector v(num - 2);
375                         int sign = 1;
376                         const ex &ix1 = e.op(0).op(1);
377                         ex result;
378                         for (int i=1; i<num; i++) {
379                                 for (int n=1, j=0; n<num; n++) {
380                                         if (n == i)
381                                                 continue;
382                                         v[j++] = e.op(n);
383                                 }
384                                 result += sign * lorentz_g(ix1, e.op(i).op(1)) * dirac_trace(ncmul(v), rl);
385                                 sign = -sign;
386                         }
387                         return result;
388                 }
389
390                 throw (std::logic_error("dirac_trace: don't know how to compute trace"));
391         }
392
393         return _ex0();
394 }
395
396 } // namespace GiNaC