@end itemize
-In addition, you may specify some environment variables.
-@env{CXX} holds the path and the name of the C++ compiler
-in case you want to override the default in your path. (The
-@command{configure} script searches your path for @command{c++},
-@command{g++}, @command{gcc}, @command{CC}, @command{cxx}
-and @command{cc++} in that order.) It may be very useful to
-define some compiler flags with the @env{CXXFLAGS} environment
-variable, like optimization, debugging information and warning
-levels. If omitted, it defaults to @option{-g -O2}.
+In addition, you may specify some environment variables. @env{CXX}
+holds the path and the name of the C++ compiler in case you want to
+override the default in your path. (The @command{configure} script
+searches your path for @command{c++}, @command{g++}, @command{gcc},
+@command{CC}, @command{cxx} and @command{cc++} in that order.) It may
+be very useful to define some compiler flags with the @env{CXXFLAGS}
+environment variable, like optimization, debugging information and
+warning levels. If omitted, it defaults to @option{-g
+-O2}.@footnote{The @command{configure} script is itself generated from
+the file @file{configure.in}. It is only distributed in packaged
+releases of GiNaC. If you got the naked sources, e.g. from CVS, you
+must generate @command{configure} along with the various
+@file{Makefile.in} by using the @command{autogen.sh} script.}
The whole process is illustrated in the following two
examples. (Substitute @command{setenv @var{VARIABLE} @var{value}} for
@example
$ export CXX=/usr/local/gnu/bin/c++
$ export CPPFLAGS="$(CPPFLAGS) -I$(HOME)/include"
-$ export CXXFLAGS="$(CXXFLAGS) -DDO_GINAC_ASSERT -ggdb -Wall -ansi -pedantic"
+$ export CXXFLAGS="$(CXXFLAGS) -DDO_GINAC_ASSERT -ggdb -Wall -pedantic"
$ export LDFLAGS="$(LDFLAGS) -L$(HOME)/lib"
$ ./configure --disable-shared --prefix=$(HOME)
@end example
Generally, the top-level Makefile runs recursively to the
subdirectories. It is therfore safe to go into any subdirectory
-(@code{doc/}, @code{ginsh/}, ...) and simply type @code{make}
+(@code{doc/}, @code{ginsh/}, @dots{}) and simply type @code{make}
@var{target} there in case something went wrong.
* Lists:: Lists of expressions.
* Mathematical functions:: Mathematical functions.
* Relations:: Equality, Inequality and all that.
+* Matrices:: Matrices.
* Indexed objects:: Handling indexed quantities.
* Non-commutative objects:: Algebras with non-commutative products.
@end menu
The most common class of objects a user deals with is the expression
@code{ex}, representing a mathematical object like a variable, number,
-function, sum, product, etc... Expressions may be put together to form
+function, sum, product, etc@dots{} Expressions may be put together to form
new expressions, passed as arguments to functions, and so on. Here is a
little collection of valid expressions:
@item @code{pseries} @tab Power Series, e.g. @math{x-1/6*x^3+1/120*x^5+O(x^7)}
@item @code{function} @tab A symbolic function like @math{sin(2*x)}
@item @code{lst} @tab Lists of expressions @{@math{x}, @math{2*y}, @math{3+z}@}
-@item @code{matrix} @tab @math{n}x@math{m} matrices of expressions
+@item @code{matrix} @tab @math{m}x@math{n} matrices of expressions
@item @code{relational} @tab A relation like the identity @math{x}@code{==}@math{y}
@item @code{indexed} @tab Indexed object like @math{A_ij}
@item @code{tensor} @tab Special tensor like the delta and metric tensors
Although symbols can be assigned expressions for internal reasons, you
should not do it (and we are not going to tell you how it is done). If
you want to replace a symbol with something else in an expression, you
-can use the expression's @code{.subs()} method (@xref{Substituting Expressions},
-for more information).
+can use the expression's @code{.subs()} method (@pxref{Substituting Expressions}).
@node Numbers, Constants, Symbols, Basic Concepts
int main()
@{
- numeric two(2); // exact integer 2
+ numeric two = 2; // exact integer 2
numeric r(2,3); // exact fraction 2/3
numeric e(2.71828); // floating point number
- numeric p("3.1415926535897932385"); // floating point number
+ numeric p = "3.14159265358979323846"; // constructor from string
// Trott's constant in scientific notation:
numeric trott("1.0841015122311136151E-2");
@}
@end example
-Note that all those constructors are @emph{explicit} which means you are
-not allowed to write @code{numeric two=2;}. This is because the basic
-objects to be handled by GiNaC are the expressions @code{ex} and we want
-to keep things simple and wish objects like @code{pow(x,2)} to be
-handled the same way as @code{pow(x,a)}, which means that we need to
-allow a general @code{ex} as base and exponent. Therefore there is an
-implicit constructor from C-integers directly to expressions handling
-numerics at work in most of our examples. This design really becomes
-convenient when one declares own functions having more than one
-parameter but it forbids using implicit constructors because that would
-lead to compile-time ambiguities.
-
It may be tempting to construct numbers writing @code{numeric r(3/2)}.
This would, however, call C's built-in operator @code{/} for integers
first and result in a numeric holding a plain integer 1. @strong{Never
@cindex @code{op()}
@cindex @code{append()}
@cindex @code{prepend()}
+@cindex @code{remove_first()}
+@cindex @code{remove_last()}
-The GiNaC class @code{lst} serves for holding a list of arbitrary expressions.
-These are sometimes used to supply a variable number of arguments of the same
-type to GiNaC methods such as @code{subs()} and @code{to_rational()}, so you
-should have a basic understanding about them.
+The GiNaC class @code{lst} serves for holding a @dfn{list} of arbitrary
+expressions. These are sometimes used to supply a variable number of
+arguments of the same type to GiNaC methods such as @code{subs()} and
+@code{to_rational()}, so you should have a basic understanding about them.
-Lists of up to 15 expressions can be directly constructed from single
+Lists of up to 16 expressions can be directly constructed from single
expressions:
@example
// ...
@end example
-Finally you can append or prepend an expression to a list with the
-@code{append()} and @code{prepend()} methods:
+You can append or prepend an expression to a list with the @code{append()}
+and @code{prepend()} methods:
@example
// ...
l.append(4*x); // l is now @{x, 2, y, x+y, 4*x@}
l.prepend(0); // l is now @{0, x, 2, y, x+y, 4*x@}
+ // ...
+@end example
+
+Finally you can remove the first or last element of a list with
+@code{remove_first()} and @code{remove_last()}:
+
+@example
+ // ...
+ l.remove_first(); // l is now @{x, 2, y, x+y, 4*x@}
+ l.remove_last(); // l is now @{x, 2, y, x+y@}
@}
@end example
instance, all trigonometric and hyperbolic functions are implemented
(@xref{Built-in Functions}, for a complete list).
-These functions are all objects of class @code{function}. They accept
-one or more expressions as arguments and return one expression. If the
-arguments are not numerical, the evaluation of the function may be
-halted, as it does in the next example, showing how a function returns
-itself twice and finally an expression that may be really useful:
+These functions (better called @emph{pseudofunctions}) are all objects
+of class @code{function}. They accept one or more expressions as
+arguments and return one expression. If the arguments are not
+numerical, the evaluation of the function may be halted, as it does in
+the next example, showing how a function returns itself twice and
+finally an expression that may be really useful:
@cindex Gamma function
@cindex @code{subs()}
expansion and so on. Read the next chapter in order to learn more about
this.
+It must be noted that these pseudofunctions are created by inline
+functions, where the argument list is templated. This means that
+whenever you call @code{GiNaC::sin(1)} it is equivalent to
+@code{sin(ex(1))} and will therefore not result in a floating point
+numeber. Unless of course the function prototype is explicitly
+overridden -- which is the case for arguments of type @code{numeric}
+(not wrapped inside an @code{ex}). Hence, in order to obtain a floating
+point number of class @code{numeric} you should call
+@code{sin(numeric(1))}. This is almost the same as calling
+@code{sin(1).evalf()} except that the latter will return a numeric
+wrapped inside an @code{ex}.
+
-@node Relations, Indexed objects, Mathematical functions, Basic Concepts
+@node Relations, Matrices, Mathematical functions, Basic Concepts
@c node-name, next, previous, up
@section Relations
@cindex @code{relational} (class)
@code{expand()} must be called explicitly.
-@node Indexed objects, Non-commutative objects, Relations, Basic Concepts
+@node Matrices, Indexed objects, Relations, Basic Concepts
+@c node-name, next, previous, up
+@section Matrices
+@cindex @code{matrix} (class)
+
+A @dfn{matrix} is a two-dimensional array of expressions. The elements of a
+matrix with @math{m} rows and @math{n} columns are accessed with two
+@code{unsigned} indices, the first one in the range 0@dots{}@math{m-1}, the
+second one in the range 0@dots{}@math{n-1}.
+
+There are a couple of ways to construct matrices, with or without preset
+elements:
+
+@example
+matrix::matrix(unsigned r, unsigned c);
+matrix::matrix(unsigned r, unsigned c, const lst & l);
+ex lst_to_matrix(const lst & l);
+ex diag_matrix(const lst & l);
+@end example
+
+The first two functions are @code{matrix} constructors which create a matrix
+with @samp{r} rows and @samp{c} columns. The matrix elements can be
+initialized from a (flat) list of expressions @samp{l}. Otherwise they are
+all set to zero. The @code{lst_to_matrix()} function constructs a matrix
+from a list of lists, each list representing a matrix row. Finally,
+@code{diag_matrix()} constructs a diagonal matrix given the list of diagonal
+elements. Note that the last two functions return expressions, not matrix
+objects.
+
+Matrix elements can be accessed and set using the parenthesis (function call)
+operator:
+
+@example
+const ex & matrix::operator()(unsigned r, unsigned c) const;
+ex & matrix::operator()(unsigned r, unsigned c);
+@end example
+
+It is also possible to access the matrix elements in a linear fashion with
+the @code{op()} method. But C++-style subscripting with square brackets
+@samp{[]} is not available.
+
+Here are a couple of examples that all construct the same 2x2 diagonal
+matrix:
+
+@example
+@{
+ symbol a("a"), b("b");
+ ex e;
+
+ matrix M(2, 2);
+ M(0, 0) = a;
+ M(1, 1) = b;
+ e = M;
+
+ e = matrix(2, 2, lst(a, 0, 0, b));
+
+ e = lst_to_matrix(lst(lst(a, 0), lst(0, b)));
+
+ e = diag_matrix(lst(a, b));
+
+ cout << e << endl;
+ // -> [[a,0],[0,b]]
+@}
+@end example
+
+@cindex @code{transpose()}
+@cindex @code{inverse()}
+There are three ways to do arithmetic with matrices. The first (and most
+efficient one) is to use the methods provided by the @code{matrix} class:
+
+@example
+matrix matrix::add(const matrix & other) const;
+matrix matrix::sub(const matrix & other) const;
+matrix matrix::mul(const matrix & other) const;
+matrix matrix::mul_scalar(const ex & other) const;
+matrix matrix::pow(const ex & expn) const;
+matrix matrix::transpose(void) const;
+matrix matrix::inverse(void) const;
+@end example
+
+All of these methods return the result as a new matrix object. Here is an
+example that calculates @math{A*B-2*C} for three matrices @math{A}, @math{B}
+and @math{C}:
+
+@example
+@{
+ matrix A(2, 2, lst(1, 2, 3, 4));
+ matrix B(2, 2, lst(-1, 0, 2, 1));
+ matrix C(2, 2, lst(8, 4, 2, 1));
+
+ matrix result = A.mul(B).sub(C.mul_scalar(2));
+ cout << result << endl;
+ // -> [[-13,-6],[1,2]]
+ ...
+@}
+@end example
+
+@cindex @code{evalm()}
+The second (and probably the most natural) way is to construct an expression
+containing matrices with the usual arithmetic operators and @code{pow()}.
+For efficiency reasons, expressions with sums, products and powers of
+matrices are not automatically evaluated in GiNaC. You have to call the
+method
+
+@example
+ex ex::evalm() const;
+@end example
+
+to obtain the result:
+
+@example
+@{
+ ...
+ ex e = A*B - 2*C;
+ cout << e << endl;
+ // -> [[1,2],[3,4]]*[[-1,0],[2,1]]-2*[[8,4],[2,1]]
+ cout << e.evalm() << endl;
+ // -> [[-13,-6],[1,2]]
+ ...
+@}
+@end example
+
+The non-commutativity of the product @code{A*B} in this example is
+automatically recognized by GiNaC. There is no need to use a special
+operator here. @xref{Non-commutative objects}, for more information about
+dealing with non-commutative expressions.
+
+Finally, you can work with indexed matrices and call @code{simplify_indexed()}
+to perform the arithmetic:
+
+@example
+@{
+ ...
+ idx i(symbol("i"), 2), j(symbol("j"), 2), k(symbol("k"), 2);
+ e = indexed(A, i, k) * indexed(B, k, j) - 2 * indexed(C, i, j);
+ cout << e << endl;
+ // -> -2*[[8,4],[2,1]].i.j+[[-1,0],[2,1]].k.j*[[1,2],[3,4]].i.k
+ cout << e.simplify_indexed() << endl;
+ // -> [[-13,-6],[1,2]].i.j
+@}
+@end example
+
+Using indices is most useful when working with rectangular matrices and
+one-dimensional vectors because you don't have to worry about having to
+transpose matrices before multiplying them. @xref{Indexed objects}, for
+more information about using matrices with indices, and about indices in
+general.
+
+The @code{matrix} class provides a couple of additional methods for
+computing determinants, traces, and characteristic polynomials:
+
+@example
+ex matrix::determinant(unsigned algo = determinant_algo::automatic) const;
+ex matrix::trace(void) const;
+ex matrix::charpoly(const symbol & lambda) const;
+@end example
+
+The @samp{algo} argument of @code{determinant()} allows to select between
+different algorithms for calculating the determinant. The possible values
+are defined in the @file{flags.h} header file. By default, GiNaC uses a
+heuristic to automatically select an algorithm that is likely to give the
+result most quickly.
+
+
+@node Indexed objects, Non-commutative objects, Matrices, Basic Concepts
@c node-name, next, previous, up
@section Indexed objects
return the value and dimension of an @code{idx} object. If you have an index
in an expression, such as returned by calling @code{.op()} on an indexed
object, you can get a reference to the @code{idx} object with the function
-@code{ex_to_idx()} on the expression.
+@code{ex_to<idx>()} on the expression.
There are also the methods
bool varidx::is_contravariant(void);
@end example
-allow you to check the variance of a @code{varidx} object (use @code{ex_to_varidx()}
+allow you to check the variance of a @code{varidx} object (use @code{ex_to<varidx>()}
to get the object reference from an expression). There's also the very useful
method
@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).
+@code{ex_to<spinidx>()} to get the object reference from an expression).
Finally, the two methods
@example
@end example
@subsection Symmetries
+@cindex @code{symmetry} (class)
+@cindex @code{sy_none()}
+@cindex @code{sy_symm()}
+@cindex @code{sy_anti()}
+@cindex @code{sy_cycl()}
-Indexed objects can be declared as being totally symmetric or antisymmetric
-with respect to their indices. In this case, GiNaC will automatically bring
-the indices into a canonical order which allows for some immediate
-simplifications:
+Indexed objects can have certain symmetry properties with respect to their
+indices. Symmetries are specified as a tree of objects of class @code{symmetry}
+that is constructed with the helper functions
@example
+symmetry sy_none(...);
+symmetry sy_symm(...);
+symmetry sy_anti(...);
+symmetry sy_cycl(...);
+@end example
+
+@code{sy_none()} stands for no symmetry, @code{sy_symm()} and @code{sy_anti()}
+specify fully symmetric or antisymmetric, respectively, and @code{sy_cycl()}
+represents a cyclic symmetry. Each of these functions accepts up to four
+arguments which can be either symmetry objects themselves or unsigned integer
+numbers that represent an index position (counting from 0). A symmetry
+specification that consists of only a single @code{sy_symm()}, @code{sy_anti()}
+or @code{sy_cycl()} with no arguments specifies the respective symmetry for
+all indices.
+
+Here are some examples of symmetry definitions:
+
+@example
+ ...
+ // No symmetry:
+ e = indexed(A, i, j);
+ e = indexed(A, sy_none(), i, j); // equivalent
+ e = indexed(A, sy_none(0, 1), i, j); // equivalent
+
+ // Symmetric in all three indices:
+ e = indexed(A, sy_symm(), i, j, k);
+ e = indexed(A, sy_symm(0, 1, 2), i, j, k); // equivalent
+ e = indexed(A, sy_symm(2, 0, 1), i, j, k); // same symmetry, but yields a
+ // different canonical order
+
+ // Symmetric in the first two indices only:
+ e = indexed(A, sy_symm(0, 1), i, j, k);
+ e = indexed(A, sy_none(sy_symm(0, 1), 2), i, j, k); // equivalent
+
+ // Antisymmetric in the first and last index only (index ranges need not
+ // be contiguous):
+ e = indexed(A, sy_anti(0, 2), i, j, k);
+ e = indexed(A, sy_none(sy_anti(0, 2), 1), i, j, k); // equivalent
+
+ // An example of a mixed symmetry: antisymmetric in the first two and
+ // last two indices, symmetric when swapping the first and last index
+ // pairs (like the Riemann curvature tensor):
+ e = indexed(A, sy_symm(sy_anti(0, 1), sy_anti(2, 3)), i, j, k, l);
+
+ // Cyclic symmetry in all three indices:
+ e = indexed(A, sy_cycl(), i, j, k);
+ e = indexed(A, sy_cycl(0, 1, 2), i, j, k); // equivalent
+
+ // The following examples are invalid constructions that will throw
+ // an exception at run time.
+
+ // An index may not appear multiple times:
+ e = indexed(A, sy_symm(0, 0, 1), i, j, k); // ERROR
+ e = indexed(A, sy_none(sy_symm(0, 1), sy_anti(0, 2)), i, j, k); // ERROR
+
+ // Every child of sy_symm(), sy_anti() and sy_cycl() must refer to the
+ // same number of indices:
+ e = indexed(A, sy_symm(sy_anti(0, 1), 2), i, j, k); // ERROR
+
+ // And of course, you cannot specify indices which are not there:
+ e = indexed(A, sy_symm(0, 1, 2, 3), i, j, k); // ERROR
...
- cout << indexed(A, indexed::symmetric, i, j)
- + indexed(A, indexed::symmetric, j, i) << endl;
+@end example
+
+If you need to specify more than four indices, you have to use the
+@code{.add()} method of the @code{symmetry} class. For example, to specify
+full symmetry in the first six indices you would write
+@code{sy_symm(0, 1, 2, 3).add(4).add(5)}.
+
+If an indexed object has a symmetry, GiNaC will automatically bring the
+indices into a canonical order which allows for some immediate simplifications:
+
+@example
+ ...
+ cout << indexed(A, sy_symm(), i, j)
+ + indexed(A, sy_symm(), j, i) << endl;
// -> 2*A.j.i
- cout << indexed(B, indexed::antisymmetric, i, j)
- + indexed(B, indexed::antisymmetric, j, j) << endl;
+ cout << indexed(B, sy_anti(), i, j)
+ + indexed(B, sy_anti(), j, i) << endl;
// -> -B.j.i
- cout << indexed(B, indexed::antisymmetric, i, j)
- + indexed(B, indexed::antisymmetric, j, i) << endl;
+ cout << indexed(B, sy_anti(), i, j, k)
+ + indexed(B, sy_anti(), j, i, k) << endl;
// -> 0
...
@end example
@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
@subsubsection Delta tensor
The delta tensor takes two indices, is symmetric and has the matrix
-representation @code{diag(1,1,1,...)}. It is constructed by the function
+representation @code{diag(1, 1, 1, ...)}. It is constructed by the function
@code{delta_tensor()}:
@example
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
idx i(symbol("i"), 2), j(symbol("j"), 2);
symbol x("x"), y("y");
+ // A is a 2x2 matrix, X is a 2x1 vector
matrix A(2, 2, lst(1, 2, 3, 4)), X(2, 1, lst(x, y));
cout << indexed(A, i, i) << endl;
@end example
You can of course obtain the same results with the @code{matrix::add()},
-@code{matrix::mul()} and @code{matrix::trace()} methods but with indices you
-don't have to worry about transposing matrices.
+@code{matrix::mul()} and @code{matrix::trace()} methods (@pxref{Matrices})
+but with indices you don't have to worry about transposing matrices.
Matrix indices always start at 0 and their dimension must match the number
of rows/columns of the matrix. Matrices with one row or one column are
The @code{clifford} and @code{color} classes are subclasses of
@code{indexed} because the elements of these algebras ususally carry
-indices.
+indices. The @code{matrix} class is described in more detail in
+@ref{Matrices}.
Unlike most computer algebra systems, GiNaC does not primarily provide an
operator (often denoted @samp{&*}) for representing inert products of
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
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);
+ e = e.collect(lst(l, ldotq, m));
cout << e << endl;
// -> (8-4*D)*l^2+(8-4*D)*ldotq+4*D*m^2
@}
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);
* Information About Expressions::
* Substituting Expressions::
* Pattern Matching and Advanced Substitutions::
+* Applying a Function on Subexpressions::
* Polynomial Arithmetic:: Working with polynomials.
* Rational Expressions:: Working with rational functions.
* Symbolic Differentiation::
@section Getting information about expressions
@subsection Checking expression types
-@cindex @code{is_ex_of_type()}
-@cindex @code{ex_to_numeric()}
-@cindex @code{ex_to_@dots{}}
-@cindex @code{Converting ex to other classes}
+@cindex @code{is_a<@dots{}>()}
+@cindex @code{is_exactly_a<@dots{}>()}
+@cindex @code{ex_to<@dots{}>()}
+@cindex Converting @code{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 a couple of functions for this (the first one is actually a macro):
+GiNaC provides a couple of functions for this:
@example
-bool is_ex_of_type(const ex & e, TYPENAME t);
+bool is_a<T>(const ex & e);
+bool is_exactly_a<T>(const ex & e);
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
-call one of the functions @code{ex_to_@dots{}}, where @code{@dots{}} is
-one of the class names (@xref{The Class Hierarchy}, for a list of all
-classes). For example, assuming @code{e} is an @code{ex}:
+When the test made by @code{is_a<T>()} returns true, it is safe to call
+one of the functions @code{ex_to<T>()}, where @code{T} is one of the
+class names (@xref{The Class Hierarchy}, for a list of all classes). For
+example, assuming @code{e} is an @code{ex}:
@example
@{
@dots{}
- if (is_ex_of_type(e, numeric))
- numeric n = ex_to_numeric(e);
+ if (is_a<numeric>(e))
+ numeric n = ex_to<numeric>(e);
@dots{}
@}
@end example
-@code{is_ex_of_type()} allows you to check whether the top-level object of
-an expression @samp{e} is an instance of the GiNaC class @samp{t}
+@code{is_a<T>(e)} allows you to check whether the top-level object of
+an expression @samp{e} is an instance of the GiNaC class @samp{T}
(@xref{The Class Hierarchy}, for a list of all classes). This is most useful,
e.g., for checking whether an expression is a number, a sum, or a product:
symbol x("x");
ex e1 = 42;
ex e2 = 4*x - 3;
- is_ex_of_type(e1, numeric); // true
- is_ex_of_type(e2, numeric); // false
- is_ex_of_type(e1, add); // false
- is_ex_of_type(e2, add); // true
- is_ex_of_type(e1, mul); // false
- is_ex_of_type(e2, mul); // false
+ is_a<numeric>(e1); // true
+ is_a<numeric>(e2); // false
+ is_a<add>(e1); // false
+ is_a<add>(e2); // true
+ is_a<mul>(e1); // false
+ is_a<mul>(e2); // false
@}
@end example
+In contrast, @code{is_exactly_a<T>(e)} allows you to check whether the
+top-level object of an expression @samp{e} is an instance of the GiNaC
+class @samp{T}, not including parent classes.
+
The @code{info()} method is used for checking certain attributes of
expressions. The possible values for the @code{flag} argument are defined
in @file{ginac/flags.h}, the most important being explained in the following
@multitable @columnfractions .30 .70
@item @strong{Flag} @tab @strong{Returns true if the object is@dots{}}
@item @code{numeric}
-@tab @dots{}a number (same as @code{is_ex_of_type(..., numeric)})
+@tab @dots{}a number (same as @code{is_<numeric>(...)})
@item @code{real}
@tab @dots{}a real integer, rational or float (i.e. is not complex)
@item @code{rational}
@item @code{prime}
@tab @dots{}a prime integer (probabilistic primality test)
@item @code{relation}
-@tab @dots{}a relation (same as @code{is_ex_of_type(..., relational)})
+@tab @dots{}a relation (same as @code{is_a<relational>(...)})
@item @code{relation_equal}
@tab @dots{}a @code{==} relation
@item @code{relation_not_equal}
@item @code{relation_greater_or_equal}
@tab @dots{}a @code{>=} relation
@item @code{symbol}
-@tab @dots{}a symbol (same as @code{is_ex_of_type(..., symbol)})
+@tab @dots{}a symbol (same as @code{is_a<symbol>(...)})
@item @code{list}
-@tab @dots{}a list (same as @code{is_ex_of_type(..., lst)})
+@tab @dots{}a list (same as @code{is_a<lst>(...)})
@item @code{polynomial}
@tab @dots{}a polynomial (i.e. only consists of sums and products of numbers and symbols with positive integer powers)
@item @code{integer_polynomial}
@code{false}.
Actually, if you construct an expression like @code{a == b}, this will be
-represented by an object of the @code{relational} class (@xref{Relations}.)
+represented by an object of the @code{relational} class (@pxref{Relations})
which is not evaluated until (explicitly or implicitely) cast to a @code{bool}.
There are also two methods
next section.
-@node Pattern Matching and Advanced Substitutions, Polynomial Arithmetic, Substituting Expressions, Methods and Functions
+@node Pattern Matching and Advanced Substitutions, Applying a Function on Subexpressions, Substituting Expressions, Methods and Functions
@c node-name, next, previous, up
@section Pattern matching and advanced substitutions
+@cindex @code{wildcard} (class)
+@cindex Pattern matching
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
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
+are specified in @command{ginsh}). In C++ code, wildcard objects are created
with the call
@example
> 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.)
+ even though a==a^1.)
> match(x*atan2(x,x^2),$0*atan2($0,$0^2));
@{$0==x@}
> match(atan2(y,x^2),atan2(y,$0));
contains a linear term you should use the coeff() function instead.)
@end example
+@cindex @code{find()}
+The method
+
+@example
+bool ex::find(const ex & pattern, lst & found);
+@end example
+
+works a bit like @code{has()} but it doesn't stop upon finding the first
+match. Instead, it appends all found matches to the specified list. If there
+are multiple occurrences of the same expression, it is entered only once to
+the list. @code{find()} returns false if no matches were found (in
+@command{ginsh}, it returns an empty list):
+
+@example
+> find(1+x+x^2+x^3,x);
+@{x@}
+> find(1+x+x^2+x^3,y);
+@{@}
+> find(1+x+x^2+x^3,x^$1);
+@{x^3,x^2@}
+ (Note the absence of "x".)
+> expand((sin(x)+sin(y))*(a+b));
+sin(y)*a+sin(x)*b+sin(x)*a+sin(y)*b
+> find(",sin($1));
+@{sin(y),sin(x)@}
+@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
@end example
-@node Polynomial Arithmetic, Rational Expressions, Pattern Matching and Advanced Substitutions, Methods and Functions
+@node Applying a Function on Subexpressions, Polynomial Arithmetic, Pattern Matching and Advanced Substitutions, Methods and Functions
+@c node-name, next, previous, up
+@section Applying a Function on Subexpressions
+@cindex Tree traversal
+@cindex @code{map()}
+
+Sometimes you may want to perform an operation on specific parts of an
+expression while leaving the general structure of it intact. An example
+of this would be a matrix trace operation: the trace of a sum is the sum
+of the traces of the individual terms. That is, the trace should @dfn{map}
+on the sum, by applying itself to each of the sum's operands. It is possible
+to do this manually which usually results in code like this:
+
+@example
+ex calc_trace(ex e)
+@{
+ if (is_a<matrix>(e))
+ return ex_to<matrix>(e).trace();
+ else if (is_a<add>(e)) @{
+ ex sum = 0;
+ for (unsigned i=0; i<e.nops(); i++)
+ sum += calc_trace(e.op(i));
+ return sum;
+ @} else if (is_a<mul>)(e)) @{
+ ...
+ @} else @{
+ ...
+ @}
+@}
+@end example
+
+This is, however, slightly inefficient (if the sum is very large it can take
+a long time to add the terms one-by-one), and its applicability is limited to
+a rather small class of expressions. If @code{calc_trace()} is called with
+a relation or a list as its argument, you will probably want the trace to
+be taken on both sides of the relation or of all elements of the list.
+
+GiNaC offers the @code{map()} method to aid in the implementation of such
+operations:
+
+@example
+static ex ex::map(map_function & f) const;
+static ex ex::map(ex (*f)(const ex & e)) const;
+@end example
+
+In the first (preferred) form, @code{map()} takes a function object that
+is subclassed from the @code{map_function} class. In the second form, it
+takes a pointer to a function that accepts and returns an expression.
+@code{map()} constructs a new expression of the same type, applying the
+specified function on all subexpressions (in the sense of @code{op()}),
+non-recursively.
+
+The use of a function object makes it possible to supply more arguments to
+the function that is being mapped, or to keep local state information.
+The @code{map_function} class declares a virtual function call operator
+that you can overload. Here is a sample implementation of @code{calc_trace()}
+that uses @code{map()} in a recursive fashion:
+
+@example
+struct calc_trace : public map_function @{
+ ex operator()(const ex &e)
+ @{
+ if (is_a<matrix>(e))
+ return ex_to<matrix>(e).trace();
+ else if (is_a<mul>(e)) @{
+ ...
+ @} else
+ return e.map(*this);
+ @}
+@};
+@end example
+
+This function object could then be used like this:
+
+@example
+@{
+ ex M = ... // expression with matrices
+ calc_trace do_trace;
+ ex tr = do_trace(M);
+@}
+@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
+acts as the placeholder for the operands:
+
+@example
+> map(a*b,sin($0));
+sin(a)*sin(b)
+> map(a+2*b,sin($0));
+sin(a)+sin(2*b)
+> map(@{a,b,c@},$0^2+$0);
+@{a^2+a,b^2+b,c^2+c@}
+@end example
+
+Note that it is only possible to use algebraic functions in the second
+argument. You can not use functions like @samp{diff()}, @samp{op()},
+@samp{subs()} etc. because these are evaluated immediately:
+
+@example
+> map(@{a,b,c@},diff($0,a));
+@{0,0,0@}
+ This is because "diff($0,a)" evaluates to "0", so the command is equivalent
+ to "map(@{a,b,c@},0)".
+@end example
+
+
+@node Polynomial Arithmetic, Rational Expressions, Applying a Function on Subexpressions, Methods and Functions
@c node-name, next, previous, up
@section Polynomial arithmetic
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
-for @code{collect()} to be able to find the coefficients properly.
+Note that the original polynomial needs to be in expanded form (for the
+variables concerned) in order for @code{collect()} to be able to find the
+coefficients properly.
+
+The following @command{ginsh} transcript shows an application of @code{collect()}
+together with @code{find()}:
+
+@example
+> a=expand((sin(x)+sin(y))*(1+p+q)*(1+d));
+d*p*sin(x)+p*sin(x)+q*d*sin(x)+q*sin(y)+d*sin(x)+q*d*sin(y)+sin(y)+d*sin(y)+q*sin(x)+d*sin(y)*p+sin(x)+sin(y)*p
+> collect(a,@{p,q@});
+d*sin(x)+(d*sin(x)+sin(y)+d*sin(y)+sin(x))*p+(d*sin(x)+sin(y)+d*sin(y)+sin(x))*q+sin(y)+d*sin(y)+sin(x)
+> collect(a,find(a,sin($1)));
+(1+q+d+q*d+d*p+p)*sin(y)+(1+q+d+q*d+d*p+p)*sin(x)
+> collect(a,@{find(a,sin($1)),p,q@});
+(1+(1+d)*p+d+q*(1+d))*sin(x)+(1+(1+d)*p+d+q*(1+d))*sin(y)
+> collect(a,@{find(a,sin($1)),d@});
+(1+q+d*(1+q+p)+p)*sin(y)+(1+q+d*(1+q+p)+p)*sin(x)
+@end example
@subsection Degree and coefficients
@cindex @code{degree()}
@section Symmetrization
@cindex @code{symmetrize()}
@cindex @code{antisymmetrize()}
+@cindex @code{symmetrize_cyclic()}
-The two methods
+The three methods
@example
ex ex::symmetrize(const lst & l);
ex ex::antisymmetrize(const lst & l);
+ex ex::symmetrize_cyclic(const lst & l);
@end example
-symmetrize an expression by returning the symmetric or antisymmetric sum
-over all permutations of the specified list of objects, weighted by the
-number of permutations.
+symmetrize an expression by returning the sum over all symmetric,
+antisymmetric or cyclic permutations of the specified list of objects,
+weighted by the number of permutations.
-The two additional methods
+The three additional methods
@example
ex ex::symmetrize();
ex ex::antisymmetrize();
+ex ex::symmetrize_cyclic();
@end example
symmetrize or antisymmetrize an expression over its free indices.
// -> 1/2*A.j.i+1/2*A.i.j
cout << indexed(A, i, j, k).antisymmetrize(lst(i, j)) << endl;
// -> -1/2*A.j.i.k+1/2*A.i.j.k
- cout << lst(a, b, c).symmetrize(lst(a, b, c)) << endl;
- // -> 1/6*@{a,b,c@}+1/6*@{c,a,b@}+1/6*@{b,a,c@}+1/6*@{c,b,a@}+1/6*@{b,c,a@}+1/6*@{a,c,b@}
+ cout << lst(a, b, c).symmetrize_cyclic(lst(a, b, c)) << endl;
+ // -> 1/3*@{a,b,c@}+1/3*@{b,c,a@}+1/3*@{c,a,b@}
@}
@end example
@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
@{(-\ln(x))@}+@{(-\gamma_E)@} x+@{(1/12 \pi^2)@} x^@{2@}+\mathcal@{O@}(x^3)
@end example
+@cindex Tree traversal
If you need any fancy special output format, e.g. for interfacing GiNaC
with other algebra systems or for producing code for different
programming languages, you can always traverse the expression tree yourself:
@example
static void my_print(const ex & e)
@{
- if (is_ex_of_type(e, function))
- cout << ex_to_function(e).get_name();
+ if (is_a<function>(e))
+ cout << ex_to<function>(e).get_name();
else
cout << e.bp->class_name();
cout << "(";
switch (p[i].type) @{
case archive_node::PTYPE_BOOL: @{
bool x;
- n.find_bool(name, x);
+ n.find_bool(name, x, j);
cout << (x ? "true" : "false");
break;
@}
case archive_node::PTYPE_UNSIGNED: @{
unsigned x;
- n.find_unsigned(name, x);
+ n.find_unsigned(name, x, j);
cout << x;
break;
@}
case archive_node::PTYPE_STRING: @{
string x;
- n.find_string(name, x);
+ n.find_string(name, x, j);
cout << '\"' << x << '\"';
break;
@}
@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
string str;
@};
-GIANC_IMPLEMENT_REGISTERED_CLASS(mystring, basic)
+GINAC_IMPLEMENT_REGISTERED_CLASS(mystring, basic)
@end example
The @code{GINAC_DECLARE_REGISTERED_CLASS} and @code{GINAC_IMPLEMENT_REGISTERED_CLASS}
@example
ex e = mystring("Hello, world!");
-cout << is_ex_of_type(e, mystring) << endl;
+cout << is_a<mystring>(e) << endl;
// -> 1 (true)
cout << e.bp->class_name() << endl;
// -> "GiNaC rulez"+"Hello, world!"
@end example
-(note that GiNaC's automatic term reordering is in effect here), or even
+(GiNaC's automatic term reordering is in effect here), or even
@example
e = pow(mystring("One string"), 2*sin(Pi-mystring("Another string")));
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)
-@{
- return static_cast<const mystring &>(*e.bp);
-@}
-@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.
+You can, of course, also add your own new member functions. Remember,
+that the RTTI may be used to get information about what kinds of objects
+you are dealing with (the position in the class hierarchy) and that you
+can always extract the bare object from an @code{ex} by stripping the
+@code{ex} off using the @code{ex_to<mystring>(e)} function when that
+should become a need.
That's it. May the source be with you!
@item
development tools: powerful development tools exist for C++, like fancy
editors (e.g. with automatic indentation and syntax highlighting),
-debuggers, visualization tools, documentation generators...
+debuggers, visualization tools, documentation generators@dots{}
@item
modularization: C++ programs can easily be split into modules by
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