@example
> a = x^4 + 2*x^2*y^2 + 4*x^3*y + 12*x*y^3 - 3*y^4;
--3*y^4+x^4+12*x*y^3+2*x^2*y^2+4*x^3*y
+12*x*y^3+2*x^2*y^2+4*x^3*y-3*y^4+x^4
> b = x^2 + 4*x*y - y^2;
--y^2+x^2+4*x*y
+4*x*y-y^2+x^2
> expand(a*b);
-3*y^6+x^6-24*x*y^5+43*x^2*y^4+16*x^3*y^3+17*x^4*y^2+8*x^5*y
-> collect(a*b,x);
-3*y^6+48*x*y^4+2*x^2*y^2+x^4*(-y^2+x^2+4*x*y)+4*x^3*y*(-y^2+x^2+4*x*y)
+8*x^5*y+17*x^4*y^2+43*x^2*y^4-24*x*y^5+16*x^3*y^3+3*y^6+x^6
+> collect(a+b,x);
+4*x^3*y-y^2-3*y^4+(12*y^3+4*y)*x+x^4+x^2*(1+2*y^2)
+> collect(a+b,y);
+12*x*y^3-3*y^4+(-1+2*x^2)*y^2+(4*x+4*x^3)*y+x^2+x^4
> normal(a/b);
3*y^2+x^2
@end example
* Mathematical functions:: Mathematical functions.
* Relations:: Equality, Inequality and all that.
* Indexed objects:: Handling indexed quantities.
+* Non-commutative objects:: Algebras with non-commutative products.
@end menu
@item @code{numeric} @tab All kinds of numbers, @math{42}, @math{7/3*I}, @math{3.14159}@dots{}
@item @code{add} @tab Sums like @math{x+y} or @math{a-(2*b)+3}
@item @code{mul} @tab Products like @math{x*y} or @math{2*a^2*(x+y+z)/b}
+@item @code{ncmul} @tab Products of non-commutative objects
@item @code{power} @tab Exponentials such as @math{x^2}, @math{a^b},
@tex
$\sqrt{2}$
@item @code{tensor} @tab Special tensor like the delta and metric tensors
@item @code{idx} @tab Index of an indexed object
@item @code{varidx} @tab Index with variance
+@item @code{spinidx} @tab Index with variance and dot (used in Weyl-van-der-Waerden spinor formalism)
+@item @code{wildcard} @tab Wildcard for pattern matching
@end multitable
@end cartouche
@code{expand()} must be called explicitly.
-@node Indexed objects, Methods and Functions, Relations, Basic Concepts
+@node Indexed objects, Non-commutative objects, Relations, Basic Concepts
@c node-name, next, previous, up
@section Indexed objects
a @dfn{value} and a @dfn{dimension} (which is the dimension of the space
the index lives in) which can both be arbitrary expressions but are usually
a number or a simple symbol. In addition, indices of class @code{varidx} have
-a @dfn{variance} (they can be co- or contravariant).
+a @dfn{variance} (they can be co- or contravariant), and indices of class
+@code{spinidx} have a variance and can be @dfn{dotted} or @dfn{undotted}.
@item Indexed objects are of class @code{indexed} or a subclass. They
contain a @dfn{base expression} (which is the expression being indexed), and
@end itemize
@strong{Note:} when printing expressions, covariant indices and indices
-without variance are denoted @samp{.i} while contravariant indices are denoted
-@samp{~i}. In the following, we are going to use that notation in the text
-so instead of @math{A^i_jk} we will write @samp{A~i.j.k}. Index dimensions
-are not visible in the output.
+without variance are denoted @samp{.i} while contravariant indices are
+denoted @samp{~i}. Dotted indices have a @samp{*} in front of the index
+value. In the following, we are going to use that notation in the text so
+instead of @math{A^i_jk} we will write @samp{A~i.j.k}. Index dimensions are
+not visible in the output.
A simple example shall illustrate the concepts:
which makes a new index with the same value and dimension but the opposite
variance. By using it you only have to define the index once.
+@cindex @code{spinidx} (class)
+The @code{spinidx} class provides dotted and undotted variant indices, as
+used in the Weyl-van-der-Waerden spinor formalism:
+
+@example
+ ...
+ symbol K("K"), C_sym("C"), D_sym("D");
+ spinidx C(C_sym, 2), D(D_sym); // default is 2-dimensional,
+ // contravariant, undotted
+ spinidx C_co(C_sym, 2, true); // covariant index
+ spinidx D_dot(D_sym, 2, false, true); // contravariant, dotted
+ spinidx D_co_dot(D_sym, 2, true, true); // covariant, dotted
+
+ cout << indexed(K, C, D) << endl;
+ // -> K~C~D
+ cout << indexed(K, C_co, D_dot) << endl;
+ // -> K.C~*D
+ cout << indexed(K, D_co_dot, D) << endl;
+ // -> K.*D~D
+ ...
+@end example
+
+A @code{spinidx} is a @code{varidx} with an additional flag that marks it as
+dotted or undotted. The default is undotted but this can be overridden by
+supplying a fourth argument to the @code{spinidx} constructor. The two
+methods
+
+@example
+bool spinidx::is_dotted(void);
+bool spinidx::is_undotted(void);
+@end example
+
+allow you to check whether or not a @code{spinidx} object is dotted (use
+@code{ex_to_spinidx()} to get the object reference from an expression).
+Finally, the two methods
+
+@example
+ex spinidx::toggle_dot(void);
+ex spinidx::toggle_variance_dot(void);
+@end example
+
+create a new index with the same value and dimension but opposite dottedness
+and the same or opposite variance.
+
@subsection Substituting indices
@cindex @code{subs()}
To be recognized as a dummy index pair, the two indices must be of the same
class and dimension and their value must be the same single symbol (an index
like @samp{2*n+1} is never a dummy index). If the indices are of class
-@code{varidx}, they must also be of opposite variance.
+@code{varidx} they must also be of opposite variance; if they are of class
+@code{spinidx} they must be both dotted or both undotted.
The method @code{.get_free_indices()} returns a vector containing the free
indices of an expression. It also checks that the free indices of the terms
@itemize
@item it checks the consistency of free indices in sums in the same way
@code{get_free_indices()} does
+@item it tries to give dumy indices that appear in different terms of a sum
+ the same name to allow simplifications like @math{a_i*b_i-a_j*b_j=0}
@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)
@code{simplify_indexed()} will replace all scalar products of indexed
objects that have the symbols @code{A} and @code{B} as base expressions
with the single value 0. The number, type and dimension of the indices
-doesn't matter; @samp{A~mu~nu*B.mu.nu} would also be replaced by 0.
+don't matter; @samp{A~mu~nu*B.mu.nu} would also be replaced by 0.
@cindex @code{expand()}
The example above also illustrates a feature of the @code{expand()} method:
@}
@end example
+@cindex @code{spinor_metric()}
+@subsubsection Spinor metric tensor
+
+The function @code{spinor_metric()} creates an antisymmetric tensor with
+two indices that is used to raise/lower indices of 2-component spinors.
+It is output as @samp{eps}:
+
+@example
+@{
+ symbol psi("psi");
+
+ spinidx A(symbol("A")), B(symbol("B")), C(symbol("C"));
+ ex A_co = A.toggle_variance(), B_co = B.toggle_variance();
+
+ e = spinor_metric(A, B) * indexed(psi, B_co);
+ cout << e.simplify_indexed() << endl;
+ // -> psi~A
+
+ e = spinor_metric(A, B) * indexed(psi, A_co);
+ cout << e.simplify_indexed() << endl;
+ // -> -psi~B
+
+ e = spinor_metric(A_co, B_co) * indexed(psi, B);
+ cout << e.simplify_indexed() << endl;
+ // -> -psi.A
+
+ e = spinor_metric(A_co, B_co) * indexed(psi, A);
+ cout << e.simplify_indexed() << endl;
+ // -> psi.B
+
+ e = spinor_metric(A_co, B_co) * spinor_metric(A, B);
+ cout << e.simplify_indexed() << endl;
+ // -> 2
+
+ e = spinor_metric(A_co, B_co) * spinor_metric(B, C);
+ cout << e.simplify_indexed() << endl;
+ // -> -delta.A~C
+@}
+@end example
+
+The matrix representation of the spinor metric is @code{[[ [[ 0, 1 ]], [[ -1, 0 ]] ]]}.
+
+@cindex @code{epsilon_tensor()}
+@cindex @code{lorentz_eps()}
@subsubsection Epsilon tensor
The epsilon tensor is totally antisymmetric, its number of indices is equal
of the metric tensor.
-@node Methods and Functions, Information About Expressions, Indexed objects, Top
+@node Non-commutative objects, Methods and Functions, Indexed objects, Basic Concepts
+@c node-name, next, previous, up
+@section Non-commutative objects
+
+GiNaC is equipped to handle certain non-commutative algebras. Three classes of
+non-commutative objects are built-in which are mostly of use in high energy
+physics:
+
+@itemize
+@item Clifford (Dirac) algebra (class @code{clifford})
+@item su(3) Lie algebra (class @code{color})
+@item Matrices (unindexed) (class @code{matrix})
+@end itemize
+
+The @code{clifford} and @code{color} classes are subclasses of
+@code{indexed} because the elements of these algebras ususally carry
+indices.
+
+Unlike most computer algebra systems, GiNaC does not primarily provide an
+operator (often denoted @samp{&*}) for representing inert products of
+arbitrary objects. Rather, non-commutativity in GiNaC is a property of the
+classes of objects involved, and non-commutative products are formed with
+the usual @samp{*} operator, as are ordinary products. GiNaC is capable of
+figuring out by itself which objects commute and will group the factors
+by their class. Consider this example:
+
+@example
+ ...
+ varidx mu(symbol("mu"), 4), nu(symbol("nu"), 4);
+ idx a(symbol("a"), 8), b(symbol("b"), 8);
+ ex e = -dirac_gamma(mu) * (2*color_T(a)) * 8 * color_T(b) * dirac_gamma(nu);
+ cout << e << endl;
+ // -> -16*(gamma~mu*gamma~nu)*(T.a*T.b)
+ ...
+@end example
+
+As can be seen, GiNaC pulls out the overall commutative factor @samp{-16} and
+groups the non-commutative factors (the gammas and the su(3) generators)
+together while preserving the order of factors within each class (because
+Clifford objects commute with color objects). The resulting expression is a
+@emph{commutative} product with two factors that are themselves non-commutative
+products (@samp{gamma~mu*gamma~nu} and @samp{T.a*T.b}). For clarification,
+parentheses are placed around the non-commutative products in the output.
+
+@cindex @code{ncmul} (class)
+Non-commutative products are internally represented by objects of the class
+@code{ncmul}, as opposed to commutative products which are handled by the
+@code{mul} class. You will normally not have to worry about this distinction,
+though.
+
+The advantage of this approach is that you never have to worry about using
+(or forgetting to use) a special operator when constructing non-commutative
+expressions. Also, non-commutative products in GiNaC are more intelligent
+than in other computer algebra systems; they can, for example, automatically
+canonicalize themselves according to rules specified in the implementation
+of the non-commutative classes. The drawback is that to work with other than
+the built-in algebras you have to implement new classes yourself. Symbols
+always commute and it's not possible to construct non-commutative products
+using symbols to represent the algebra elements or generators. User-defined
+functions can, however, be specified as being non-commutative.
+
+@cindex @code{return_type()}
+@cindex @code{return_type_tinfo()}
+Information about the commutativity of an object or expression can be
+obtained with the two member functions
+
+@example
+unsigned ex::return_type(void) const;
+unsigned ex::return_type_tinfo(void) const;
+@end example
+
+The @code{return_type()} function returns one of three values (defined in
+the header file @file{flags.h}), corresponding to three categories of
+expressions in GiNaC:
+
+@itemize
+@item @code{return_types::commutative}: Commutes with everything. Most GiNaC
+ classes are of this kind.
+@item @code{return_types::noncommutative}: Non-commutative, belonging to a
+ certain class of non-commutative objects which can be determined with the
+ @code{return_type_tinfo()} method. Expressions of this category commute
+ with everything except @code{noncommutative} expressions of the same
+ class.
+@item @code{return_types::noncommutative_composite}: Non-commutative, composed
+ of non-commutative objects of different classes. Expressions of this
+ category don't commute with any other @code{noncommutative} or
+ @code{noncommutative_composite} expressions.
+@end itemize
+
+The value returned by the @code{return_type_tinfo()} method is valid only
+when the return type of the expression is @code{noncommutative}. It is a
+value that is unique to the class of the object and usually one of the
+constants in @file{tinfos.h}, or derived therefrom.
+
+Here are a couple of examples:
+
+@cartouche
+@multitable @columnfractions 0.33 0.33 0.34
+@item @strong{Expression} @tab @strong{@code{return_type()}} @tab @strong{@code{return_type_tinfo()}}
+@item @code{42} @tab @code{commutative} @tab -
+@item @code{2*x-y} @tab @code{commutative} @tab -
+@item @code{dirac_ONE()} @tab @code{noncommutative} @tab @code{TINFO_clifford}
+@item @code{dirac_gamma(mu)*dirac_gamma(nu)} @tab @code{noncommutative} @tab @code{TINFO_clifford}
+@item @code{2*color_T(a)} @tab @code{noncommutative} @tab @code{TINFO_color}
+@item @code{dirac_ONE()*color_T(a)} @tab @code{noncommutative_composite} @tab -
+@end multitable
+@end cartouche
+
+Note: the @code{return_type_tinfo()} of Clifford objects is only equal to
+@code{TINFO_clifford} for objects with a representation label of zero.
+Other representation labels yield a different @code{return_type_tinfo()},
+but it's the same for any two objects with the same label. This is also true
+for color objects.
+
+
+@cindex @code{clifford} (class)
+@subsection Clifford algebra
+
+@cindex @code{dirac_gamma()}
+Clifford algebra elements (also called Dirac gamma matrices, although GiNaC
+doesn't treat them as matrices) are designated as @samp{gamma~mu} and satisfy
+@samp{gamma~mu*gamma~nu + gamma~nu*gamma~mu = 2*eta~mu~nu} where @samp{eta~mu~nu}
+is the Minkowski metric tensor. Dirac gammas are constructed by the function
+
+@example
+ex dirac_gamma(const ex & mu, unsigned char rl = 0);
+@end example
+
+which takes two arguments: the index and a @dfn{representation label} in the
+range 0 to 255 which is used to distinguish elements of different Clifford
+algebras (this is also called a @dfn{spin line index}). Gammas with different
+labels commute with each other. The dimension of the index can be 4 or (in
+the framework of dimensional regularization) any symbolic value. Spinor
+indices on Dirac gammas are not supported in GiNaC.
+
+@cindex @code{dirac_ONE()}
+The unity element of a Clifford algebra is constructed by
+
+@example
+ex dirac_ONE(unsigned char rl = 0);
+@end example
+
+@cindex @code{dirac_gamma5()}
+and 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
+
+@example
+ex dirac_gamma5(unsigned char rl = 0);
+@end example
+
+@cindex @code{dirac_gamma6()}
+@cindex @code{dirac_gamma7()}
+The two additional functions
+
+@example
+ex dirac_gamma6(unsigned char rl = 0);
+ex dirac_gamma7(unsigned char rl = 0);
+@end example
+
+return @code{dirac_ONE(rl) + dirac_gamma5(rl)} and @code{dirac_ONE(rl) - dirac_gamma5(rl)},
+respectively.
+
+@cindex @code{dirac_slash()}
+Finally, the function
+
+@example
+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.
+
+In products of dirac gammas, superfluous unity elements are automatically
+removed, squares are replaced by their values and @samp{gamma5} is
+anticommuted to the front. The @code{simplify_indexed()} function performs
+contractions in gamma strings, for example
+
+@example
+@{
+ ...
+ symbol a("a"), b("b"), D("D");
+ varidx mu(symbol("mu"), D);
+ 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
+ e = e.simplify_indexed();
+ cout << e << endl;
+ // -> -gamma~symbol10*a.symbol10*D+2*gamma~symbol10*a.symbol10
+ cout << e.subs(D == 4) << endl;
+ // -> -2*gamma~symbol10*a.symbol10
+ // [ == -2 * dirac_slash(a, D) ]
+ ...
+@}
+@end example
+
+@cindex @code{dirac_trace()}
+To calculate the trace of an expression containing strings of Dirac gammas
+you use the function
+
+@example
+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
+@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
+@cite{The Role of gamma5 in Dimensional Regularization}.
+
+The value of the trace itself is also usually different in 4 and in
+@math{D != 4} dimensions:
+
+@example
+@{
+ // 4 dimensions
+ varidx mu(symbol("mu"), 4), nu(symbol("nu"), 4), rho(symbol("rho"), 4);
+ ex e = dirac_gamma(mu) * dirac_gamma(nu) *
+ dirac_gamma(mu.toggle_variance()) * dirac_gamma(rho);
+ cout << dirac_trace(e).simplify_indexed() << endl;
+ // -> -8*eta~rho~nu
+@}
+...
+@{
+ // D dimensions
+ symbol D("D");
+ varidx mu(symbol("mu"), D), nu(symbol("nu"), D), rho(symbol("rho"), D);
+ ex e = dirac_gamma(mu) * dirac_gamma(nu) *
+ dirac_gamma(mu.toggle_variance()) * dirac_gamma(rho);
+ cout << dirac_trace(e).simplify_indexed() << endl;
+ // -> 8*eta~rho~nu-4*eta~rho~nu*D
+@}
+@end example
+
+Here is an example for using @code{dirac_trace()} to compute a value that
+appears in the calculation of the one-loop vacuum polarization amplitude in
+QED:
+
+@example
+@{
+ symbol q("q"), l("l"), m("m"), ldotq("ldotq"), D("D");
+ varidx mu(symbol("mu"), D), nu(symbol("nu"), D);
+
+ scalar_products sp;
+ sp.add(l, l, pow(l, 2));
+ sp.add(l, q, ldotq);
+
+ ex e = dirac_gamma(mu) *
+ (dirac_slash(l, D) + dirac_slash(q, D) + m * dirac_ONE()) *
+ dirac_gamma(mu.toggle_variance()) *
+ (dirac_slash(l, D) + m * dirac_ONE());
+ e = dirac_trace(e).simplify_indexed(sp);
+ e = e.collect(lst(l, ldotq, m), true);
+ cout << e << endl;
+ // -> (8-4*D)*l^2+(8-4*D)*ldotq+4*D*m^2
+@}
+@end example
+
+The @code{canonicalize_clifford()} function reorders all gamma products that
+appear in an expression to a canonical (but not necessarily simple) form.
+You can use this to compare two expressions or for further simplifications:
+
+@example
+@{
+ varidx mu(symbol("mu"), 4), nu(symbol("nu"), 4);
+ ex e = dirac_gamma(mu) * dirac_gamma(nu) + dirac_gamma(nu) * dirac_gamma(mu);
+ cout << e << endl;
+ // -> gamma~mu*gamma~nu+gamma~nu*gamma~mu
+
+ e = canonicalize_clifford(e);
+ cout << e << endl;
+ // -> 2*eta~mu~nu
+@}
+@end example
+
+
+@cindex @code{color} (class)
+@subsection Color algebra
+
+@cindex @code{color_T()}
+For computations in quantum chromodynamics, GiNaC implements the base elements
+and structure constants of the su(3) Lie algebra (color algebra). The base
+elements @math{T_a} are constructed by the function
+
+@example
+ex color_T(const ex & a, unsigned char rl = 0);
+@end example
+
+which takes two arguments: the index and a @dfn{representation label} in the
+range 0 to 255 which is used to distinguish elements of different color
+algebras. Objects with different labels commute with each other. The
+dimension of the index must be exactly 8 and it should be of class @code{idx},
+not @code{varidx}.
+
+@cindex @code{color_ONE()}
+The unity element of a color algebra is constructed by
+
+@example
+ex color_ONE(unsigned char rl = 0);
+@end example
+
+@cindex @code{color_d()}
+@cindex @code{color_f()}
+and the functions
+
+@example
+ex color_d(const ex & a, const ex & b, const ex & c);
+ex color_f(const ex & a, const ex & b, const ex & c);
+@end example
+
+create the symmetric and antisymmetric structure constants @math{d_abc} and
+@math{f_abc} which satisfy @math{@{T_a, T_b@} = 1/3 delta_ab + d_abc T_c}
+and @math{[T_a, T_b] = i f_abc T_c}.
+
+@cindex @code{color_h()}
+There's an additional function
+
+@example
+ex color_h(const ex & a, const ex & b, const ex & c);
+@end example
+
+which returns the linear combination @samp{color_d(a, b, c)+I*color_f(a, b, c)}.
+
+The function @code{simplify_indexed()} performs some simplifications on
+expressions containing color objects:
+
+@example
+@{
+ ...
+ idx a(symbol("a"), 8), b(symbol("b"), 8), c(symbol("c"), 8),
+ k(symbol("k"), 8), l(symbol("l"), 8);
+
+ e = color_d(a, b, l) * color_f(a, b, k);
+ cout << e.simplify_indexed() << endl;
+ // -> 0
+
+ e = color_d(a, b, l) * color_d(a, b, k);
+ cout << e.simplify_indexed() << endl;
+ // -> 5/3*delta.k.l
+
+ e = color_f(l, a, b) * color_f(a, b, k);
+ cout << e.simplify_indexed() << endl;
+ // -> 3*delta.k.l
+
+ e = color_h(a, b, c) * color_h(a, b, c);
+ cout << e.simplify_indexed() << endl;
+ // -> -32/3
+
+ e = color_h(a, b, c) * color_T(b) * color_T(c);
+ cout << e.simplify_indexed() << endl;
+ // -> -2/3*T.a
+
+ e = color_h(a, b, c) * color_T(a) * color_T(b) * color_T(c);
+ cout << e.simplify_indexed() << endl;
+ // -> -8/9*ONE
+
+ e = color_T(k) * color_T(a) * color_T(b) * color_T(k);
+ cout << e.simplify_indexed() << endl;
+ // -> 1/4*delta.b.a*ONE-1/6*T.a*T.b
+ ...
+@end example
+
+@cindex @code{color_trace()}
+To calculate the trace of an expression containing color objects you use the
+function
+
+@example
+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:
+
+@example
+ ...
+ e = color_trace(4 * color_T(a) * color_T(b) * color_T(c));
+ cout << e << endl;
+ // -> -I*f.a.c.b+d.a.c.b
+@}
+@end example
+
+
+@node Methods and Functions, Information About Expressions, Non-commutative objects, Top
@c node-name, next, previous, up
@chapter Methods and Functions
@cindex polynomial
@menu
* Information About Expressions::
* Substituting Expressions::
+* Pattern Matching and Advanced Substitutions::
* Polynomial Arithmetic:: Working with polynomials.
* Rational Expressions:: Working with rational functions.
* Symbolic Differentiation::
@cindex @code{ex_to_@dots{}}
@cindex @code{Converting ex to other classes}
@cindex @code{info()}
+@cindex @code{return_type()}
+@cindex @code{return_type_tinfo()}
Sometimes it's useful to check whether a given expression is a plain number,
a sum, a polynomial with integer coefficients, or of some other specific type.
-GiNaC provides two functions for this (the first one is actually a macro):
+GiNaC provides a couple of functions for this (the first one is actually a macro):
@example
bool is_ex_of_type(const ex & e, TYPENAME t);
bool ex::info(unsigned flag);
+unsigned ex::return_type(void) const;
+unsigned ex::return_type_tinfo(void) const;
@end example
When the test made by @code{is_ex_of_type()} returns true, it is safe to
@end multitable
@end cartouche
+To determine whether an expression is commutative or non-commutative and if
+so, with which other expressions it would commute, you use the methods
+@code{return_type()} and @code{return_type_tinfo()}. @xref{Non-commutative objects},
+for an explanation of these.
+
@subsection Accessing subexpressions
@cindex @code{nops()}
@cindex @code{op()}
-@cindex @code{has()}
@cindex container
@cindex @code{relational} (class)
ex ex::rhs();
@end example
-Finally, the method
-
-@example
-bool ex::has(const ex & other);
-@end example
-
-checks whether an expression contains the given subexpression @code{other}.
-This only works reliably if @code{other} is of an atomic class such as a
-@code{numeric} or a @code{symbol}. It is, e.g., not possible to verify that
-@code{a+b+c} contains @code{a+c} (or @code{a+b}) as a subexpression.
-
@subsection Comparing expressions
@cindex @code{is_equal()}
expressions will give very surprising results.
-@node Substituting Expressions, Polynomial Arithmetic, Information About Expressions, Methods and Functions
+@node Substituting Expressions, Pattern Matching and Advanced Substitutions, Information About Expressions, Methods and Functions
@c node-name, next, previous, up
@section Substituting expressions
@cindex @code{subs()}
@}
@end example
+If you specify multiple substitutions, they are performed in parallel, so e.g.
+@code{subs(lst(x == y, y == x))} exchanges @samp{x} and @samp{y}.
+
+The second form of @code{subs()} takes two lists, one for the objects to be
+replaced and one for the expressions to be substituted (both lists must
+contain the same number of elements). Using this form, you would write
+@code{subs(lst(x, y), lst(y, x))} to exchange @samp{x} and @samp{y}.
+
@code{subs()} performs syntactic substitution of any complete algebraic
object; it does not try to match sub-expressions as is demonstrated by the
following example:
cout << e1.subs(x+y == 4) << endl;
// -> 16
- ex e2 = sin(x)*cos(x);
+ ex e2 = sin(x)*sin(y)*cos(x);
cout << e2.subs(sin(x) == cos(x)) << endl;
- // -> cos(x)^2
+ // -> cos(x)^2*sin(y)
ex e3 = x+y+z;
cout << e3.subs(x+y == 4) << endl;
@}
@end example
-If you specify multiple substitutions, they are performed in parallel, so e.g.
-@code{subs(lst(x == y, y == x))} exchanges @samp{x} and @samp{y}.
+A more powerful form of substitution using wildcards is described in the
+next section.
-The second form of @code{subs()} takes two lists, one for the objects to be
-replaced and one for the expressions to be substituted (both lists must
-contain the same number of elements). Using this form, you would write
-@code{subs(lst(x, y), lst(y, x))} to exchange @samp{x} and @samp{y}.
+@node Pattern Matching and Advanced Substitutions, Polynomial Arithmetic, Substituting Expressions, Methods and Functions
+@c node-name, next, previous, up
+@section Pattern matching and advanced substitutions
+
+GiNaC allows the use of patterns for checking whether an expression is of a
+certain form or contains subexpressions of a certain form, and for
+substituting expressions in a more general way.
+
+A @dfn{pattern} is an algebraic expression that optionally contains wildcards.
+A @dfn{wildcard} is a special kind of object (of class @code{wildcard}) that
+represents an arbitrary expression. Every wildcard has a @dfn{label} which is
+an unsigned integer number to allow having multiple different wildcards in a
+pattern. Wildcards are printed as @samp{$label} (this is also the way they
+are specified in @command{ginsh}. In C++ code, wildcard objects are created
+with the call
+
+@example
+ex wild(unsigned label = 0);
+@end example
+
+which is simply a wrapper for the @code{wildcard()} constructor with a shorter
+name.
+
+Some examples for patterns:
+
+@multitable @columnfractions .5 .5
+@item @strong{Constructed as} @tab @strong{Output as}
+@item @code{wild()} @tab @samp{$0}
+@item @code{pow(x,wild())} @tab @samp{x^$0}
+@item @code{atan2(wild(1),wild(2))} @tab @samp{atan2($1,$2)}
+@item @code{indexed(A,idx(wild(),3))} @tab @samp{A.$0}
+@end multitable
+
+Notes:
+
+@itemize
+@item Wildcards behave like symbols and are subject to the same algebraic
+ rules. E.g., @samp{$0+2*$0} is automatically transformed to @samp{3*$0}.
+@item As shown in the last example, to use wildcards for indices you have to
+ use them as the value of an @code{idx} object. This is because indices must
+ always be of class @code{idx} (or a subclass).
+@item Wildcards only represent expressions or subexpressions. It is not
+ possible to use them as placeholders for other properties like index
+ dimension or variance, representation labels, symmetry of indexed objects
+ etc.
+@item Because wildcards are commutative, it is not possible to use wildcards
+ as part of noncommutative products.
+@item A pattern does not have to contain wildcards. @samp{x} and @samp{x+y}
+ are also valid patterns.
+@end itemize
-@node Polynomial Arithmetic, Rational Expressions, Substituting Expressions, Methods and Functions
+@cindex @code{match()}
+The most basic application of patterns is to check whether an expression
+matches a given pattern. This is done by the function
+
+@example
+bool ex::match(const ex & pattern);
+bool ex::match(const ex & pattern, lst & repls);
+@end example
+
+This function returns @code{true} when the expression matches the pattern
+and @code{false} if it doesn't. If used in the second form, the actual
+subexpressions matched by the wildcards get returned in the @code{repls}
+object as a list of relations of the form @samp{wildcard == expression}.
+If @code{match()} returns false, the state of @code{repls} is undefined.
+For reproducible results, the list should be empty when passed to
+@code{match()}, but it is also possible to find similarities in multiple
+expressions by passing in the result of a previous match.
+
+The matching algorithm works as follows:
+
+@itemize
+@item A single wildcard matches any expression. If one wildcard appears
+ multiple times in a pattern, it must match the same expression in all
+ places (e.g. @samp{$0} matches anything, and @samp{$0*($0+1)} matches
+ @samp{x*(x+1)} but not @samp{x*(y+1)}).
+@item If the expression is not of the same class as the pattern, the match
+ fails (i.e. a sum only matches a sum, a function only matches a function,
+ etc.).
+@item If the pattern is a function, it only matches the same function
+ (i.e. @samp{sin($0)} matches @samp{sin(x)} but doesn't match @samp{exp(x)}).
+@item Except for sums and products, the match fails if the number of
+ subexpressions (@code{nops()}) is not equal to the number of subexpressions
+ of the pattern.
+@item If there are no subexpressions, the expressions and the pattern must
+ be equal (in the sense of @code{is_equal()}).
+@item Except for sums and products, each subexpression (@code{op()}) must
+ match the corresponding subexpression of the pattern.
+@end itemize
+
+Sums (@code{add}) and products (@code{mul}) are treated in a special way to
+account for their commutativity and associativity:
+
+@itemize
+@item If the pattern contains a term or factor that is a single wildcard,
+ this one is used as the @dfn{global wildcard}. If there is more than one
+ such wildcard, one of them is chosen as the global wildcard in a random
+ way.
+@item Every term/factor of the pattern, except the global wildcard, is
+ matched against every term of the expression in sequence. If no match is
+ found, the whole match fails. Terms that did match are not considered in
+ further matches.
+@item If there are no unmatched terms left, the match succeeds. Otherwise
+ the match fails unless there is a global wildcard in the pattern, in
+ which case this wildcard matches the remaining terms.
+@end itemize
+
+In general, having more than one single wildcard as a term of a sum or a
+factor of a product (such as @samp{a+$0+$1}) will lead to unpredictable or
+amgiguous results.
+
+Here are some examples in @command{ginsh} to demonstrate how it works (the
+@code{match()} function in @command{ginsh} returns @samp{FAIL} if the
+match fails, and the list of wildcard replacements otherwise):
+
+@example
+> match((x+y)^a,(x+y)^a);
+[]
+> match((x+y)^a,(x+y)^b);
+FAIL
+> match((x+y)^a,$1^$2);
+[$1==x+y,$2==a]
+> match((x+y)^a,$1^$1);
+FAIL
+> match((x+y)^(x+y),$1^$1);
+[$1==x+y]
+> match((x+y)^(x+y),$1^$2);
+[$1==x+y,$2==x+y]
+> match((a+b)*(a+c),($1+b)*($1+c));
+[$1==a]
+> match((a+b)*(a+c),(a+$1)*(a+$2));
+[$1==c,$2==b]
+ (Unpredictable. The result might also be [$1==c,$2==b].)
+> match((a+b)*(a+c),($1+$2)*($1+$3));
+ (The result is undefined. Due to the sequential nature of the algorithm
+ and the re-ordering of terms in GiNaC, the match for the first factor
+ may be [$1==a,$2==b] in which case the match for the second factor
+ succeeds, or it may be [$1==b,$2==a] which causes the second match to
+ fail.)
+> match(a*(x+y)+a*z+b,a*$1+$2);
+ (This is also ambiguous and may return either [$1==z,$2==a*(x+y)+b] or
+ [$1=x+y,$2=a*z+b].)
+> match(a+b+c+d+e+f,c);
+FAIL
+> match(a+b+c+d+e+f,c+$0);
+[$0==a+e+b+f+d]
+> match(a+b+c+d+e+f,c+e+$0);
+[$0==a+b+f+d]
+> match(a+b,a+b+$0);
+[$0==0]
+> match(a*b^2,a^$1*b^$2);
+FAIL
+ (The matching is syntactic, not algebraic, and "a" doesn't match "a^$1"
+ even if a==a^1.)
+> match(x*atan2(x,x^2),$0*atan2($0,$0^2));
+[$0==x]
+> match(atan2(y,x^2),atan2(y,$0));
+[$0==x^2]
+@end example
+
+@cindex @code{has()}
+A more general way to look for patterns in expressions is provided by the
+member function
+
+@example
+bool ex::has(const ex & pattern);
+@end example
+
+This function checks whether a pattern is matched by an expression itself or
+by any of its subexpressions.
+
+Again some examples in @command{ginsh} for illustration (in @command{ginsh},
+@code{has()} returns @samp{1} for @code{true} and @samp{0} for @code{false}):
+
+@example
+> has(x*sin(x+y+2*a),y);
+1
+> has(x*sin(x+y+2*a+y),x+y);
+0
+ (This is because in GiNaC, "x+y" is not a subexpression of "x+y+2*a" (which
+ has the subexpressions "x", "y" and "2*a".)
+> has(x*sin(x+y+2*a+y),x+y+$1);
+1
+ (But this is possible.)
+> has(x*sin(2*(x+y)+2*a),x+y);
+0
+ (This fails because "2*(x+y)" automatically gets converted to "2*x+2*y" of
+ which "x+y" is not a subexpression.)
+> has(x+1,x^$1);
+0
+ (Although x^1==x and x^0==1, neither "x" nor "1" are actually of the form
+ "x^something".)
+> has(4*x^2-x+3,$1*x);
+1
+> has(4*x^2+x+3,$1*x);
+0
+ (Another possible pitfall. The first expression matches because the term
+ "-x" has the form "(-1)*x" in GiNaC. To check whether a polynomial
+ contains a linear term you should use the coeff() function instead.)
+@end example
+
+@cindex @code{subs()}
+Probably the most useful application of patterns is to use them for
+substituting expressions with the @code{subs()} method. Wildcards can be
+used in the search patterns as well as in the replacement expressions, where
+they get replaced by the expressions matched by them. @code{subs()} doesn't
+know anything about algebra; it performs purely syntactic substitutions.
+
+Some examples:
+
+@example
+> subs(a^2+b^2+(x+y)^2,$1^2==$1^3);
+b^3+a^3+(x+y)^3
+> subs(a^4+b^4+(x+y)^4,$1^2==$1^3);
+b^4+a^4+(x+y)^4
+> subs((a+b+c)^2,a+b=x);
+(a+b+c)^2
+> subs((a+b+c)^2,a+b+$1==x+$1);
+(x+c)^2
+> subs(a+2*b,a+b=x);
+a+2*b
+> subs(4*x^3-2*x^2+5*x-1,x==a);
+-1+5*a-2*a^2+4*a^3
+> subs(4*x^3-2*x^2+5*x-1,x^$0==a^$0);
+-1+5*x-2*a^2+4*a^3
+> subs(sin(1+sin(x)),sin($1)==cos($1));
+cos(1+cos(x))
+> expand(subs(a*sin(x+y)^2+a*cos(x+y)^2+b,cos($1)^2==1-sin($1)^2));
+a+b
+@end example
+
+The last example would be written in C++ in this way:
+
+@example
+@{
+ symbol a("a"), b("b"), x("x"), y("y");
+ e = a*pow(sin(x+y), 2) + a*pow(cos(x+y), 2) + b;
+ e = e.subs(pow(cos(wild()), 2) == 1-pow(sin(wild()), 2));
+ cout << e.expand() << endl;
+ // -> "b+a"
+@}
+@end example
+
+
+@node Polynomial Arithmetic, Rational Expressions, Pattern Matching and Advanced Substitutions, Methods and Functions
@c node-name, next, previous, up
@section Polynomial arithmetic
@code{collect()} accomplishes this task:
@example
-ex ex::collect(const ex & s);
+ex ex::collect(const ex & s, bool distributed = false);
@end example
+The first argument to @code{collect()} can also be a list of objects in which
+case the result is either a recursively collected polynomial, or a polynomial
+in a distributed form with terms like @math{c*x1^e1*...*xn^en}, as specified
+by the @code{distributed} flag.
+
Note that the original polynomial needs to be in expanded form in order
-to be able to find the coefficients properly.
+for @code{collect()} to be able to find the coefficients properly.
@subsection Degree and coefficients
@cindex @code{degree()}
Another useful output format is for LaTeX parsing in mathematical mode.
It is rather similar to the default @code{print_context} but provides
some braces needed by LaTeX for delimiting boxes and also converts some
-common objects to conventional LaTeX names. The code snippet
+common objects to conventional LaTeX names. It is possible to give symbols
+a special name for LaTeX output by supplying it as a second argument to
+the @code{symbol} constructor.
+
+For example, the code snippet
@example
// ...
some more functions that you will want to re-implement, such as
@code{evalf()}, @code{series()} or @code{op()}. Have a look at @file{basic.h}
or the header file of the class you want to make a subclass of to see
-what's there. You can, of course, also add your own new member functions.
-In this case you will probably want to define a little helper function like
+what's there. One member function that you will most likely want to
+implement for terminal classes like the described string class is
+@code{calcchash()} that returns an @code{unsigned} hash value for the object
+which will allow GiNaC to compare and canonicalize expressions much more
+efficiently.
+
+You can, of course, also add your own new member functions. In this case you
+will probably want to define a little helper function like
@example
inline const mystring &ex_to_mystring(const ex &e)
@}
@end example
-that let's you get at the object inside an expression (after you have verified
-that the type is correct) so you can call member functions that are specific
-to the class.
+that let's you get at the object inside an expression (after you have
+verified that the type is correct) so you can call member functions that are
+specific to the class.
That's it. May the source be with you!
J.H. Davenport, Y. Siret, and E. Tournier, ISBN 0-12-204230-1, 1988,
Academic Press, London
+@item
+@cite{The Role of gamma5 in Dimensional Regularization}, D. Kreimer, hep-ph/9401354
+
@end itemize