This is a tutorial that documents GiNaC @value{VERSION}, an open
framework for symbolic computation within the C++ programming language.
-Copyright (C) 1999-2017 Johannes Gutenberg University Mainz, Germany
+Copyright (C) 1999-2019 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
@page
@vskip 0pt plus 1filll
-Copyright @copyright{} 1999-2017 Johannes Gutenberg University Mainz, Germany
+Copyright @copyright{} 1999-2019 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
@section License
The GiNaC framework for symbolic computation within the C++ programming
-language is Copyright @copyright{} 1999-2017 Johannes Gutenberg
+language is Copyright @copyright{} 1999-2019 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
* 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
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.). You can retrive the name
+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()}
@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
@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
...
@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
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
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
@code{dirac_gamma} have more efficient simplification mechanism.
@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 pevious
+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:
@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
@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);
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
@{
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
@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");