+/** Check whether a given tinfo key (as returned by return_type_tinfo()
+ * is that of a clifford object (with an arbitrary representation label). */
+static bool is_clifford_tinfo(unsigned ti)
+{
+ return (ti & ~0xff) == TINFO_clifford;
+}
+
+/** Take trace of a string of an even number of Dirac gammas given a vector
+ * of indices. */
+static ex trace_string(exvector::const_iterator ix, unsigned num)
+{
+ // Tr gamma.mu gamma.nu = 4 g.mu.nu
+ if (num == 2)
+ return lorentz_g(ix[0], ix[1]);
+
+ // Tr gamma.mu gamma.nu gamma.rho gamma.sig = 4 (g.mu.nu g.rho.sig + g.nu.rho g.mu.sig - g.mu.rho g.nu.sig
+ else if (num == 4)
+ return lorentz_g(ix[0], ix[1]) * lorentz_g(ix[2], ix[3])
+ + lorentz_g(ix[1], ix[2]) * lorentz_g(ix[0], ix[3])
+ - lorentz_g(ix[0], ix[2]) * lorentz_g(ix[1], ix[3]);
+
+ // Traces of 6 or more gammas are computed recursively:
+ // Tr gamma.mu1 gamma.mu2 ... gamma.mun =
+ // + g.mu1.mu2 * Tr gamma.mu3 ... gamma.mun
+ // - g.mu1.mu3 * Tr gamma.mu2 gamma.mu4 ... gamma.mun
+ // + g.mu1.mu4 * Tr gamma.mu3 gamma.mu3 gamma.mu5 ... gamma.mun
+ // - ...
+ // + g.mu1.mun * Tr gamma.mu2 ... gamma.mu(n-1)
+ exvector v(num - 2);
+ int sign = 1;
+ ex result;
+ for (unsigned i=1; i<num; i++) {
+ for (unsigned n=1, j=0; n<num; n++) {
+ if (n == i)
+ continue;
+ v[j++] = ix[n];
+ }
+ result += sign * lorentz_g(ix[0], ix[i]) * trace_string(v.begin(), num-2);
+ sign = -sign;
+ }
+ return result;
+}
+