e = dirac_trace(e);
result += check_equal(e, 4);
+ // traces with multiple representation labels
+ e = dirac_ONE(0) * dirac_ONE(1) / 16;
+ result += check_equal(dirac_trace(e, 0), dirac_ONE(1) / 4);
+ result += check_equal(dirac_trace(e, 1), dirac_ONE(0) / 4);
+ result += check_equal(dirac_trace(e, 2), e);
+ result += check_equal(dirac_trace(e, lst(0, 1)), 1);
+
+ e = dirac_gamma(mu, 0) * dirac_gamma(mu.toggle_variance(), 1) * dirac_gamma(nu, 0) * dirac_gamma(nu.toggle_variance(), 1);
+ result += check_equal_simplify(dirac_trace(e, 0), 4 * dim * dirac_ONE(1));
+ result += check_equal_simplify(dirac_trace(e, 1), 4 * dim * dirac_ONE(0));
+ result += check_equal_simplify(dirac_trace(e, 2), e);
+ result += check_equal_simplify(dirac_trace(e, lst(0, 1)), 16 * dim);
+
return result;
}
unsigned result = 0;
- idx a(symbol("a"), 8), b(symbol("b"), 8), c(symbol("c"), 8), k(symbol("k"), 8);
+ idx a(symbol("a"), 8), b(symbol("b"), 8), c(symbol("c"), 8);
ex e;
e = color_ONE();
e = color_T(a) * color_T(b) * color_T(c);
result += check_equal(color_trace(e), color_h(a, b, c) / 4);
+ e = color_ONE(0) * color_ONE(1) / 9;
+ result += check_equal(color_trace(e, 0), color_ONE(1) / 3);
+ result += check_equal(color_trace(e, 1), color_ONE(0) / 3);
+ result += check_equal(color_trace(e, 2), e);
+ result += check_equal(color_trace(e, lst(0, 1)), 1);
+
+ e = color_T(a, 0) * color_T(a, 1) * color_T(b, 0) * color_T(b, 1);
+ result += check_equal_simplify(color_trace(e, 0), 2 * color_ONE(1) / 3);
+ result += check_equal_simplify(color_trace(e, 1), 2 * color_ONE(0) / 3);
+ result += check_equal_simplify(color_trace(e, 2), e);
+ result += check_equal_simplify(color_trace(e, lst(0, 1)), 2);
+
return result;
}
@cindex @code{dirac_trace()}
To calculate the trace of an expression containing strings of Dirac gammas
-you use the function
+you use one of the functions
@example
+ex dirac_trace(const ex & e, const std::set<unsigned char> & rls, const ex & trONE = 4);
+ex dirac_trace(const ex & e, const lst & rll, const ex & trONE = 4);
ex dirac_trace(const ex & e, unsigned char rl = 0, const ex & trONE = 4);
@end example
-This function takes the trace of all gammas with the specified representation
-label; gammas with other labels are left standing. The last argument to
+These functions take the trace over all gammas in the specified set @code{rls}
+or list @code{rll} of representation labels, or the single label @code{rl};
+gammas with other labels are left standing. The last argument to
@code{dirac_trace()} is the value to be returned for the trace of the unity
-element, which defaults to 4. The @code{dirac_trace()} function is a linear
-functional that is equal to the usual trace only in @math{D = 4} dimensions.
-In particular, the functional is not cyclic in @math{D != 4} dimensions when
-acting on expressions containing @samp{gamma5}, so it's not a proper trace.
-This @samp{gamma5} scheme is described in greater detail in
+element, which defaults to 4.
+
+The @code{dirac_trace()} function is a linear functional that is equal to the
+ordinary matrix trace only in @math{D = 4} dimensions. In particular, the
+functional is not cyclic in @math{D != 4} dimensions when acting on
+expressions containing @samp{gamma5}, so it's not a proper trace. This
+@samp{gamma5} scheme is described in greater detail in
@cite{The Role of gamma5 in Dimensional Regularization}.
The value of the trace itself is also usually different in 4 and in
@end example
@cindex @code{color_trace()}
-To calculate the trace of an expression containing color objects you use the
-function
+To calculate the trace of an expression containing color objects you use one
+of the functions
@example
+ex color_trace(const ex & e, const std::set<unsigned char> & rls);
+ex color_trace(const ex & e, const lst & rll);
ex color_trace(const ex & e, unsigned char rl = 0);
@end example
-This function takes the trace of all color @samp{T} objects with the
-specified representation label; @samp{T}s with other labels are left
-standing. For example:
+These functions take the trace over all color @samp{T} objects in the
+specified set @code{rls} or list @code{rll} of representation labels, or the
+single label @code{rl}; @samp{T}s with other labels are left standing. For
+example:
@example
...
}
}
+/** Predicate for finding non-clifford objects. */
+struct is_not_a_clifford : public std::unary_function<ex, bool> {
+ bool operator()(const ex & e)
+ {
+ return !is_a<clifford>(e);
+ }
+};
+
/** Contraction of a gamma matrix with something else. */
bool diracgamma::contract_with(exvector::iterator self, exvector::iterator other, exvector & v) const
{
if (ex_to<clifford>(*other).get_representation_label() != rl)
return false;
+ size_t num = other - self;
+
// gamma~mu gamma.mu = dim ONE
- if (other - self == 1) {
+ if (num == 1) {
*self = dim;
*other = dirac_ONE(rl);
return true;
// gamma~mu gamma~alpha gamma.mu = (2-dim) gamma~alpha
- } else if (other - self == 2
+ } else if (num == 2
&& is_a<clifford>(self[1])) {
*self = 2 - dim;
*other = _ex1;
return true;
// gamma~mu gamma~alpha gamma~beta gamma.mu = 4 g~alpha~beta + (dim-4) gamam~alpha gamma~beta
- } else if (other - self == 3
+ } else if (num == 3
&& is_a<clifford>(self[1])
&& is_a<clifford>(self[2])) {
ex b1, i1, b2, i2;
return true;
// gamma~mu gamma~alpha gamma~beta gamma~delta gamma.mu = -2 gamma~delta gamma~beta gamma~alpha - (dim-4) gamam~alpha gamma~beta gamma~delta
- } else if (other - self == 4
+ } else if (num == 4
&& is_a<clifford>(self[1])
&& is_a<clifford>(self[2])
&& is_a<clifford>(self[3])) {
*other = _ex1;
return true;
+ // gamma~mu Sodd gamma.mu = -2 Sodd_R
+ // (Chisholm identity in 4 dimensions)
+ } else if (!((other - self) & 1) && dim.is_equal(4)) {
+ if (std::find_if(self + 1, other, is_not_a_clifford()) != other)
+ return false;
+
+ *self = ncmul(exvector(std::reverse_iterator<exvector::const_iterator>(other), std::reverse_iterator<exvector::const_iterator>(self + 1)), true);
+ std::fill(self + 1, other, _ex1);
+ *other = _ex_2;
+ return true;
+
+ // gamma~mu Sodd gamma~alpha gamma.mu = 2 gamma~alpha Sodd + 2 Sodd_R gamma~alpha
+ // (commutate contracted indices towards each other, then use
+ // Chisholm identity in 4 dimensions)
+ } else if (((other - self) & 1) && dim.is_equal(4)) {
+ if (std::find_if(self + 1, other, is_not_a_clifford()) != other)
+ return false;
+
+ exvector::iterator next_to_last = other - 1;
+ ex S = ncmul(exvector(self + 1, next_to_last), true);
+ ex SR = ncmul(exvector(std::reverse_iterator<exvector::const_iterator>(next_to_last), std::reverse_iterator<exvector::const_iterator>(self + 1)), true);
+
+ *self = (*next_to_last) * S + SR * (*next_to_last);
+ std::fill(self + 1, other, _ex1);
+ *other = _ex2;
+ return true;
+
// gamma~mu S gamma~alpha gamma.mu = 2 gamma~alpha S - gamma~mu S gamma.mu gamma~alpha
// (commutate contracted indices towards each other, simplify_indexed()
// will re-expand and re-run the simplification)
} else {
- exvector::iterator it = self + 1, next_to_last = other - 1;
- while (it != other) {
- if (!is_a<clifford>(*it))
- return false;
- ++it;
- }
+ if (std::find_if(self + 1, other, is_not_a_clifford()) != other)
+ return false;
- it = self + 1;
- ex S = _ex1;
- while (it != next_to_last) {
- S *= *it;
- *it++ = _ex1;
- }
+ exvector::iterator next_to_last = other - 1;
+ ex S = ncmul(exvector(self + 1, next_to_last), true);
*self = 2 * (*next_to_last) * S - (*self) * S * (*other) * (*next_to_last);
- *next_to_last = _ex1;
- *other = _ex1;
+ std::fill(self + 1, other + 1, _ex1);
return true;
}
return (ti & ~0xff) == TINFO_clifford;
}
+/** Extract representation label from tinfo key (as returned by
+ * return_type_tinfo()). */
+static unsigned char get_representation_label(unsigned ti)
+{
+ return ti & 0xff;
+}
+
/** 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, size_t num)
return result;
}
-ex dirac_trace(const ex & e, unsigned char rl, const ex & trONE)
+ex dirac_trace(const ex & e, const std::set<unsigned char> & rls, const ex & trONE)
{
if (is_a<clifford>(e)) {
- if (!ex_to<clifford>(e).get_representation_label() == rl)
- return _ex0;
+ unsigned char rl = ex_to<clifford>(e).get_representation_label();
+
+ // Are we taking the trace over this object's representation label?
+ if (rls.find(rl) == rls.end())
+ return e;
+
+ // Yes, all elements are traceless, except for dirac_ONE and dirac_L/R
const ex & g = e.op(0);
if (is_a<diracone>(g))
return trONE;
ex prod = _ex1;
for (size_t i=0; i<e.nops(); i++) {
const ex &o = e.op(i);
- if (is_clifford_tinfo(o.return_type_tinfo(), rl))
- prod *= dirac_trace(o, rl, trONE);
+ if (is_clifford_tinfo(o.return_type_tinfo()))
+ prod *= dirac_trace(o, rls, trONE);
else
prod *= o;
}
} else if (is_exactly_a<ncmul>(e)) {
- if (!is_clifford_tinfo(e.return_type_tinfo(), rl))
- return _ex0;
+ unsigned char rl = get_representation_label(e.return_type_tinfo());
+
+ // Are we taking the trace over this string's representation label?
+ if (rls.find(rl) == rls.end())
+ return e;
// Substitute gammaL/R and expand product, if necessary
ex e_expanded = e.subs(lst(
dirac_gammaR(rl) == (dirac_ONE(rl)+dirac_gamma5(rl))/2
), subs_options::no_pattern).expand();
if (!is_a<ncmul>(e_expanded))
- return dirac_trace(e_expanded, rl, trONE);
+ return dirac_trace(e_expanded, rls, trONE);
// gamma5 gets moved to the front so this check is enough
bool has_gamma5 = is_a<diracgamma5>(e.op(0).op(0));
} else if (e.nops() > 0) {
// Trace maps to all other container classes (this includes sums)
- pointer_to_map_function_2args<unsigned char, const ex &> fcn(dirac_trace, rl, trONE);
+ pointer_to_map_function_2args<const std::set<unsigned char> &, const ex &> fcn(dirac_trace, rls, trONE);
return e.map(fcn);
} else
return _ex0;
}
+ex dirac_trace(const ex & e, const lst & rll, const ex & trONE)
+{
+ // Convert list to set
+ std::set<unsigned char> rls;
+ for (lst::const_iterator i = rll.begin(); i != rll.end(); ++i) {
+ if (i->info(info_flags::nonnegint))
+ rls.insert(ex_to<numeric>(*i).to_int());
+ }
+
+ return dirac_trace(e, rls, trONE);
+}
+
+ex dirac_trace(const ex & e, unsigned char rl, const ex & trONE)
+{
+ // Convert label to set
+ std::set<unsigned char> rls;
+ rls.insert(rl);
+
+ return dirac_trace(e, rls, trONE);
+}
+
+
ex canonicalize_clifford(const ex & e)
{
// Scan for any ncmul objects
#include "indexed.h"
#include "tensor.h"
+#include <set>
+
namespace GiNaC {
* @param rl Representation label */
ex dirac_slash(const ex & e, const ex & dim, unsigned char rl = 0);
+/** Calculate dirac traces over the specified set of representation labels.
+ * The computed trace is a linear functional that is equal to the usual
+ * trace only in D = 4 dimensions. In particular, the functional is not
+ * always cyclic in D != 4 dimensions when gamma5 is involved.
+ *
+ * @param e Expression to take the trace of
+ * @param rls Set of representation labels
+ * @param trONE Expression to be returned as the trace of the unit matrix */
+ex dirac_trace(const ex & e, const std::set<unsigned char> & rls, const ex & trONE = 4);
+
+/** Calculate dirac traces over the specified list of representation labels.
+ * The computed trace is a linear functional that is equal to the usual
+ * trace only in D = 4 dimensions. In particular, the functional is not
+ * always cyclic in D != 4 dimensions when gamma5 is involved.
+ *
+ * @param e Expression to take the trace of
+ * @param rll List of representation labels
+ * @param trONE Expression to be returned as the trace of the unit matrix */
+ex dirac_trace(const ex & e, const lst & rll, const ex & trONE = 4);
+
/** Calculate the trace of an expression containing gamma objects with
* a specified representation label. The computed trace is a linear
* functional that is equal to the usual trace only in D = 4 dimensions.
return ti == (TINFO_color + rl);
}
-ex color_trace(const ex & e, unsigned char rl)
+/** Check whether a given tinfo key (as returned by return_type_tinfo()
+ * is that of a color object (with an arbitrary representation label). */
+static bool is_color_tinfo(unsigned ti)
+{
+ return (ti & ~0xff) == TINFO_color;
+}
+
+/** Extract representation label from tinfo key (as returned by
+ * return_type_tinfo()). */
+static unsigned char get_representation_label(unsigned ti)
+{
+ return ti & 0xff;
+}
+
+ex color_trace(const ex & e, const std::set<unsigned char> & rls)
{
if (is_a<color>(e)) {
- if (ex_to<color>(e).get_representation_label() == rl
- && is_a<su3one>(e.op(0)))
+ unsigned char rl = ex_to<color>(e).get_representation_label();
+
+ // Are we taking the trace over this object's representation label?
+ if (rls.find(rl) == rls.end())
+ return e;
+
+ // Yes, all generators are traceless, except for color_ONE
+ if (is_a<su3one>(e.op(0)))
return _ex3;
else
return _ex0;
ex prod = _ex1;
for (size_t i=0; i<e.nops(); i++) {
const ex &o = e.op(i);
- if (is_color_tinfo(o.return_type_tinfo(), rl))
- prod *= color_trace(o, rl);
+ if (is_color_tinfo(o.return_type_tinfo()))
+ prod *= color_trace(o, rls);
else
prod *= o;
}
} else if (is_exactly_a<ncmul>(e)) {
- if (!is_color_tinfo(e.return_type_tinfo(), rl))
- return _ex0;
+ unsigned char rl = get_representation_label(e.return_type_tinfo());
- // Expand product, if necessary
+ // Are we taking the trace over this string's representation label?
+ if (rls.find(rl) == rls.end())
+ return e;
+
+ // Yes, expand product if necessary
ex e_expanded = e.expand();
if (!is_a<ncmul>(e_expanded))
- return color_trace(e_expanded, rl);
+ return color_trace(e_expanded, rls);
size_t num = e.nops();
} else if (e.nops() > 0) {
// Trace maps to all other container classes (this includes sums)
- pointer_to_map_function_1arg<unsigned char> fcn(color_trace, rl);
+ pointer_to_map_function_1arg<const std::set<unsigned char> &> fcn(color_trace, rls);
return e.map(fcn);
} else
return _ex0;
}
+ex color_trace(const ex & e, const lst & rll)
+{
+ // Convert list to set
+ std::set<unsigned char> rls;
+ for (lst::const_iterator i = rll.begin(); i != rll.end(); ++i) {
+ if (i->info(info_flags::nonnegint))
+ rls.insert(ex_to<numeric>(*i).to_int());
+ }
+
+ return color_trace(e, rls);
+}
+
+ex color_trace(const ex & e, unsigned char rl)
+{
+ // Convert label to set
+ std::set<unsigned char> rls;
+ rls.insert(rl);
+
+ return color_trace(e, rls);
+}
+
} // namespace GiNaC
#include "indexed.h"
#include "tensor.h"
+#include <set>
+
namespace GiNaC {
/** This returns the linear combination d.a.b.c+I*f.a.b.c. */
ex color_h(const ex & a, const ex & b, const ex & c);
+/** Calculate color traces over the specified set of representation labels.
+ *
+ * @param e Expression to take the trace of
+ * @param rls Set of representation labels */
+ex color_trace(const ex & e, const std::set<unsigned char> & rls);
+
+/** Calculate color traces over the specified list of representation labels.
+ *
+ * @param e Expression to take the trace of
+ * @param rll List of representation labels */
+ex color_trace(const ex & e, const lst & rll);
+
/** Calculate the trace of an expression containing color objects with a
* specified representation label.
*
* performs contraction of dummy indices where possible and checks whether
* the free indices in sums are consistent.
*
+ * @param options Simplification options (currently unused)
* @return simplified expression */
ex ex::simplify_indexed(unsigned options) const
{
* scalar products by known values if desired.
*
* @param sp Scalar products to be replaced automatically
+ * @param options Simplification options (currently unused)
* @return simplified expression */
ex ex::simplify_indexed(const scalar_products & sp, unsigned options) const
{