This is a tutorial that documents GiNaC @value{VERSION}, an open
framework for symbolic computation within the C++ programming language.
-Copyright (C) 1999-2008 Johannes Gutenberg University Mainz, Germany
+Copyright (C) 1999-2021 Johannes Gutenberg University Mainz, Germany
Permission is granted to make and distribute verbatim copies of
this manual provided the copyright notice and this permission notice
@title GiNaC @value{VERSION}
@subtitle An open framework for symbolic computation within the C++ programming language
@subtitle @value{UPDATED}
-@author @uref{http://www.ginac.de}
+@author @uref{https://www.ginac.de}
@page
@vskip 0pt plus 1filll
-Copyright @copyright{} 1999-2008 Johannes Gutenberg University Mainz, Germany
+Copyright @copyright{} 1999-2021 Johannes Gutenberg University Mainz, Germany
@sp 2
Permission is granted to make and distribute verbatim copies of
this manual provided the copyright notice and this permission notice
the development, the actual documentation is inside the sources in the
form of comments. That documentation may be parsed by one of the many
Javadoc-like documentation systems. If you fail at generating it you
-may access it from @uref{http://www.ginac.de/reference/, the GiNaC home
+may access it from @uref{https://www.ginac.de/reference/, the GiNaC home
page}. It is an invaluable resource not only for the advanced user who
wishes to extend the system (or chase bugs) but for everybody who wants
to comprehend the inner workings of GiNaC. This little tutorial on the
@section License
The GiNaC framework for symbolic computation within the C++ programming
-language is Copyright @copyright{} 1999-2008 Johannes Gutenberg
+language is Copyright @copyright{} 1999-2021 Johannes Gutenberg
University Mainz, Germany.
This program is free software; you can redistribute it and/or
and run it like this:
@example
-$ c++ hello.cc -o hello -lcln -lginac
+$ c++ hello.cc -o hello -lginac -lcln
$ ./hello
355687428096000*x*y+20922789888000*y^2+6402373705728000*x^2
@end example
@end example
Multivariate polynomials and rational functions may be expanded,
-collected and normalized (i.e. converted to a ratio of two coprime
-polynomials):
+collected, factorized, and normalized (i.e. converted to a ratio of
+two coprime polynomials):
@example
> a = x^4 + 2*x^2*y^2 + 4*x^3*y + 12*x*y^3 - 3*y^4;
4*x*y-y^2+x^2
> expand(a*b);
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
+> factor(%);
+(4*x*y+x^2-y^2)^2*(x^2+3*y^2)
> 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);
3*y^2+x^2
@end example
+Here we have made use of the @command{ginsh}-command @code{%} to pop the
+previously evaluated element from @command{ginsh}'s internal stack.
+
You can differentiate functions and expand them as Taylor or Laurent
series in a very natural syntax (the second argument of @code{series} is
a relation defining the evaluation point, the third specifies the
-Euler-1/12+Order((x-1/2*Pi)^3)
@end example
-Here we have made use of the @command{ginsh}-command @code{%} to pop the
-previously evaluated element from @command{ginsh}'s internal stack.
-
Often, functions don't have roots in closed form. Nevertheless, it's
quite easy to compute a solution numerically, to arbitrary precision:
In order to install GiNaC on your system, some prerequisites need to be
met. First of all, you need to have a C++-compiler adhering to the
-ANSI-standard @cite{ISO/IEC 14882:1998(E)}. We used GCC for development
+ISO standard @cite{ISO/IEC 14882:2011(E)}. We used GCC for development
so if you have a different compiler you are on your own. For the
configuration to succeed you need a Posix compliant shell installed in
@file{/bin/sh}, GNU @command{bash} is fine. The pkg-config utility is
@uref{http://pkg-config.freedesktop.org}.
Last but not least, the CLN library
is used extensively and needs to be installed on your system.
-Please get it from @uref{ftp://ftpthep.physik.uni-mainz.de/pub/gnu/}
-(it is covered by GPL) and install it prior to trying to install
-GiNaC. The configure script checks if it can find it and if it cannot
-it will refuse to continue.
+Please get it from @uref{https://www.ginac.de/CLN/} (it is licensed under
+the GPL) and install it prior to trying to install GiNaC. The configure
+script checks if it can find it and if it cannot, it will refuse to
+continue.
@node Configuration, Building GiNaC, Prerequisites, Installation
* Matrices:: Matrices.
* Indexed objects:: Handling indexed quantities.
* Non-commutative objects:: Algebras with non-commutative products.
-* Hash maps:: A faster alternative to std::map<>.
@end menu
Internally, the anonymous evaluator in GiNaC is implemented by the methods
@example
-ex ex::eval(int level = 0) const;
-ex basic::eval(int level = 0) const;
+ex ex::eval() const;
+ex basic::eval() const;
@end example
but unless you are extending GiNaC with your own classes or functions, there
as "@code{\Box}" in LaTeX code (@xref{Input/output}, for more
information about the different output formats of expressions in GiNaC).
GiNaC automatically creates proper LaTeX code for symbols having names of
-greek letters (@samp{alpha}, @samp{mu}, etc.).
+greek letters (@samp{alpha}, @samp{mu}, etc.). You can retrieve the name
+and the LaTeX name of a symbol using the respective methods:
+@cindex @code{get_name()}
+@cindex @code{get_TeX_name()}
+@example
+symbol::get_name() const;
+symbol::get_TeX_name() const;
+@end example
@cindex @code{subs()}
Symbols in GiNaC can't be assigned values. If you need to store results of
@tab modulus in positive representation (in the range @code{[0, abs(b)-1]} with the sign of b, or zero)
@cindex @code{mod()}
@item @code{smod(a, b)}
-@tab modulus in symmetric representation (in the range @code{[-iquo(abs(b)-1, 2), iquo(abs(b), 2)]})
+@tab modulus in symmetric representation (in the range @code{[-iquo(abs(b), 2), iquo(abs(b), 2)]})
@cindex @code{smod()}
@item @code{irem(a, b)}
@tab integer remainder (has the sign of @math{a}, or is zero)
@code{to_int()/to_long()} and @code{to_double()} discard the imaginary
part of complex numbers.
+Note the signature of the above methods, you may need to apply a type
+conversion and call @code{evalf()} as shown in the following example:
+@example
+ ...
+ ex e1 = 1, e2 = sin(Pi/5);
+ cout << ex_to<numeric>(e1).to_int() << endl
+ << ex_to<numeric>(e2.evalf()).to_double() << endl;
+ ...
+@end example
@node Constants, Fundamental containers, Numbers, Basic concepts
@c node-name, next, previous, up
the same type to GiNaC methods such as @code{subs()} and some @code{matrix}
constructors, so you should have a basic understanding of them.
-Lists can be constructed by assigning a comma-separated sequence of
-expressions:
+Lists can be constructed from an initializer list of expressions:
@example
@{
symbol x("x"), y("y");
- lst l;
- l = x, 2, y, x+y;
+ lst l = @{x, 2, y, x+y@};
// now, l is a list holding the expressions 'x', '2', 'y', and 'x+y',
// in that order
...
@end example
-There are also constructors that allow direct creation of lists of up to
-16 expressions, which is often more convenient but slightly less efficient:
-
-@example
- ...
- // This produces the same list 'l' as above:
- // lst l(x, 2, y, x+y);
- // lst l = lst(x, 2, y, x+y);
- ...
-@end example
-
Use the @code{nops()} method to determine the size (number of expressions) of
a list and the @code{op()} method or the @code{[]} operator to access
individual elements:
@example
...
- lst l1, l2;
- l1 = x, 2, y, x+y;
- l2 = 2, x+y, x, y;
+ lst l1 = @{x, 2, y, x+y@};
+ lst l2 = @{2, x+y, x, y@};
l1.sort();
l2.sort();
// l1 and l2 are now equal
@example
...
- lst l3;
- l3 = x, 2, 2, 2, y, x+y, y+x;
+ lst l3 = @{x, 2, 2, 2, y, x+y, y+x@};
l3.unique(); // l3 is now @{x, 2, y, x+y@}
@}
@end example
method, where the left hand side of the relation specifies the variable
to expand in and the right hand side the expansion point. They can also
be used for creating systems of equations that are to be solved for
-unknown variables. But the most common usage of objects of this class
+unknown variables.
+
+But the most common usage of objects of this class
is rather inconspicuous in statements of the form @code{if
(expand(pow(a+b,2))==a*a+2*a*b+b*b) @{...@}}. Here, an implicit
conversion from @code{relational} to @code{bool} takes place. Note,
however, that @code{==} here does not perform any simplifications, hence
@code{expand()} must be called explicitly.
+Simplifications of
+relationals may be more efficient if preceded by a call to
+@example
+ex relational::canonical() const
+@end example
+which returns an equivalent relation with the zero
+right-hand side. For example:
+@example
+possymbol p("p");
+relational rel = (p >= (p*p-1)/p);
+if (ex_to<relational>(rel.canonical().normal()))
+ cout << "correct inequality" << endl;
+@end example
+However, a user shall not expect that any inequality can be fully
+resolved by GiNaC.
+
@node Integrals, Matrices, Relations, Basic concepts
@c node-name, next, previous, up
@section Integrals
creates a matrix with @samp{r} rows and @samp{c} columns with all elements
set to zero.
-The fastest way to create a matrix with preinitialized elements is to assign
-a list of comma-separated expressions to an empty matrix (see below for an
-example). But you can also specify the elements as a (flat) list with
+The easiest way to create a matrix is using an initializer list of
+initializer lists, all of the same size:
+
+@example
+@{
+ matrix m = @{@{1, -a@},
+ @{a, 1@}@};
+@}
+@end example
+
+You can also specify the elements as a (flat) list with
@example
matrix::matrix(unsigned r, unsigned c, const lst & l);
@cindex @code{symbolic_matrix()}
@example
ex diag_matrix(const lst & l);
+ex diag_matrix(initializer_list<ex> l);
ex unit_matrix(unsigned x);
ex unit_matrix(unsigned r, unsigned c);
ex symbolic_matrix(unsigned r, unsigned c, const string & base_name);
const string & tex_base_name);
@end example
-@code{diag_matrix()} constructs a diagonal matrix given the list of diagonal
+@code{diag_matrix()} constructs a square diagonal matrix given the diagonal
elements. @code{unit_matrix()} creates an @samp{x} by @samp{x} (or @samp{r}
by @samp{c}) unit matrix. And finally, @code{symbolic_matrix} constructs a
matrix filled with newly generated symbols made of the specified base name
@example
@{
- matrix m(3,3);
- m = 11, 12, 13,
- 21, 22, 23,
- 31, 32, 33;
+ matrix m = @{@{11, 12, 13@},
+ @{21, 22, 23@},
+ @{31, 32, 33@}@};
cout << reduced_matrix(m, 1, 1) << endl;
// -> [[11,13],[31,33]]
cout << sub_matrix(m, 1, 2, 1, 2) << endl;
@{
symbol a("a"), b("b");
- matrix M(2, 2);
- M = a, 0,
- 0, b;
+ matrix M = @{@{a, 0@},
+ @{0, b@}@};
cout << M << endl;
// -> [[a,0],[0,b]]
cout << M2 << endl;
// -> [[a,0],[0,b]]
- cout << matrix(2, 2, lst(a, 0, 0, b)) << endl;
+ cout << matrix(2, 2, lst@{a, 0, 0, b@}) << endl;
// -> [[a,0],[0,b]]
- cout << lst_to_matrix(lst(lst(a, 0), lst(0, b))) << endl;
+ cout << lst_to_matrix(lst@{lst@{a, 0@}, lst@{0, b@}@}) << endl;
// -> [[a,0],[0,b]]
- cout << diag_matrix(lst(a, b)) << endl;
+ cout << diag_matrix(lst@{a, b@}) << endl;
// -> [[a,0],[0,b]]
cout << unit_matrix(3) << endl;
@example
@{
- matrix A(2, 2), B(2, 2), C(2, 2);
- A = 1, 2,
- 3, 4;
- B = -1, 0,
- 2, 1;
- C = 8, 4,
- 2, 1;
+ matrix A = @{@{ 1, 2@},
+ @{ 3, 4@}@};
+ matrix B = @{@{-1, 0@},
+ @{ 2, 1@}@};
+ matrix C = @{@{ 8, 4@},
+ @{ 2, 1@}@};
matrix result = A.mul(B).sub(C.mul_scalar(2));
cout << result << endl;
ex matrix::determinant(unsigned algo=determinant_algo::automatic) const;
ex matrix::trace() const;
ex matrix::charpoly(const ex & lambda) const;
-unsigned matrix::rank() const;
+unsigned matrix::rank(unsigned algo=solve_algo::automatic) const;
@end example
-The @samp{algo} argument of @code{determinant()} allows to select
-between different algorithms for calculating the determinant. The
-asymptotic speed (as parametrized by the matrix size) can greatly differ
-between those algorithms, depending on the nature of the matrix'
-entries. 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 (but not guaranteed) to give the result most
-quickly.
+The optional @samp{algo} argument of @code{determinant()} and @code{rank()}
+functions allows to select between different algorithms for calculating the
+determinant and rank respectively. The asymptotic speed (as parametrized
+by the matrix size) can greatly differ between those algorithms, depending
+on the nature of the matrix' entries. 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 (but not guaranteed)
+to give the result most quickly.
-@cindex @code{inverse()} (matrix)
@cindex @code{solve()}
-Matrices may also be inverted using the @code{ex matrix::inverse()}
-method and linear systems may be solved with:
+Linear systems can be solved with:
@example
matrix matrix::solve(const matrix & vars, const matrix & rhs,
contain some of the indeterminates from @code{vars}. If the system is
overdetermined, an exception is thrown.
+@cindex @code{inverse()} (matrix)
+To invert a matrix, use the method:
+
+@example
+matrix matrix::inverse(unsigned algo=solve_algo::automatic) const;
+@end example
+
+The @samp{algo} argument is optional. If given, it must be one of
+@code{solve_algo} defined in @file{flags.h}.
@node Indexed objects, Non-commutative objects, Matrices, Basic concepts
@c node-name, next, previous, up
symbol x("x"), y("y");
// A is a 2x2 matrix, X is a 2x1 vector
- matrix A(2, 2), X(2, 1);
- A = 1, 2,
- 3, 4;
- X = x, y;
+ matrix A = @{@{1, 2@},
+ @{3, 4@}@};
+ matrix X = @{@{x, y@}@};
cout << indexed(A, i, i) << endl;
// -> 5
of the metric tensor.
-@node Non-commutative objects, Hash maps, Indexed objects, Basic concepts
+@node Non-commutative objects, Methods and functions, Indexed objects, Basic concepts
@c node-name, next, previous, up
@section Non-commutative objects
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. Both
symbols and user-defined functions can be specified as being non-commutative.
+For symbols, this is done by subclassing class symbol; for functions,
+by explicitly setting the return type (@pxref{Symbolic functions}).
@cindex @code{return_type()}
@cindex @code{return_type_tinfo()}
obtained with the two member functions
@example
-unsigned ex::return_type() const;
-unsigned ex::return_type_tinfo() const;
+unsigned ex::return_type() const;
+return_type_t ex::return_type_tinfo() const;
@end example
The @code{return_type()} function returns one of three values (defined in
@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, but may vary every time a
-GiNaC program is being run (it is dynamically assigned on start-up).
+The @code{return_type_tinfo()} method returns an object of type
+@code{return_type_t} that contains information about the type of the expression
+and, if given, its representation label (see section on dirac gamma matrices for
+more details). The objects of type @code{return_type_t} can be tested for
+equality to test whether two expressions belong to the same category and
+therefore may not commute.
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 -
+@multitable @columnfractions .6 .4
+@item @strong{Expression} @tab @strong{@code{return_type()}}
+@item @code{42} @tab @code{commutative}
+@item @code{2*x-y} @tab @code{commutative}
+@item @code{dirac_ONE()} @tab @code{noncommutative}
+@item @code{dirac_gamma(mu)*dirac_gamma(nu)} @tab @code{noncommutative}
+@item @code{2*color_T(a)} @tab @code{noncommutative}
+@item @code{dirac_ONE()*color_T(a)} @tab @code{noncommutative_composite}
@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.
-
A last note: With the exception of matrices, positive integer powers of
non-commutative objects are automatically expanded in GiNaC. For example,
@code{pow(a*b, 2)} becomes @samp{a*b*a*b} if @samp{a} and @samp{b} are
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));
+ e = e.collect(lst@{l, ldotq, m@});
cout << e << endl;
// -> (8-4*D)*l^2+(8-4*D)*ldotq+4*D*m^2
@}
Note that the call @code{clifford_unit(mu, minkmetric())} creates
something very close to @code{dirac_gamma(mu)}, although
@code{dirac_gamma} have more efficient simplification mechanism.
-@cindex @code{clifford::get_metric()}
+@cindex @code{get_metric()}
+Also, the object created by @code{clifford_unit(mu, minkmetric())} is
+not aware about the symmetry of its metric, see the start of the previous
+paragraph. A more accurate analog of 'dirac_gamma(mu)' should be
+specifies as follows:
+
+@example
+ clifford_unit(mu, indexed(minkmetric(),sy_symm(),varidx(symbol("i"),4),varidx(symbol("j"),4)));
+@end example
+
The method @code{clifford::get_metric()} returns a metric defining this
Clifford number.
...
idx i(symbol("i"), 4);
realsymbol s("s");
- ex M = diag_matrix(lst(1, -1, 0, s));
+ ex M = diag_matrix(lst@{1, -1, 0, s@});
ex e = clifford_unit(i, M);
ex e0 = e.subs(i == 0);
ex e1 = e.subs(i == 1);
...
idx i(symbol("i"), 4);
realsymbol s("s");
- ex M = diag_matrix(lst(1, -1, 0, s));
- ex e0 = lst_to_clifford(lst(1, 0, 0, 0), i, M);
- ex e1 = lst_to_clifford(lst(0, 1, 0, 0), i, M);
- ex e2 = lst_to_clifford(lst(0, 0, 1, 0), i, M);
- ex e3 = lst_to_clifford(lst(0, 0, 0, 1), i, M);
+ ex M = diag_matrix(@{1, -1, 0, s@});
+ ex e0 = lst_to_clifford(lst@{1, 0, 0, 0@}, i, M);
+ ex e1 = lst_to_clifford(lst@{0, 1, 0, 0@}, i, M);
+ ex e2 = lst_to_clifford(lst@{0, 0, 1, 0@}, i, M);
+ ex e3 = lst_to_clifford(lst@{0, 0, 0, 1@}, i, M);
...
@}
@end example
@example
ex clifford_prime(const ex & e)
- inline ex clifford_star(const ex & e) @{ return e.conjugate(); @}
- inline ex clifford_bar(const ex & e) @{ return clifford_prime(e.conjugate()); @}
+ inline ex clifford_star(const ex & e)
+ inline ex clifford_bar(const ex & e)
@end example
The automorphism of a Clifford algebra @code{clifford_prime()} simply
changes signs of all Clifford units in the expression. The reversion
-of a Clifford algebra @code{clifford_star()} coincides with the
-@code{conjugate()} method and effectively reverses the order of Clifford
+of a Clifford algebra @code{clifford_star()} reverses the order of Clifford
units in any product. Finally the main anti-automorphism
of a Clifford algebra @code{clifford_bar()} is the composition of the
previous two, i.e. it makes the reversion and changes signs of all Clifford units
@end example
-@node Hash maps, Methods and functions, Non-commutative objects, Basic concepts
-@c node-name, next, previous, up
-@section Hash Maps
-@cindex hash maps
-@cindex @code{exhashmap} (class)
-
-For your convenience, GiNaC offers the container template @code{exhashmap<T>}
-that can be used as a drop-in replacement for the STL
-@code{std::map<ex, T, ex_is_less>}, using hash tables to provide faster,
-typically constant-time, element look-up than @code{map<>}.
-
-@code{exhashmap<>} supports all @code{map<>} members and operations, with the
-following differences:
-
-@itemize @bullet
-@item
-no @code{lower_bound()} and @code{upper_bound()} methods
-@item
-no reverse iterators, no @code{rbegin()}/@code{rend()}
-@item
-no @code{operator<(exhashmap, exhashmap)}
-@item
-the comparison function object @code{key_compare} is hardcoded to
-@code{ex_is_less}
-@item
-the constructor @code{exhashmap(size_t n)} allows specifying the minimum
-initial hash table size (the actual table size after construction may be
-larger than the specified value)
-@item
-the method @code{size_t bucket_count()} returns the current size of the hash
-table
-@item
-@code{insert()} and @code{erase()} operations invalidate all iterators
-@end itemize
-
-
-@node Methods and functions, Information about expressions, Hash maps, Top
+@node Methods and functions, Information about expressions, Non-commutative objects, Top
@c node-name, next, previous, up
@chapter Methods and functions
@cindex polynomial
* Symmetrization::
* Built-in functions:: List of predefined mathematical functions.
* Multiple polylogarithms::
+* Iterated integrals::
* Complex expressions::
* Solving linear systems of equations::
* Input/output:: Input and output of expressions.
bool is_exactly_a<T>(const ex & e);
bool ex::info(unsigned flag);
unsigned ex::return_type() const;
-unsigned ex::return_type_tinfo() const;
+return_type_t ex::return_type_tinfo() const;
@end example
When the test made by @code{is_a<T>()} returns true, it is safe to call
@tab @dots{}a polynomial with (possibly complex) rational coefficients (such as @math{2/3+7/2*I})
@item @code{rational_function}
@tab @dots{}a rational function (@math{x+y}, @math{z/(x+y)})
-@item @code{algebraic}
-@tab @dots{}an algebraic object (@math{sqrt(2)}, @math{sqrt(x)-1})
@end multitable
@end cartouche
@example
@{
symbol A("A"), B("B"), C("C");
- ex e = lst(lst(A, B), C);
+ ex e = lst@{lst@{A, B@}, C@};
std::copy(e.begin(), e.end(),
std::ostream_iterator<ex>(cout, "\n"));
predicates to the STL:
@example
-class ex_is_less : public std::binary_function<ex, ex, bool> @{
+class ex_is_less @{
public:
bool operator()(const ex &lh, const ex &rh) const;
@};
-class ex_is_equal : public std::binary_function<ex, ex, bool> @{
+class ex_is_equal @{
public:
bool operator()(const ex &lh, const ex &rh) const;
@};
// count the number of expressions equal to '1'
unsigned num_ones = std::count_if(v.begin(), v.end(),
- std::bind2nd(ex_is_equal(), 1));
+ [](const ex& e) @{ return ex_is_equal()(e, 1); @});
@end example
The implementation of @code{ex_is_less} uses the member function
To evaluate them using floating-point arithmetic you need to call
@example
-ex ex::evalf(int level = 0) const;
+ex ex::evalf() const;
@end example
@cindex @code{Digits}
@{
symbol x("x"), y("y");
- ex e1 = 2*x^2-4*x+3;
+ ex e1 = 2*x*x-4*x+3;
cout << "e1(7) = " << e1.subs(x == 7) << endl;
// -> 73
ex e2 = x*y + x;
- cout << "e2(-2, 4) = " << e2.subs(lst(x == -2, y == 4)) << endl;
+ cout << "e2(-2, 4) = " << e2.subs(lst@{x == -2, y == 4@}) << endl;
// -> -10
@}
@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}.
+@code{subs(lst@{x == y, y == x@})} exchanges @samp{x} and @samp{y}.
The second form of @code{subs()} takes an @code{exmap} object which is a
pair associative container that maps expressions to expressions (currently
symbol x("x"), y("y");
ex e2 = x*y + x;
- cout << "e2(-2, 4) = " << e2.subs(lst(x, y), lst(-2, 4)) << endl;
+ cout << "e2(-2, 4) = " << e2.subs(lst@{x, y@}, lst@{-2, 4@}) << endl;
@}
@end example
@code{(x^(-3)*y^(-2)*z).subs(1/(x*y)==c, subs_options::algebraic)} will
return @code{x^(-1)*c^2*z}.
-@strong{Note:} this only works for multiplications
+@strong{Please notice:} this only works for multiplications
and not for locating @code{x+y} within @code{x+y+z}.
One solution to this dilemma is the @dfn{Visitor} design pattern,
which is implemented in GiNaC (actually, Robert Martin's Acyclic Visitor
variation, described in detail in
-@uref{http://objectmentor.com/publications/acv.pdf}). Instead of adding
+@uref{https://condor.depaul.edu/dmumaugh/OOT/Design-Principles/acv.pdf}). Instead of adding
virtual functions to the class hierarchy to implement operations, GiNaC
provides a single "bouncing" method @code{accept()} that takes an instance
of a special @code{visitor} class and redirects execution to the one
@example
(x*y*sin(y)).is_polynomial(x) // Returns true.
-(x*y*sin(y)).is_polynomial(lst(x,y)) // Returns false.
+(x*y*sin(y)).is_polynomial(lst@{x,y@}) // Returns false.
@end example
@subsection Expanding and collecting
@cindex @code{ldegree()}
@cindex @code{coeff()}
-The degree and low degree of a polynomial can be obtained using the two
-methods
+The degree and low degree of a polynomial in expanded form can be obtained
+using the two methods
@example
int ex::degree(const ex & s);
int ex::ldegree(const ex & s);
@end example
-which also work reliably on non-expanded input polynomials (they even work
-on rational functions, returning the asymptotic degree). By definition, the
-degree of zero is zero. To extract a coefficient with a certain power from
-an expanded polynomial you use
+These functions even work on rational functions, returning the asymptotic
+degree. By definition, the degree of zero is zero. To extract a coefficient
+with a certain power from an expanded polynomial you use
@example
ex ex::coeff(const ex & s, int n);
@cindex factorization
@cindex @code{sqrfree()}
-GiNaC still lacks proper factorization support. Some form of
-factorization is, however, easily implemented by noting that factors
-appearing in a polynomial with power two or more also appear in the
-derivative and hence can easily be found by computing the GCD of the
-original polynomial and its derivatives. Any decent system has an
-interface for this so called square-free factorization. So we provide
-one, too:
+Square-free decomposition is available in GiNaC:
@example
-ex sqrfree(const ex & a, const lst & l = lst());
+ex sqrfree(const ex & a, const lst & l = lst@{@});
@end example
Here is an example that by the way illustrates how the exact form of the
result may slightly depend on the order of differentiation, calling for
symbol x("x"), y("y");
ex BiVarPol = expand(pow(2-2*y,3) * pow(1+x*y,2) * pow(x-2*y,2) * (x+y));
- cout << sqrfree(BiVarPol, lst(x,y)) << endl;
+ cout << sqrfree(BiVarPol, lst@{x,y@}) << endl;
// -> 8*(1-y)^3*(y*x^2-2*y+x*(1-2*y^2))^2*(y+x)
- cout << sqrfree(BiVarPol, lst(y,x)) << endl;
+ cout << sqrfree(BiVarPol, lst@{y,x@}) << endl;
// -> 8*(1-y)^3*(-y*x^2+2*y+x*(-1+2*y^2))^2*(y+x)
cout << sqrfree(BiVarPol) << endl;
Note also, how factors with the same exponents are not fully factorized
with this method.
+@subsection Polynomial factorization
+@cindex factorization
+@cindex polynomial factorization
+@cindex @code{factor()}
+
+Polynomials can also be fully factored with a call to the function
+@example
+ex factor(const ex & a, unsigned int options = 0);
+@end example
+The factorization works for univariate and multivariate polynomials with
+rational coefficients. The following code snippet shows its capabilities:
+@example
+ ...
+ cout << factor(pow(x,2)-1) << endl;
+ // -> (1+x)*(-1+x)
+ cout << factor(expand((x-y*z)*(x-pow(y,2)-pow(z,3))*(x+y+z))) << endl;
+ // -> (y+z+x)*(y*z-x)*(y^2-x+z^3)
+ cout << factor(pow(x,2)-1+sin(pow(x,2)-1)) << endl;
+ // -> -1+sin(-1+x^2)+x^2
+ ...
+@end example
+The results are as expected except for the last one where no factorization
+seems to have been done. This is due to the default option
+@command{factor_options::polynomial} (equals zero) to @command{factor()}, which
+tells GiNaC to try a factorization only if the expression is a valid polynomial.
+In the shown example this is not the case, because one term is a function.
+
+There exists a second option @command{factor_options::all}, which tells GiNaC to
+ignore non-polynomial parts of an expression and also to look inside function
+arguments. With this option the example gives:
+@example
+ ...
+ cout << factor(pow(x,2)-1+sin(pow(x,2)-1), factor_options::all)
+ << endl;
+ // -> (-1+x)*(1+x)+sin((-1+x)*(1+x))
+ ...
+@end example
+GiNaC's factorization functions cannot handle algebraic extensions. Therefore
+the following example does not factor:
+@example
+ ...
+ cout << factor(pow(x,2)-2) << endl;
+ // -> -2+x^2 and not (x-sqrt(2))*(x+sqrt(2))
+ ...
+@end example
+Factorization is useful in many applications. A lot of algorithms in computer
+algebra depend on the ability to factor a polynomial. Of course, factorization
+can also be used to simplify expressions, but it is costly and applying it to
+complicated expressions (high degrees or many terms) may consume far too much
+time. So usually, looking for a GCD at strategic points in a calculation is the
+cheaper and more appropriate alternative.
@node Rational expressions, Symbolic differentiation, Polynomial arithmetic, Methods and functions
@c node-name, next, previous, up
These functions will first normalize the expression as described above and
then return the numerator, denominator, or both as a list, respectively.
-If you need both numerator and denominator, calling @code{numer_denom()} is
-faster than using @code{numer()} and @code{denom()} separately.
+If you need both numerator and denominator, call @code{numer_denom()}: it
+is faster than using @code{numer()} and @code{denom()} separately. And even
+more important: a separate evaluation of @code{numer()} and @code{denom()}
+may result in a spurious sign, e.g. for $x/(x^2-1)$ @code{numer()} may
+return $x$ and @code{denom()} $1-x^2$.
@subsection Converting to a polynomial or rational expression
@example
ex ex::to_polynomial(exmap & m);
-ex ex::to_polynomial(lst & l);
@end example
or
@example
ex ex::to_rational(exmap & m);
-ex ex::to_rational(lst & l);
@end example
-on the expression to be converted. The supplied @code{exmap} or @code{lst}
-will be filled with the generated temporary symbols and their replacement
-expressions in a format that can be used directly for the @code{subs()}
-method. It can also already contain a list of replacements from an earlier
-application of @code{.to_polynomial()} or @code{.to_rational()}, so it's
-possible to use it on multiple expressions and get consistent results.
+on the expression to be converted. The supplied @code{exmap} will be filled
+with the generated temporary symbols and their replacement expressions in a
+format that can be used directly for the @code{subs()} method. It can also
+already contain a list of replacements from an earlier application of
+@code{.to_polynomial()} or @code{.to_rational()}, so it's possible to use
+it on multiple expressions and get consistent results.
The difference between @code{.to_polynomial()} and @code{.to_rational()}
is probably best illustrated with an example:
ex a = 2*x/sin(x) - y/(3*sin(x));
cout << a << endl;
- lst lp;
- ex p = a.to_polynomial(lp);
- cout << " = " << p << "\n with " << lp << endl;
+ exmap mp;
+ ex p = a.to_polynomial(mp);
+ cout << " = " << p << "\n with " << mp << endl;
// = symbol3*symbol2*y+2*symbol2*x
// with @{symbol2==sin(x)^(-1),symbol3==-1/3@}
- lst lr;
- ex r = a.to_rational(lr);
- cout << " = " << r << "\n with " << lr << endl;
+ exmap mr;
+ ex r = a.to_rational(mr);
+ cout << " = " << r << "\n with " << mr << endl;
// = -1/3*symbol4^(-1)*y+2*symbol4^(-1)*x
// with @{symbol4==sin(x)@}
@}
idx i(symbol("i"), 3), j(symbol("j"), 3), k(symbol("k"), 3);
symbol A("A"), B("B"), a("a"), b("b"), c("c");
- cout << indexed(A, i, j).symmetrize() << endl;
+ cout << ex(indexed(A, i, j)).symmetrize() << endl;
// -> 1/2*A.j.i+1/2*A.i.j
- cout << indexed(A, i, j, k).antisymmetrize(lst(i, j)) << endl;
+ cout << ex(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_cyclic(lst(a, b, c)) << endl;
+ cout << ex(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{log(x)}
@tab natural logarithm
@cindex @code{log()}
+@item @code{eta(x,y)}
+@tab Eta function: @code{eta(x,y) = log(x*y) - log(x) - log(y)}
+@cindex @code{eta()}
@item @code{Li2(x)}
@tab dilogarithm
@cindex @code{Li2()}
@cindex @code{zeta()}
@item @code{zetaderiv(n, x)}
@tab derivatives of Riemann's zeta function
+@item @code{iterated_integral(a, y)}
+@tab iterated integral
+@cindex @code{iterated_integral()}
+@item @code{iterated_integral(a, y, N)}
+@tab iterated integral with explicit truncation parameter
+@cindex @code{iterated_integral()}
@item @code{tgamma(x)}
@tab gamma function
@cindex @code{tgamma()}
@cindex @code{psi()}
@item @code{psi(n, x)}
@tab derivatives of psi function (polygamma functions)
+@item @code{EllipticK(x)}
+@tab complete elliptic integral of the first kind
+@cindex @code{EllipticK()}
+@item @code{EllipticE(x)}
+@tab complete elliptic integral of the second kind
+@cindex @code{EllipticE()}
@item @code{factorial(n)}
@tab factorial function @math{n!}
@cindex @code{factorial()}
@end cartouche
@cindex branch cut
-For functions that have a branch cut in the complex plane GiNaC follows
-the conventions for C++ as defined in the ANSI standard as far as
-possible. In particular: the natural logarithm (@code{log}) and the
-square root (@code{sqrt}) both have their branch cuts running along the
-negative real axis where the points on the axis itself belong to the
-upper part (i.e. continuous with quadrant II). The inverse
-trigonometric and hyperbolic functions are not defined for complex
-arguments by the C++ standard, however. In GiNaC we follow the
-conventions used by CLN, which in turn follow the carefully designed
-definitions in the Common Lisp standard. It should be noted that this
-convention is identical to the one used by the C99 standard and by most
-serious CAS. It is to be expected that future revisions of the C++
-standard incorporate these functions in the complex domain in a manner
-compatible with C99.
-
-@node Multiple polylogarithms, Complex expressions, Built-in functions, Methods and functions
+For functions that have a branch cut in the complex plane, GiNaC
+follows the conventions of C/C++ for systems that do not support a
+signed zero. In particular: the natural logarithm (@code{log}) and
+the square root (@code{sqrt}) both have their branch cuts running
+along the negative real axis. The @code{asin}, @code{acos}, and
+@code{atanh} functions all have two branch cuts starting at +/-1 and
+running away towards infinity along the real axis. The @code{atan} and
+@code{asinh} functions have two branch cuts starting at +/-i and
+running away towards infinity along the imaginary axis. The
+@code{acosh} function has one branch cut starting at +1 and running
+towards -infinity. These functions are continuous as the branch cut
+is approached coming around the finite endpoint of the cut in a
+counter clockwise direction.
+
+@c
+@subsection Expanding functions
+@cindex expand trancedent functions
+@cindex @code{expand_options::expand_transcendental}
+@cindex @code{expand_options::expand_function_args}
+GiNaC knows several expansion laws for trancedent functions, e.g.
+@tex
+$e^{a+b}=e^a e^b$,
+$|zw|=|z|\cdot |w|$
+@end tex
+@ifnottex
+@command{exp(a+b)=exp(a) exp(b), |zw|=|z| |w|}
+@end ifnottex
+or
+@tex
+$\log(c*d)=\log(c)+\log(d)$,
+@end tex
+@ifnottex
+@command{log(cd)=log(c)+log(d)}
+@end ifnottex
+(for positive
+@tex
+$c,\ d$
+@end tex
+@ifnottex
+@command{c, d}
+@end ifnottex
+). In order to use these rules you need to call @code{expand()} method
+with the option @code{expand_options::expand_transcendental}. Another
+relevant option is @code{expand_options::expand_function_args}. Their
+usage and interaction can be seen from the following example:
+@example
+@{
+ symbol x("x"), y("y");
+ ex e=exp(pow(x+y,2));
+ cout << e.expand() << endl;
+ // -> exp((x+y)^2)
+ cout << e.expand(expand_options::expand_transcendental) << endl;
+ // -> exp((x+y)^2)
+ cout << e.expand(expand_options::expand_function_args) << endl;
+ // -> exp(2*x*y+x^2+y^2)
+ cout << e.expand(expand_options::expand_function_args
+ | expand_options::expand_transcendental) << endl;
+ // -> exp(y^2)*exp(2*x*y)*exp(x^2)
+@}
+@end example
+If both flags are set (as in the last call), then GiNaC tries to get
+the maximal expansion. For example, for the exponent GiNaC firstly expands
+the argument and then the function. For the logarithm and absolute value,
+GiNaC uses the opposite order: firstly expands the function and then its
+argument. Of course, a user can fine-tune this behavior by sequential
+calls of several @code{expand()} methods with desired flags.
+
+@node Multiple polylogarithms, Iterated integrals, Built-in functions, Methods and functions
@c node-name, next, previous, up
@subsection Multiple polylogarithms
The multiple polylogarithm is the most generic member of a family of functions,
to which others like the harmonic polylogarithm, Nielsen's generalized
polylogarithm and the multiple zeta value belong.
-Everyone of these functions can also be written as a multiple polylogarithm with specific
+Each of these functions can also be written as a multiple polylogarithm with specific
parameters. This whole family of functions is therefore often referred to simply as
multiple polylogarithms, containing @code{Li}, @code{G}, @code{H}, @code{S} and @code{zeta}.
The multiple polylogarithm itself comes in two variants: @code{Li} and @code{G}. While
will be interpreted as the sequence of signs for the corresponding indices
@code{m} or the sign of the imaginary part for the
corresponding arguments @code{a}, it must contain 1 or -1, e.g.
-@code{zeta(lst(3,4), lst(-1,1))} means
+@code{zeta(lst@{3,4@}, lst@{-1,1@})} means
@tex
$\zeta(\overline{3},4)$
@end tex
@command{zeta(\overline@{3@},4)}
@end ifnottex
and
-@code{G(lst(a,b), lst(-1,1), c)} means
+@code{G(lst@{a,b@}, lst@{-1,1@}, c)} means
@tex
$G(a-0\epsilon,b+0\epsilon;c)$.
@end tex
@end ifnottex
The definition of @code{H} allows indices to be 0, 1 or -1 (in expanded notation) or equally to
be any integer (in compact notation). With GiNaC expanded and compact notation can be mixed,
-e.g. @code{lst(0,0,-1,0,1,0,0)}, @code{lst(0,0,-1,2,0,0)} and @code{lst(-3,2,0,0)} are equivalent as
+e.g. @code{lst@{0,0,-1,0,1,0,0@}}, @code{lst@{0,0,-1,2,0,0@}} and @code{lst@{-3,2,0,0@}} are equivalent as
indices. The anonymous evaluator @code{eval()} tries to reduce the functions, if possible, to
the least-generic multiple polylogarithm. If all arguments are unit, it returns @code{zeta}.
Arguments equal to zero get considered, too. Riemann's zeta function @code{zeta} (with depth one)
@cite{Numerical Evaluation of Multiple Polylogarithms},
J.Vollinga, S.Weinzierl, hep-ph/0410259
-@node Complex expressions, Solving linear systems of equations, Multiple polylogarithms, Methods and functions
+@node Iterated integrals, Complex expressions, Multiple polylogarithms, Methods and functions
+@c node-name, next, previous, up
+@subsection Iterated integrals
+
+Multiple polylogarithms are a particular example of iterated integrals.
+An iterated integral is defined by the function @code{iterated_integral(a,y)}.
+The variable @code{y} gives the upper integration limit for the outermost integration, by convention the lower integration limit is always set to zero.
+The variable @code{a} must be a GiNaC @code{lst} containing sub-classes of @code{integration_kernel} as elements.
+The depth of the iterated integral corresponds to the number of elements of @code{a}.
+The available integrands for iterated integrals are
+(for a more detailed description the user is referred to the publications listed at the end of this section)
+@cartouche
+@multitable @columnfractions .40 .60
+@item @strong{Class} @tab @strong{Description}
+@item @code{integration_kernel()}
+@tab Base class, represents the one-form @math{dy}
+@cindex @code{integration_kernel()}
+@item @code{basic_log_kernel()}
+@tab Logarithmic one-form @math{dy/y}
+@cindex @code{basic_log_kernel()}
+@item @code{multiple_polylog_kernel(z_j)}
+@tab The one-form @math{dy/(y-z_j)}
+@cindex @code{multiple_polylog_kernel()}
+@item @code{ELi_kernel(n, m, x, y)}
+@tab The one form @math{ELi_{n;m}(x;y;q) dq/q}
+@cindex @code{ELi_kernel()}
+@item @code{Ebar_kernel(n, m, x, y)}
+@tab The one form @math{\overline{E}_{n;m}(x;y;q) dq/q}
+@cindex @code{Ebar_kernel()}
+@item @code{Kronecker_dtau_kernel(k, z_j, K, C_k)}
+@tab The one form @math{C_k K (k-1)/(2 \pi i)^k g^{(k)}(z_j,K \tau) dq/q}
+@cindex @code{Kronecker_dtau_kernel()}
+@item @code{Kronecker_dz_kernel(k, z_j, tau, K, C_k)}
+@tab The one form @math{C_k (2 \pi i)^{2-k} g^{(k-1)}(z-z_j,K \tau) dz}
+@cindex @code{Kronecker_dz_kernel()}
+@item @code{Eisenstein_kernel(k, N, a, b, K, C_k)}
+@tab The one form @math{C_k E_{k,N,a,b,K}(\tau) dq/q}
+@cindex @code{Eisenstein_kernel()}
+@item @code{Eisenstein_h_kernel(k, N, r, s, C_k)}
+@tab The one form @math{C_k h_{k,N,r,s}(\tau) dq/q}
+@cindex @code{Eisenstein_h_kernel()}
+@item @code{modular_form_kernel(k, P, C_k)}
+@tab The one form @math{C_k P dq/q}
+@cindex @code{modular_form_kernel()}
+@item @code{user_defined_kernel(f, y)}
+@tab The one form @math{f(y) dy}
+@cindex @code{user_defined_kernel()}
+@end multitable
+@end cartouche
+All parameters are assumed to be such that all integration kernels have a convergent Laurent expansion
+around zero with at most a simple pole at zero.
+The iterated integral may also be called with an optional third parameter
+@code{iterated_integral(a,y,N_trunc)}, in which case the numerical evaluation will truncate the series
+expansion at order @code{N_trunc}.
+
+The classes @code{Eisenstein_kernel()}, @code{Eisenstein_h_kernel()} and @code{modular_form_kernel()}
+provide a method @code{q_expansion_modular_form(q, order)}, which can used to obtain the q-expansion
+of @math{E_{k,N,a,b,K}(\tau)}, @math{h_{k,N,r,s}(\tau)} or @math{P} to the specified order.
+
+Useful publications:
+
+@cite{Numerical evaluation of iterated integrals related to elliptic Feynman integrals},
+M.Walden, S.Weinzierl, arXiv:2010.05271
+
+@node Complex expressions, Solving linear systems of equations, Iterated integrals, Methods and functions
@c node-name, next, previous, up
@section Complex expressions
@c
@}
@end example
-If you declare your own GiNaC functions, then they will conjugate themselves
-by conjugating their arguments. This is the default strategy. If you want to
-change this behavior, you have to supply a specialized conjugation method
-for your function (see @ref{Symbolic functions} and the GiNaC source-code
-for @code{abs} as an example). Also, specialized methods can be provided
-to take real and imaginary parts of user-defined functions.
+If you declare your own GiNaC functions and you want to conjugate them, you
+will have to supply a specialized conjugation method for them (see
+@ref{Symbolic functions} and the GiNaC source-code for @code{abs} as an
+example). GiNaC does not automatically conjugate user-supplied functions
+by conjugating their arguments because this would be incorrect on branch
+cuts. Also, specialized methods can be provided to take real and imaginary
+parts of user-defined functions.
@node Solving linear systems of equations, Input/output, Complex expressions, Methods and functions
@c node-name, next, previous, up
@example
@{
symbol a("a"), b("b"), x("x"), y("y");
- lst eqns, vars;
- eqns = a*x+b*y==3, x-y==b;
- vars = x, y;
+ lst eqns = @{a*x+b*y==3, x-y==b@};
+ lst vars = @{x, y@};
cout << lsolve(eqns, vars) << endl;
// -> @{x==(3+b^2)/(b+a),y==(3-b*a)/(b+a)@}
@end example
table["x"] = x+log(y)+1;
parser reader(table);
ex e = reader("5*x^3 - x^2");
- // e = 5*(x+log(y)+1)^3 + (x+log(y)+1)^2
+ // e = 5*(x+log(y)+1)^3 - (x+log(y)+1)^2
@}
@end example
parser reader;
ex e = reader("2*x+sin(y)");
symtab table = reader.get_syms();
- symbol x = reader["x"];
- symbol y = reader["y"];
+ symbol x = ex_to<symbol>(table["x"]);
+ symbol y = ex_to<symbol>(table["y"]);
@}
@end example
@}
@end example
-With this parser, it's also easy to implement interactive GiNaC programs:
+With this parser, it's also easy to implement interactive GiNaC programs.
+When running the following program interactively, remember to send an
+EOF marker after the input, e.g. by pressing Ctrl-D on an empty line:
@example
#include <iostream>
@cindex Monte Carlo integration
@code{FUNCP_2P} allows for two variables in the expression. @code{FUNCP_CUBA} is
the correct type to be used with the CUBA library
-(@uref{http://www.feynarts/cuba}) for numerical integrations. The details for the
+(@uref{http://www.feynarts.de/cuba}) for numerical integrations. The details for the
parameters of @code{FUNCP_CUBA} are explained in the CUBA manual.
@cindex compile_ex
@cindex ginac-excompiler
@code{compile_ex} uses the shell script @code{ginac-excompiler} to start the C
compiler and produce the object files. This shell script comes with GiNaC and
-will be installed together with GiNaC in the configured @code{$PREFIX/bin}
-directory.
+will be installed together with GiNaC in the configured @code{$LIBEXECDIR}
+(typically @code{$PREFIX/libexec} or @code{$PREFIX/lib/ginac}). You can also
+export additional compiler flags via the @env{$CXXFLAGS} variable:
+
+@example
+setenv("CXXFLAGS", "-O3 -fomit-frame-pointer -ffast-math", 1);
+compile_ex(...);
+@end example
@subsection Archiving
@cindex @code{archive} (class)
@example
#include <fstream>
-using namespace std;
#include <ginac/ginac.h>
+using namespace std;
using namespace GiNaC;
int main()
@example
// ...
- ofstream out("foobar.gar");
+ ofstream out("foobar.gar", ios::binary);
out << a;
out.close();
// ...
@end example
The file @file{foobar.gar} contains all information that is needed to
-reconstruct the expressions @code{foo} and @code{bar}.
+reconstruct the expressions @code{foo} and @code{bar}. The flag
+@code{ios::binary} prevents locales setting of your OS tampers the
+archive file structure.
@cindex @command{viewgar}
The tool @command{viewgar} that comes with GiNaC can be used to view
@example
// ...
archive a2;
- ifstream in("foobar.gar");
+ ifstream in("foobar.gar", ios::binary);
in >> a2;
// ...
@end example
@example
// ...
- lst syms;
- syms = x, y;
+ lst syms = @{x, y@};
ex ex1 = a2.unarchive_ex(syms, "foo");
ex ex2 = a2.unarchive_ex(syms, "the second one");
case the function has more than one parameter, and its main application
is for correct handling of the chain rule.
+Derivatives of some functions, for example @code{abs()} and
+@code{Order()}, could not be evaluated through the chain rule. In such
+cases the full derivative may be specified as shown for @code{Order()}:
+
+@example
+static ex Order_expl_derivative(const ex & arg, const symbol & s)
+@{
+ return Order(arg.diff(s));
+@}
+@end example
+
+That is, we need to supply a procedure, which returns the expression of
+derivative with respect to the variable @code{s} for the argument
+@code{arg}. This procedure need to be registered with the function
+through the option @code{expl_derivative_func} (see the next
+Subsection). In contrast, a partial derivative, e.g. as was defined for
+@code{cos()} above, needs to be registered through the option
+@code{derivative_func}.
+
An implementation of the series expansion is not needed for @code{cos()} as
it doesn't have any poles and GiNaC can do Taylor expansion by itself (as
long as it knows what the derivative of @code{cos()} is). @code{tan()}, on
eval_func(<C++ function>)
evalf_func(<C++ function>)
derivative_func(<C++ function>)
+expl_derivative_func(<C++ function>)
series_func(<C++ function>)
conjugate_func(<C++ function>)
@end example
These specify the C++ functions that implement symbolic evaluation,
-numeric evaluation, partial derivatives, and series expansion, respectively.
-They correspond to the GiNaC methods @code{eval()}, @code{evalf()},
-@code{diff()} and @code{series()}.
+numeric evaluation, partial derivatives, explicit derivative, and series
+expansion, respectively. They correspond to the GiNaC methods
+@code{eval()}, @code{evalf()}, @code{diff()} and @code{series()}.
The @code{eval_func()} function needs to use @code{.hold()} if no further
automatic evaluation is desired or possible.
function before calling the @code{evalf_func()}.
@example
-set_return_type(unsigned return_type, unsigned return_type_tinfo)
+set_return_type(unsigned return_type, const return_type_t * return_type_tinfo)
@end example
This allows you to explicitly specify the commutation properties of the
function (@xref{Non-commutative objects}, for an explanation of
-(non)commutativity in GiNaC). For example, you can use
-@code{set_return_type(return_types::noncommutative, TINFO_matrix)} to make
-GiNaC treat your function like a matrix. By default, functions inherit the
-commutation properties of their first argument.
+(non)commutativity in GiNaC). For example, with an object of type
+@code{return_type_t} created like
+
+@example
+return_type_t my_type = make_return_type_t<matrix>();
+@end example
+
+you can use @code{set_return_type(return_types::noncommutative, &my_type)} to
+make GiNaC treat your function like a matrix. By default, functions inherit the
+commutation properties of their first argument. The utilized template function
+@code{make_return_type_t<>()}
+
+@example
+template<typename T> inline return_type_t make_return_type_t(const unsigned rl = 0)
+@end example
+
+can also be called with an argument specifying the representation label of the
+non-commutative function (see section on dirac gamma matrices for more
+details).
@example
set_symmetry(const symmetry & s)
@example
#include <iostream>
-using namespace std;
-
#include <ginac/ginac.h>
+using namespace std;
using namespace GiNaC;
struct sprod_s @{
you enough information so you can consult the source to GiNaC's predefined
classes if you want to implement something more complicated.
-@subsection GiNaC's run-time type information system
+@subsection Hierarchy of algebraic classes.
@cindex hierarchy of classes
-@cindex RTTI
All algebraic classes (that is, all classes that can appear in expressions)
in GiNaC are direct or indirect subclasses of the class @code{basic}. So a
-@code{basic *} (which is essentially what an @code{ex} is) represents a
-generic pointer to an algebraic class. Occasionally it is necessary to find
-out what the class of an object pointed to by a @code{basic *} really is.
-Also, for the unarchiving of expressions it must be possible to find the
-@code{unarchive()} function of a class given the class name (as a string). A
-system that provides this kind of information is called a run-time type
-information (RTTI) system. The C++ language provides such a thing (see the
-standard header file @file{<typeinfo>}) but for efficiency reasons GiNaC
-implements its own, simpler RTTI.
-
-The RTTI in GiNaC is based on two mechanisms:
-
+@code{basic *} represents a generic pointer to an algebraic class. Working
+with such pointers directly is cumbersome (think of memory management), hence
+GiNaC wraps them into @code{ex} (@pxref{Expressions are reference counted}).
+To make such wrapping possible every algebraic class has to implement several
+methods. Visitors (@pxref{Visitors and tree traversal}), printing, and
+(un)archiving (@pxref{Input/output}) require helper methods too. But don't
+worry, most of the work is simplified by the following macros (defined
+in @file{registrar.h}):
@itemize @bullet
+@item @code{GINAC_DECLARE_REGISTERED_CLASS}
+@item @code{GINAC_IMPLEMENT_REGISTERED_CLASS}
+@item @code{GINAC_IMPLEMENT_REGISTERED_CLASS_OPT}
+@end itemize
-@item
-The @code{basic} class declares a member variable @code{tinfo_key} which
-holds a variable of @code{tinfo_t} type (which is actually just
-@code{const void*}) that identifies the object's class.
-
-@item
-By means of some clever tricks with static members, GiNaC maintains a list
-of information for all classes derived from @code{basic}. The information
-available includes the class names, the @code{tinfo_key}s, and pointers
-to the unarchiving functions. This class registry is defined in the
-@file{registrar.h} header file.
+The @code{GINAC_DECLARE_REGISTERED_CLASS} macro inserts declarations
+required for memory management, visitors, printing, and (un)archiving.
+It takes the name of the class and its direct superclass as arguments.
+The @code{GINAC_DECLARE_REGISTERED_CLASS} should be the first line after
+the opening brace of the class definition.
-@end itemize
+@code{GINAC_IMPLEMENT_REGISTERED_CLASS} takes the same arguments as
+@code{GINAC_DECLARE_REGISTERED_CLASS}. It initializes certain static
+members of a class so that printing and (un)archiving works. The
+@code{GINAC_IMPLEMENT_REGISTERED_CLASS} may appear anywhere else in
+the source (at global scope, of course, not inside a function).
-The disadvantage of this proprietary RTTI implementation is that there's
-a little more to do when implementing new classes (C++'s RTTI works more
-or less automatically) but don't worry, most of the work is simplified by
-macros.
+@code{GINAC_IMPLEMENT_REGISTERED_CLASS_OPT} is a variant of
+@code{GINAC_IMPLEMENT_REGISTERED_CLASS}. It allows specifying additional
+options, such as custom printing functions.
@subsection A minimalistic example
#include <iostream>
#include <string>
#include <stdexcept>
-using namespace std;
-
#include <ginac/ginac.h>
+using namespace std;
using namespace GiNaC;
@end example
Now we can write down the class declaration. The class stores a C++
@code{string} and the user shall be able to construct a @code{mystring}
-object from a C or C++ string:
+object from a string:
@example
class mystring : public basic
public:
mystring(const string & s);
- mystring(const char * s);
private:
string str;
GINAC_IMPLEMENT_REGISTERED_CLASS(mystring, basic)
@end example
-The @code{GINAC_DECLARE_REGISTERED_CLASS} and @code{GINAC_IMPLEMENT_REGISTERED_CLASS}
-macros are defined in @file{registrar.h}. They take the name of the class
-and its direct superclass as arguments and insert all required declarations
-for the RTTI system. The @code{GINAC_DECLARE_REGISTERED_CLASS} should be
-the first line after the opening brace of the class definition. The
-@code{GINAC_IMPLEMENT_REGISTERED_CLASS} may appear anywhere else in the
-source (at global scope, of course, not inside a function).
-
-@code{GINAC_DECLARE_REGISTERED_CLASS} contains, among other things the
-declarations of the default constructor and a couple of other functions that
-are required. It also defines a type @code{inherited} which refers to the
-superclass so you don't have to modify your code every time you shuffle around
-the class hierarchy. @code{GINAC_IMPLEMENT_REGISTERED_CLASS} registers the
-class with the GiNaC RTTI (there is also a
-@code{GINAC_IMPLEMENT_REGISTERED_CLASS_OPT} which allows specifying additional
-options for the class, and which we will be using instead in a few minutes).
-
-Now there are seven member functions we have to implement to get a working
+The @code{GINAC_DECLARE_REGISTERED_CLASS} macro insert declarations required
+for memory management, visitors, printing, and (un)archiving.
+@code{GINAC_IMPLEMENT_REGISTERED_CLASS} initializes certain static members
+of a class so that printing and (un)archiving works.
+
+Now there are three member functions we have to implement to get a working
class:
@itemize
@item
@code{mystring()}, the default constructor.
-@item
-@code{void archive(archive_node & n)}, the archiving function. This stores all
-information needed to reconstruct an object of this class inside an
-@code{archive_node}.
-
-@item
-@code{mystring(const archive_node & n, lst & sym_lst)}, the unarchiving
-constructor. This constructs an instance of the class from the information
-found in an @code{archive_node}.
-
-@item
-@code{ex unarchive(const archive_node & n, lst & sym_lst)}, the static
-unarchiving function. It constructs a new instance by calling the unarchiving
-constructor.
-
@item
@cindex @code{compare_same_type()}
@code{int compare_same_type(const basic & other)}, which is used internally
defined.
@item
-And, of course, @code{mystring(const string & s)} and @code{mystring(const char * s)}
-which are the two constructors we declared.
+And, of course, @code{mystring(const string& s)} which is the constructor
+we declared.
@end itemize
Let's proceed step-by-step. The default constructor looks like this:
@example
-mystring::mystring() : inherited(&mystring::tinfo_static) @{@}
+mystring::mystring() @{ @}
@end example
-The golden rule is that in all constructors you have to set the
-@code{tinfo_key} member to the @code{&your_class_name::tinfo_static}
-@footnote{Each GiNaC class has a static member called tinfo_static.
-This member is declared by the GINAC_DECLARE_REGISTERED_CLASS macros
-and defined by the GINAC_IMPLEMENT_REGISTERED_CLASS macros.}. Otherwise
-it will be set by the constructor of the superclass and all hell will break
-loose in the RTTI. For your convenience, the @code{basic} class provides
-a constructor that takes a @code{tinfo_key} value, which we are using here
-(remember that in our case @code{inherited == basic}). If the superclass
-didn't have such a constructor, we would have to set the @code{tinfo_key}
-to the right value manually.
-
In the default constructor you should set all other member variables to
reasonable default values (we don't need that here since our @code{str}
member gets set to an empty string automatically).
-Next are the three functions for archiving. You have to implement them even
-if you don't plan to use archives, but the minimum required implementation
-is really simple. First, the archiving function:
-
-@example
-void mystring::archive(archive_node & n) const
-@{
- inherited::archive(n);
- n.add_string("string", str);
-@}
-@end example
-
-The only thing that is really required is calling the @code{archive()}
-function of the superclass. Optionally, you can store all information you
-deem necessary for representing the object into the passed
-@code{archive_node}. We are just storing our string here. For more
-information on how the archiving works, consult the @file{archive.h} header
-file.
-
-The unarchiving constructor is basically the inverse of the archiving
-function:
-
-@example
-mystring::mystring(const archive_node & n, lst & sym_lst) : inherited(n, sym_lst)
-@{
- n.find_string("string", str);
-@}
-@end example
-
-If you don't need archiving, just leave this function empty (but you must
-invoke the unarchiving constructor of the superclass). Note that we don't
-have to set the @code{tinfo_key} here because it is done automatically
-by the unarchiving constructor of the @code{basic} class.
-
-Finally, the unarchiving function:
-
-@example
-ex mystring::unarchive(const archive_node & n, lst & sym_lst)
-@{
- return (new mystring(n, sym_lst))->setflag(status_flags::dynallocated);
-@}
-@end example
-
-You don't have to understand how exactly this works. Just copy these
-four lines into your code literally (replacing the class name, of
-course). It calls the unarchiving constructor of the class and unless
-you are doing something very special (like matching @code{archive_node}s
-to global objects) you don't need a different implementation. For those
-who are interested: setting the @code{dynallocated} flag puts the object
-under the control of GiNaC's garbage collection. It will get deleted
-automatically once it is no longer referenced.
-
Our @code{compare_same_type()} function uses a provided function to compare
the string members:
are considered equal (in the sense that @math{A-B=0}), so you should compare
all relevant member variables.
-Now the only thing missing is our two new constructors:
+Now the only thing missing is our constructor:
@example
-mystring::mystring(const string & s)
- : inherited(&mystring::tinfo_static), str(s) @{@}
-mystring::mystring(const char * s)
- : inherited(&mystring::tinfo_static), str(s) @{@}
+mystring::mystring(const string& s) : str(s) @{ @}
@end example
-No surprises here. We set the @code{str} member from the argument and
-remember to pass the right @code{tinfo_key} to the @code{basic} constructor.
+No surprises here. We set the @code{str} member from the argument.
That's it! We now have a minimal working GiNaC class that can store
strings in algebraic expressions. Let's confirm that the RTTI works:
@{
...
public:
- ex eval(int level = 0) const;
+ ex eval() const override;
...
@};
-ex mystring::eval(int level) const
+ex mystring::eval() const
@{
string new_str;
for (size_t i=0; i<str.length(); i++) @{
if (new_str.length() == 0)
return 0;
- else
- return mystring(new_str).hold();
+
+ return mystring(new_str).hold();
@}
@end example
-The @code{level} argument is used to limit the recursion depth of the
-evaluation. We don't have any subexpressions in the @code{mystring}
-class so we are not concerned with this. If we had, we would call the
-@code{eval()} functions of the subexpressions with @code{level - 1} as
-the argument if @code{level != 1}. The @code{hold()} member function
-sets a flag in the object that prevents further evaluation. Otherwise
-we might end up in an endless loop. When you want to return the object
-unmodified, use @code{return this->hold();}.
+The @code{hold()} member function sets a flag in the object that prevents
+further evaluation. Otherwise we might end up in an endless loop. When you
+want to return the object unmodified, use @code{return this->hold();}.
+
+If our class had subobjects, we would have to evaluate them first (unless
+they are all of type @code{ex}, which are automatically evaluated). We don't
+have any subexpressions in the @code{mystring} class, so we are not concerned
+with this.
Let's confirm that it works:
@cindex @code{calchash()}
@cindex @code{is_equal_same_type()}
@example
-unsigned calchash() const;
-bool is_equal_same_type(const basic & other) const;
+unsigned calchash() const override;
+bool is_equal_same_type(const basic & other) const override;
@end example
The @code{calchash()} method returns an @code{unsigned} hash value for the
might want to provide:
@example
-bool info(unsigned inf) const;
-ex evalf(int level = 0) const;
-ex series(const relational & r, int order, unsigned options = 0) const;
-ex derivative(const symbol & s) const;
+bool info(unsigned inf) const override;
+ex evalf() const override;
+ex series(const relational & r, int order, unsigned options = 0) const override;
+ex derivative(const symbol & s) const override;
@end example
If your class stores sub-expressions (see the scalar product example in the
@cindex @code{let_op()}
@example
-size_t nops() cont;
-ex op(size_t i) const;
-ex & let_op(size_t i);
-ex subs(const lst & ls, const lst & lr, unsigned options = 0) const;
-ex map(map_function & f) const;
+size_t nops() const override;
+ex op(size_t i) const override;
+ex & let_op(size_t i) override;
+ex subs(const lst & ls, const lst & lr, unsigned options = 0) const override;
+ex map(map_function & f) const override;
@end example
@code{let_op()} is a variant of @code{op()} that allows write access. The
@subsection Upgrading extension classes from older version of GiNaC
-If you got some extension classes for GiNaC 1.3.X some changes are
-necessary in order to make your code work with GiNaC 1.4.
-
-@itemize @bullet
-@item constructors which set @code{tinfo_key} such as
+GiNaC used to use a custom run time type information system (RTTI). It was
+removed from GiNaC. Thus, one needs to rewrite constructors which set
+@code{tinfo_key} (which does not exist any more). For example,
@example
-myclass::myclass() : inherited(TINFO_myclass) @{@}
+myclass::myclass() : inherited(&myclass::tinfo_static) @{@}
@end example
-need to be rewritten as
+needs to be rewritten as
@example
-myclass::myclass() : inherited(&myclass::tinfo_static) @{@}
+myclass::myclass() @{@}
@end example
-@item TINO_myclass is not necessary any more and can be removed.
-
-@end itemize
-
-
@node A comparison with other CAS, Advantages, Adding classes, Top
@c node-name, next, previous, up
@chapter A Comparison With Other CAS
multiple interfaces: Though real GiNaC programs have to be written in
some editor, then be compiled, linked and executed, there are more ways
to work with the GiNaC engine. Many people want to play with
-expressions interactively, as in traditional CASs. Currently, two such
-windows into GiNaC have been implemented and many more are possible: the
-tiny @command{ginsh} that is part of the distribution exposes GiNaC's
-types to a command line and second, as a more consistent approach, an
-interactive interface to the Cint C++ interpreter has been put together
-(called GiNaC-cint) that allows an interactive scripting interface
-consistent with the C++ language. It is available from the usual GiNaC
-FTP-site.
+expressions interactively, as in traditional CASs: The tiny
+@command{ginsh} that comes with the distribution exposes many, but not
+all, of GiNaC's types to a command line.
@item
seamless integration: it is somewhere between difficult and impossible
advanced features: GiNaC cannot compete with a program like
@emph{Reduce} which exists for more than 30 years now or @emph{Maple}
which grows since 1981 by the work of dozens of programmers, with
-respect to mathematical features. Integration, factorization,
+respect to mathematical features. Integration,
non-trivial simplifications, limits etc. are missing in GiNaC (and are
not planned for the near future).
occasionally used other compilers and may be able to give you advice.}
GiNaC uses recent language features like explicit constructors, mutable
members, RTTI, @code{dynamic_cast}s and STL, so ANSI compliance is meant
-literally. Recent GCC versions starting at 2.95.3, although itself not
-yet ANSI compliant, support all needed features.
+literally.
@end itemize
happens. Knowing this will enable you to write much more efficient
code. If you still have an uncertain feeling with copy-on-write
semantics, we recommend you have a look at the
-@uref{http://www.parashift.com/c++-faq-lite/, C++-FAQ lite} by
-Marshall Cline. Chapter 16 covers this issue and presents an
-implementation which is pretty close to the one in GiNaC.
+@uref{https://isocpp.org/faq, C++-FAQ's} chapter on memory management.
+It covers this issue and presents an implementation which is pretty
+close to the one in GiNaC.
@node Internal representation of products and sums, Package tools, Expressions are reference counted, Internal structures
@node Configure script options, Example package, Package tools, Package tools
@c node-name, next, previous, up
-@subsection Configuring a package that uses GiNaC
+@appendixsection Configuring a package that uses GiNaC
The directory where the GiNaC libraries are installed needs
to be found by your system's dynamic linkers (both compile- and run-time
@node Example package, Bibliography, Configure script options, Package tools
@c node-name, next, previous, up
-@subsection Example of a package using GiNaC
+@appendixsection Example of a package using GiNaC
The following shows how to build a simple package using automake
and the @samp{PKG_CHECK_MODULES} macro. The program used here is @file{simple.cpp}:
@itemize @minus{}
@item
-@cite{ISO/IEC 14882:1998: Programming Languages: C++}
+@cite{ISO/IEC 14882:2011: Programming Languages: C++}
@item
@cite{CLN: A Class Library for Numbers}, @email{haible@@ilog.fr, Bruno Haible}