@item it (symbolically) calculates all possible dummy index summations/contractions
with the predefined tensors (this will be explained in more detail in the
next section)
+@item it detects contractions that vanish for symmetry reasons, for example
+ the contraction of a symmetric and a totally antisymmetric tensor
@item as a special case of dummy index summation, it can replace scalar products
of two tensors with a user-defined value
@end itemize
dimensions, the last function creates an epsilon tensor in a 4-dimensional
Minkowski space (the last @code{bool} argument specifies whether the metric
has negative or positive signature, as in the case of the Minkowski metric
-tensor).
+tensor):
+
+@example
+@{
+ varidx mu(symbol("mu"), 4), nu(symbol("nu"), 4), rho(symbol("rho"), 4),
+ sig(symbol("sig"), 4), lam(symbol("lam"), 4), bet(symbol("bet"), 4);
+ e = lorentz_eps(mu, nu, rho, sig) *
+ lorentz_eps(mu.toggle_variance(), nu.toggle_variance(), lam, bet);
+ cout << simplify_indexed(e) << endl;
+ // -> 2*eta~bet~rho*eta~sig~lam-2*eta~sig~bet*eta~rho~lam
+
+ idx i(symbol("i"), 3), j(symbol("j"), 3), k(symbol("k"), 3);
+ symbol A("A"), B("B");
+ e = epsilon_tensor(i, j, k) * indexed(A, j) * indexed(B, k);
+ cout << simplify_indexed(e) << endl;
+ // -> -B.k*A.j*eps.i.k.j
+ e = epsilon_tensor(i, j, k) * indexed(A, j) * indexed(A, k);
+ cout << simplify_indexed(e) << endl;
+ // -> 0
+@}
+@end example
@subsection Linear algebra
ex dirac_ONE(unsigned char rl = 0);
@end example
+@strong{Note:} You must always use @code{dirac_ONE()} when referring to
+multiples of the unity element, even though it's customary to omit it.
+E.g. instead of @code{dirac_gamma(mu)*(dirac_slash(q,4)+m)} you have to
+write @code{dirac_gamma(mu)*(dirac_slash(q,4)+m*dirac_ONE())}. Otherwise,
+GiNaC may produce incorrect results.
+
@cindex @code{dirac_gamma5()}
-and there's a special element @samp{gamma5} that commutes with all other
+There's a special element @samp{gamma5} that commutes with all other
gammas and in 4 dimensions equals @samp{gamma~0 gamma~1 gamma~2 gamma~3},
provided by
ex dirac_slash(const ex & e, const ex & dim, unsigned char rl = 0);
@end example
-creates a term of the form @samp{e.mu gamma~mu} with a new and unique index
-whose dimension is given by the @code{dim} argument.
+creates a term that represents a contraction of @samp{e} with the Dirac
+Lorentz vector (it behaves like a term of the form @samp{e.mu gamma~mu}
+with a unique index whose dimension is given by the @code{dim} argument).
+Such slashed expressions are printed with a trailing backslash, e.g. @samp{e\}.
In products of dirac gammas, superfluous unity elements are automatically
removed, squares are replaced by their values and @samp{gamma5} is
ex e = dirac_gamma(mu) * dirac_slash(a, D)
* dirac_gamma(mu.toggle_variance());
cout << e << endl;
- // -> (gamma~mu*gamma~symbol10*gamma.mu)*a.symbol10
+ // -> gamma~mu*a\*gamma.mu
e = e.simplify_indexed();
cout << e << endl;
- // -> -gamma~symbol10*a.symbol10*D+2*gamma~symbol10*a.symbol10
+ // -> -D*a\+2*a\
cout << e.subs(D == 4) << endl;
- // -> -2*gamma~symbol10*a.symbol10
- // [ == -2 * dirac_slash(a, D) ]
+ // -> -2*a\
...
@}
@end example
ex color_ONE(unsigned char rl = 0);
@end example
+@strong{Note:} You must always use @code{color_ONE()} when referring to
+multiples of the unity element, even though it's customary to omit it.
+E.g. instead of @code{color_T(a)*(color_T(b)*indexed(X,b)+1)} you have to
+write @code{color_T(a)*(color_T(b)*indexed(X,b)+color_ONE())}. Otherwise,
+GiNaC may produce incorrect results.
+
@cindex @code{color_d()}
@cindex @code{color_f()}
-and the functions
+The functions
@example
ex color_d(const ex & a, const ex & b, const ex & c);
@}
@end example
+Here is another example for you to meditate over. It removes quadratic
+terms in a variable from an expanded polynomial:
+
+@example
+struct map_rem_quad : public map_function @{
+ ex var;
+ map_rem_quad(const ex & var_) : var(var_) @{@}
+
+ ex operator()(const ex & e)
+ @{
+ if (is_a<add>(e) || is_a<mul>(e))
+ return e.map(*this);
+ else if (is_a<power>(e) && e.op(0).is_equal(var) && e.op(1).info(info_flags::even))
+ return 0;
+ else
+ return e;
+ @}
+@};
+
+...
+
+@{
+ symbol x("x"), y("y");
+
+ ex e;
+ for (int i=0; i<8; i++)
+ e += pow(x, i) * pow(y, 8-i) * (i+1);
+ cout << e << endl;
+ // -> 4*y^5*x^3+5*y^4*x^4+8*y*x^7+7*y^2*x^6+2*y^7*x+6*y^3*x^5+3*y^6*x^2+y^8
+
+ map_rem_quad rem_quad(x);
+ cout << rem_quad(e) << endl;
+ // -> 4*y^5*x^3+8*y*x^7+2*y^7*x+6*y^3*x^5+y^8
+@}
+@end example
+
@command{ginsh} offers a slightly different implementation of @code{map()}
that allows applying algebraic functions to operands. The second argument
to @code{map()} is an expression containing the wildcard @samp{$0} which
@item @code{csgn(x)}
@tab complex sign
@item @code{sqrt(x)}
-@tab square root (not a GiNaC function proper but equivalent to @code{pow(x, numeric(1, 2)})
+@tab square root (not a GiNaC function, rather an alias for @code{pow(x, numeric(1, 2))})
@item @code{sin(x)}
@tab sine
@item @code{cos(x)}
@tab binomial coefficients
@item @code{Order(x)}
@tab order term function in truncated power series
-@item @code{Derivative(x, l)}
-@tab inert partial differentiation operator (used internally)
@end multitable
@end cartouche
@example
static ex cos_evalf(const ex & x)
@{
- return cos(ex_to<numeric>(x));
+ if (is_a<numeric>(x))
+ return cos(ex_to<numeric>(x));
+ else
+ return cos(x).hold();
@}
@end example
J.H. Davenport, Y. Siret, and E. Tournier, ISBN 0-12-204230-1, 1988,
Academic Press, London
+@item
+@cite{The Art of Computer Programming, Vol 2: Seminumerical Algorithms},
+D.E. Knuth, ISBN 0-201-89684-2, 1998, Addison Wesley
+
@item
@cite{The Role of gamma5 in Dimensional Regularization}, D. Kreimer, hep-ph/9401354