* <ftp://ftp.santafe.edu/pub/gnu/>,
* <ftp://ftp.ilog.fr/pub/Users/haible/gnu/> or
* <ftp://ftpthep.physik.uni-mainz.de/pub/gnu/>.
-You will also need a decent ANSI-compliant C++-compiler. We use
-`post-EGCS' GCC, i.e GCC >= 2.95 for development so if you have a
-different compiler you are on your own. Note that you may have to use
-the same compiler you compiled CLN with because of differing
-name-mangling schemes.
+You will also need a decent ANSI-compliant C++-compiler. We recommend
+the C++ compiler from the GNU compiler collection, GCC >= 3.0. If you
+have a different or older compiler you are on your own. Note that you
+may have to use the same compiler you compiled CLN with because of
+differing name-mangling schemes.
INSTALLATION
# make install
Known to work with:
- - Linux on x86, Alpha and Sparc using GCC 2-95.x.
+ - Linux on x86, Alpha and Sparc using GCC 3.0.x, 3.1 and 3.2.
Known not to work with:
- - GCC 2.7.x or earlier because proper exception support is missing there.
+ - GCC 2.96 or earlier because proper exception and standard library support
+ is missing there.
The "configure" script can be given a number of options to enable and
disable various features. For a complete list, type:
You should use at least CLN-1.1, since during the development of
GiNaC various bugs have been discovered and fixed in earlier versions.
Please install CLN properly on your system before continuing with
-GiNaC. When using GCC3 as compiler please use at least CLN-1.1.1
-since some parts of GiNaC won't build with CLN-1.1.
+GiNaC.
Problems with building ginsh
----------------------------
Building GiNaC requires many standard header files. If you get a
configure error complaining about such missing files your compiler and
library are probably not up to date enough and it's no worth
-continuing. If the only file missing is <sstream>, however, there is
-a solution. GCC-2.95.2 and earlier don't ship with this file. A
-working implementation has been available since GCC-2.95.3. GCC-3.0
-and later have an even better, fully standard-conforming
-implementation, by default. If you are stuck with GCC-2.95.2 or
-earlier and you cannot upgrade your compiler we recommend obtaining
-the libstdc++-v2 <sstream> header written by Magnus Fromreide. It was
-posted to the gcc-patches mailing list on November 21 2000:
-<http://gcc.gnu.org/ml/gcc-patches/2000-11/msg01152.html>.
+continuing.
This file records noteworthy changes.
-1.0.15 (<date>)
-* Added on-line help and Tab-completion for print(), iprint(), print_latex()
- and print_csrc() in ginsh.
-* Fixed a bug in the unarchiving of sums and products: terms were not
- reordered in a canonical way.
-* Fixed a bug in normal()/numer_denom(): denominator was not made unit
- normal if it was a simple number
+1.2.0 (<insert date>)
+* Added a structure<T> template class for the easy creation of user-defined
+ algebraic classes.
+* Many internal reorganizations and optimizations.
+* Caveats for class implementors:
+ - basic::copy() and basic::destroy() are gone; classes derived from
+ basic can use the defaults for the assignment operator and copy
+ constructor.
+ - basic::subs() now descends into subexpressions (if accessible via
+ nops()/op()/let_op()). If you have a custom implementation of subs()
+ that calls basic::subs() after substituting subexpressions, this needs
+ to be changed to a call to subs_one_level().
+
+1.1.0 (3 April 2003)
+* Removed deprecated macros is_ex_a, is_ex_exactly_a and friends for good.
+* The scalar_products mechanism allows the specification of an index dimension.
+* Removed dirac_gamma6/7().
+* Added ex::to_polynomial().
+* subs() accepts an optional "options" argument. The option
+ subs_option::subs_algebraic enables "smart" substitutions in products and
+ powers.
+* Added stream manipulators "dflt", "latex", "python", "python_repr", "tree",
+ "csrc", "csrc_float", "csrc_double", "csrc_cl_N", "index_dimensions" and
+ "no_index_dimensions" to control the output format. Calling basic::print()
+ directly is now deprecated.
+* Made the hashing more simple and efficient.
+* Caveats for class implementors:
+ - basic::subs(): third argument changed from "bool" to "unsigned"
+ - unarchiving constructor and basic::unarchive(): "const" removed from
+ second argument
+ - basic::let_op() should only be implemented if write access to
+ subexpressions is desired
+ - simplify_ncmul() renamed to eval_ncmul()
+ - simplified_ncmul() renamed to hold_ncmul()
+ - nonsimplified_ncmul() renamed to reeval_ncmul()
1.0.14 (1 March 2003)
* Improved the C-source output: complex numbers are printed correctly (using
time_lw_H.cpp time_lw_IJKL.cpp time_lw_M1.cpp time_lw_M2.cpp time_lw_N.cpp \
time_lw_O.cpp time_lw_P.cpp time_lw_Pprime.cpp time_lw_Q.cpp \
time_lw_Qprime.cpp time_antipode.cpp time_fateman_expand.cpp \
- timer.cpp times.cpp times.h
+ timer.cpp timer.h times.cpp times.h
times_LDADD = ../ginac/libginac.la
INCLUDES = -I$(srcdir)/../ginac -I../ginac
#include "checks.h"
/* Some tests on the sine trigonometric function. */
-static unsigned inifcns_check_sin(void)
+static unsigned inifcns_check_sin()
{
unsigned result = 0;
bool errorflag = false;
}
/* Simple tests on the cosine trigonometric function. */
-static unsigned inifcns_check_cos(void)
+static unsigned inifcns_check_cos()
{
unsigned result = 0;
bool errorflag;
}
/* Simple tests on the tangent trigonometric function. */
-static unsigned inifcns_check_tan(void)
+static unsigned inifcns_check_tan()
{
unsigned result = 0;
bool errorflag;
}
/* Simple tests on the dilogarithm function. */
-static unsigned inifcns_check_Li2(void)
+static unsigned inifcns_check_Li2()
{
// NOTE: this can safely be removed once CLN supports dilogarithms and
// checks them itself.
return result;
}
-unsigned check_inifcns(void)
+unsigned check_inifcns()
{
unsigned result = 0;
/** @file check_lsolve.cpp
*
* These test routines do some simple checks on solving linear systems of
- * symbolic equations. */
+ * symbolic equations. They are a well-tried resource for cross-checking
+ * the underlying symbolic manipulations. */
/*
* GiNaC Copyright (C) 1999-2003 Johannes Gutenberg University Mainz, Germany
{
unsigned result = 0;
- for (int repetition=0; repetition<100; ++repetition) {
+ for (int repetition=0; repetition<200; ++repetition) {
// create two size n vectors of symbols, one for the coefficients
// a[0],..,a[n], one for indeterminates x[0]..x[n]:
vector<symbol> a;
return result;
}
-unsigned check_lsolve(void)
+unsigned check_lsolve()
{
unsigned result = 0;
clog << "---------linear solve:" << endl;
// solve some numeric linear systems
- for (unsigned n=1; n<12; ++n)
+ for (unsigned n=1; n<14; ++n)
result += check_matrix_solve(n, n, 1, 0);
cout << '.' << flush;
// solve some underdetermined numeric systems
- for (unsigned n=1; n<12; ++n)
+ for (unsigned n=1; n<14; ++n)
result += check_matrix_solve(n+1, n, 1, 0);
cout << '.' << flush;
// solve some overdetermined numeric systems
- for (unsigned n=1; n<12; ++n)
+ for (unsigned n=1; n<14; ++n)
result += check_matrix_solve(n, n+1, 1, 0);
cout << '.' << flush;
// solve some multiple numeric systems
- for (unsigned n=1; n<12; ++n)
+ for (unsigned n=1; n<14; ++n)
result += check_matrix_solve(n, n, n/3+1, 0);
cout << '.' << flush;
// solve some symbolic linear systems
- for (unsigned n=1; n<7; ++n)
+ for (unsigned n=1; n<8; ++n)
result += check_matrix_solve(n, n, 1, 2);
cout << '.' << flush;
/** @file check_matrices.cpp
*
- * Here we test manipulations on GiNaC's symbolic matrices. */
+ * Here we test manipulations on GiNaC's symbolic matrices. They are a
+ * well-tried resource for cross-checking the underlying symbolic
+ * manipulations. */
/*
* GiNaC Copyright (C) 1999-2003 Johannes Gutenberg University Mainz, Germany
/* determinants of some sparse symbolic matrices with coefficients in
* an integral domain. */
-static unsigned integdom_matrix_determinants(void)
+static unsigned integdom_matrix_determinants()
{
unsigned result = 0;
symbol a("a");
- for (unsigned size=3; size<20; ++size) {
+ for (unsigned size=3; size<22; ++size) {
matrix A(size,size);
// populate one element in each row:
for (unsigned r=0; r<size-1; ++r)
/* determinants of some symbolic matrices with multivariate rational function
* coefficients. */
-static unsigned rational_matrix_determinants(void)
+static unsigned rational_matrix_determinants()
{
unsigned result = 0;
symbol a("a"), b("b"), c("c");
- for (unsigned size=3; size<8; ++size) {
+ for (unsigned size=3; size<9; ++size) {
matrix A(size,size);
for (unsigned r=0; r<size-1; ++r) {
// populate one or two elements in each row:
}
/* Some quite funny determinants with functions and stuff like that inside. */
-static unsigned funny_matrix_determinants(void)
+static unsigned funny_matrix_determinants()
{
unsigned result = 0;
symbol a("a"), b("b"), c("c");
- for (unsigned size=3; size<7; ++size) {
+ for (unsigned size=3; size<8; ++size) {
matrix A(size,size);
for (unsigned co=0; co<size-1; ++co) {
// populate one or two elements in each row:
}
/* compare results from different determinant algorithms.*/
-static unsigned compare_matrix_determinants(void)
+static unsigned compare_matrix_determinants()
{
unsigned result = 0;
symbol a("a");
- for (unsigned size=2; size<7; ++size) {
+ for (unsigned size=2; size<8; ++size) {
matrix A(size,size);
for (unsigned co=0; co<size; ++co) {
for (unsigned ro=0; ro<size; ++ro) {
return result;
}
-static unsigned symbolic_matrix_inverse(void)
+static unsigned symbolic_matrix_inverse()
{
unsigned result = 0;
symbol a("a"), b("b"), c("c");
- for (unsigned size=2; size<5; ++size) {
+ for (unsigned size=2; size<6; ++size) {
matrix A(size,size);
do {
for (unsigned co=0; co<size; ++co) {
return result;
}
-unsigned check_matrices(void)
+unsigned check_matrices()
{
unsigned result = 0;
/* Simple and maybe somewhat pointless consistency tests of assorted tests and
* conversions. */
-static unsigned check_numeric1(void)
+static unsigned check_numeric1()
{
unsigned result = 0;
bool errorflag = false;
return result;
}
-static unsigned check_numeric2(void)
+static unsigned check_numeric2()
{
unsigned result = 0;
bool errorflag = false;
return result;
}
-unsigned check_numeric(void)
+unsigned check_numeric()
{
unsigned result = 0;
#include <fstream>
-unsigned exam_archive(void)
+unsigned exam_archive()
{
unsigned result = 0;
return 0;
}
-static unsigned clifford_check1(void)
+static unsigned clifford_check1()
{
// checks general identities and contractions
return result;
}
-static unsigned clifford_check2(void)
+static unsigned clifford_check2()
{
// checks identities relating to gamma5
return result;
}
-static unsigned clifford_check3(void)
+static unsigned clifford_check3()
{
// checks traces
return result;
}
-static unsigned clifford_check4(void)
+static unsigned clifford_check4()
{
// simplify_indexed()/dirac_trace() cross-checks
return result;
}
-static unsigned clifford_check5(void)
+static unsigned clifford_check5()
{
// canonicalize_clifford() checks
return result;
}
-unsigned exam_clifford(void)
+unsigned exam_clifford()
{
unsigned result = 0;
return 0;
}
-static unsigned color_check1(void)
+static unsigned color_check1()
{
// checks general identities and contractions of the structure constants
return result;
}
-static unsigned color_check2(void)
+static unsigned color_check2()
{
// checks general identities and contractions of the generators
return result;
}
-static unsigned color_check3(void)
+static unsigned color_check3()
{
// checks traces
return result;
}
-unsigned exam_color(void)
+unsigned exam_color()
{
unsigned result = 0;
clog << "derivative of " << e << " by " << x << " returned "
<< ed << " instead of " << d << endl;
clog << "returned:" << endl;
- ed.printtree(clog);
- clog << endl << "instead of" << endl;
- d.printtree(clog);
+ clog << tree << ed << "instead of\n" << d << dflt;
return 1;
}
}
// Simple (expanded) polynomials
-static unsigned exam_differentiation1(void)
+static unsigned exam_differentiation1()
{
unsigned result = 0;
symbol x("x"), y("y");
}
// Trigonometric functions
-static unsigned exam_differentiation2(void)
+static unsigned exam_differentiation2()
{
unsigned result = 0;
symbol x("x"), y("y"), a("a"), b("b");
}
// exp function
-static unsigned exam_differentiation3(void)
+static unsigned exam_differentiation3()
{
unsigned result = 0;
symbol x("x"), y("y"), a("a"), b("b");
}
// log functions
-static unsigned exam_differentiation4(void)
+static unsigned exam_differentiation4()
{
unsigned result = 0;
symbol x("x"), y("y"), a("a"), b("b");
}
// Functions with two variables
-static unsigned exam_differentiation5(void)
+static unsigned exam_differentiation5()
{
unsigned result = 0;
symbol x("x"), y("y"), a("a"), b("b");
}
// Series
-static unsigned exam_differentiation6(void)
+static unsigned exam_differentiation6()
{
symbol x("x");
ex e, d, ed;
}
// Hashing can help a lot, if differentiation is done cleverly
-static unsigned exam_differentiation7(void)
+static unsigned exam_differentiation7()
{
symbol x("x");
ex P = x + pow(x,3);
return 0;
}
-unsigned exam_differentiation(void)
+unsigned exam_differentiation()
{
unsigned result = 0;
return 0;
}
-static unsigned delta_check(void)
+static unsigned delta_check()
{
// checks identities of the delta tensor
return result;
}
-static unsigned metric_check(void)
+static unsigned metric_check()
{
// checks identities of the metric tensor
return result;
}
-static unsigned epsilon_check(void)
+static unsigned epsilon_check()
{
// checks identities of the epsilon tensor
DECLARE_FUNCTION_2P(anti_fcn)
REGISTER_FUNCTION(anti_fcn, set_symmetry(sy_anti(0, 1)));
-static unsigned symmetry_check(void)
+static unsigned symmetry_check()
{
// check symmetric/antisymmetric objects
return result;
}
-static unsigned scalar_product_check(void)
+static unsigned scalar_product_check()
{
// check scalar product replacement
return result;
}
-static unsigned edyn_check(void)
+static unsigned edyn_check()
{
// Relativistic electrodynamics
return result;
}
-static unsigned spinor_check(void)
+static unsigned spinor_check()
{
// check identities of the spinor metric
return result;
}
-static unsigned dummy_check(void)
+static unsigned dummy_check()
{
// check dummy index renaming/repositioning
return result;
}
-unsigned exam_indexed(void)
+unsigned exam_indexed()
{
unsigned result = 0;
#include "exams.h"
/* Assorted tests on other transcendental functions. */
-static unsigned inifcns_consist_trans(void)
+static unsigned inifcns_consist_trans()
{
unsigned result = 0;
symbol x("x");
/* Simple tests on the tgamma function. We stuff in arguments where the results
* exists in closed form and check if it's ok. */
-static unsigned inifcns_consist_gamma(void)
+static unsigned inifcns_consist_gamma()
{
unsigned result = 0;
ex e;
/* Simple tests on the Psi-function (aka polygamma-function). We stuff in
arguments where the result exists in closed form and check if it's ok. */
-static unsigned inifcns_consist_psi(void)
+static unsigned inifcns_consist_psi()
{
unsigned result = 0;
symbol x;
/* Simple tests on the Riemann Zeta function. We stuff in arguments where the
* result exists in closed form and check if it's ok. Of course, this checks
* the Bernoulli numbers as a side effect. */
-static unsigned inifcns_consist_zeta(void)
+static unsigned inifcns_consist_zeta()
{
unsigned result = 0;
ex e;
return result;
}
-unsigned exam_inifcns(void)
+unsigned exam_inifcns()
{
unsigned result = 0;
#include "exams.h"
-static unsigned exam_lsolve1(void)
+static unsigned exam_lsolve1()
{
// A trivial example.
unsigned result = 0;
return result;
}
-static unsigned exam_lsolve2a(void)
+static unsigned exam_lsolve2a()
{
// An example from the Maple online help.
unsigned result = 0;
return result;
}
-static unsigned exam_lsolve2b(void)
+static unsigned exam_lsolve2b()
{
// A boring example from Mathematica's online help.
unsigned result = 0;
return result;
}
-static unsigned exam_lsolve2c(void)
+static unsigned exam_lsolve2c()
{
// A more interesting example from the Maple online help.
unsigned result = 0;
return result;
}
-static unsigned exam_lsolve2S(void)
+static unsigned exam_lsolve2S()
{
// A degenerate example that went wrong in GiNaC 0.6.2.
unsigned result = 0;
return result;
}
-static unsigned exam_lsolve3S(void)
+static unsigned exam_lsolve3S()
{
// A degenerate example that went wrong while trying to improve elimination
unsigned result = 0;
return result;
}
-unsigned exam_lsolve(void)
+unsigned exam_lsolve()
{
unsigned result = 0;
#include <stdexcept>
#include "exams.h"
-static unsigned matrix_determinants(void)
+static unsigned matrix_determinants()
{
unsigned result = 0;
ex det;
return result;
}
-static unsigned matrix_invert1(void)
+static unsigned matrix_invert1()
{
unsigned result = 0;
matrix m(1,1);
return result;
}
-static unsigned matrix_invert2(void)
+static unsigned matrix_invert2()
{
unsigned result = 0;
matrix m(2,2);
return result;
}
-static unsigned matrix_invert3(void)
+static unsigned matrix_invert3()
{
unsigned result = 0;
matrix m(3,3);
return result;
}
-static unsigned matrix_solve2(void)
+static unsigned matrix_solve2()
{
// check the solution of the multiple system A*X = B:
// [ 1 2 -1 ] [ x0 y0 ] [ 4 0 ]
return result;
}
-static unsigned matrix_evalm(void)
+static unsigned matrix_evalm()
{
unsigned result = 0;
return result;
}
-static unsigned matrix_misc(void)
+static unsigned matrix_misc()
{
unsigned result = 0;
matrix m1(2,2);
return result;
}
-unsigned exam_matrices(void)
+unsigned exam_matrices()
{
unsigned result = 0;
#include "exams.h"
#define VECSIZE 30
-static unsigned exam_expand_subs(void)
+static unsigned exam_expand_subs()
{
unsigned result = 0;
symbol a[VECSIZE];
* 2) expand e
* 3) substitute a0 by -a1 in e
* after which e should return 0 (without expanding). */
-static unsigned exam_expand_subs2(void)
+static unsigned exam_expand_subs2()
{
unsigned result = 0;
symbol a("a"), b("b");
return result;
}
-static unsigned exam_expand_power(void)
+static unsigned exam_expand_power()
{
unsigned result = 0;
symbol x("x"), a("a"), b("b");
return result;
}
-static unsigned exam_sqrfree(void)
+static unsigned exam_sqrfree()
{
unsigned result = 0;
symbol x("x"), y("y");
* When somebody screws up the operators this routine will most probably fail
* to compile. Unfortunately we can only test the stuff that is allowed, not
* what is forbidden (e.g. e1+e2 = 42) since that must not compile. :-( */
-static unsigned exam_operator_semantics(void)
+static unsigned exam_operator_semantics()
{
unsigned result = 0;
ex e1, e2;
}
/* This checks whether subs() works as intended in some special cases. */
-static unsigned exam_subs(void)
+static unsigned exam_subs()
{
unsigned result = 0;
symbol x("x");
return result;
}
-unsigned exam_misc(void)
+/* Joris van der Hoeven (he of TeXmacs fame) is a funny guy. He has his own
+ * ideas what a symbolic system should do. Let's make sure we won't disappoint
+ * him some day. Incidentally, this seems to always have worked. */
+static unsigned exam_joris()
+{
+ unsigned result = 0;
+ symbol x("x");
+
+ ex e = expand(pow(x, x-1) * x);
+ if (e != pow(x, x)) {
+ clog << "x^(x-1)*x did not expand to x^x. Please call Joris!" << endl;
+ ++result;
+ }
+
+ return result;
+}
+
+/* Test Chris Dams' algebraic substitutions. */
+static unsigned exam_subs_algebraic()
+{
+ unsigned result = 0;
+ symbol x("x"), y("y");
+
+ ex e = ex(x*x*x*y*y).subs(x*y==2, subs_options::subs_algebraic);
+ if (e != 4*x) {
+ clog << "(x^3*y^2).subs(x*y==2,subs_options::subs_algebraic) erroneously returned " << e << endl;
+ ++result;
+ }
+
+ e = ex(x*x*x*x*x).subs(x*x==y, subs_options::subs_algebraic);
+ if (e != y*y*x) {
+ clog << "x^5.subs(x^2==y,subs_options::subs_algebraic) erroneously returned " << e << endl;
+ ++result;
+ }
+
+ return result;
+}
+
+unsigned exam_misc()
{
unsigned result = 0;
result += exam_sqrfree(); cout << '.' << flush;
result += exam_operator_semantics(); cout << '.' << flush;
result += exam_subs(); cout << '.' << flush;
+ result += exam_joris(); cout << '.' << flush;
+ result += exam_subs_algebraic(); cout << '.' << flush;
if (!result) {
cout << " passed " << endl;
return 0;
}
-static unsigned exam_normal1(void)
+static unsigned exam_normal1()
{
unsigned result = 0;
ex e, d;
return result;
}
-static unsigned exam_normal2(void)
+static unsigned exam_normal2()
{
unsigned result = 0;
ex e, d;
return result;
}
-static unsigned exam_normal3(void)
+static unsigned exam_normal3()
{
unsigned result = 0;
ex e, d;
return result;
}
-static unsigned exam_normal4(void)
+static unsigned exam_normal4()
{
unsigned result = 0;
ex e, d;
return result;
}
-unsigned exam_normalization(void)
+unsigned exam_normalization()
{
unsigned result = 0;
/* Simple and maybe somewhat pointless consistency tests of assorted tests and
* conversions. */
-static unsigned exam_numeric1(void)
+static unsigned exam_numeric1()
{
unsigned result = 0;
numeric test_int1(42);
* Implementing a workaround sadly introduced another bug on May 28th 1999
* that was fixed on May 31st. The workaround turned out to be stupid and
* the original bug in CLN was finally killed on September 2nd. */
-static unsigned exam_numeric2(void)
+static unsigned exam_numeric2()
{
unsigned result = 0;
/* Assorted tests to ensure some crucial functions behave exactly as specified
* in the documentation. */
-static unsigned exam_numeric3(void)
+static unsigned exam_numeric3()
{
unsigned result = 0;
numeric calc_rem, calc_quo;
/* Now we perform some less trivial checks about several functions which should
* return exact numbers if possible. */
-static unsigned exam_numeric4(void)
+static unsigned exam_numeric4()
{
unsigned result = 0;
bool passed;
/* This test examines that simplifications of the form 5^(3/2) -> 5*5^(1/2)
* are carried out properly. */
-static unsigned exam_numeric5(void)
+static unsigned exam_numeric5()
{
unsigned result = 0;
/* This test checks whether the numeric output/parsing routines are
consistent. */
-static unsigned exam_numeric6(void)
+static unsigned exam_numeric6()
{
unsigned result = 0;
return result;
}
-unsigned exam_numeric(void)
+unsigned exam_numeric()
{
unsigned result = 0;
// The very first pair of historic problems had its roots in power.cpp and was
// finally resolved on April 27th 1999. (Fixing the first on April 23rd
// actually introduced the second.)
-static unsigned exam_paranoia1(void)
+static unsigned exam_paranoia1()
{
unsigned result = 0;
symbol x("x"), y("y"), z("z");
// And here the second oops which showed up until May 17th 1999. It had to do
// with lexicographic canonicalization and thus showed up only if the variables
// had the names as given here:
-static unsigned exam_paranoia2(void)
+static unsigned exam_paranoia2()
{
unsigned result = 0;
symbol x("x"), y("y"), z("z");
// The third bug was introduced on May 18th 1999, discovered on May 19 and
// fixed that same day. It worked when x was substituted by 1 but not with
// other numbers:
-static unsigned exam_paranoia3(void)
+static unsigned exam_paranoia3()
{
unsigned result = 0;
symbol x("x"), y("y");
}
// The fourth bug was also discovered on May 19th 1999 and fixed immediately:
-static unsigned exam_paranoia4(void)
+static unsigned exam_paranoia4()
{
unsigned result = 0;
symbol x("x");
}
// The fifth oops was discovered on May 20th 1999 and fixed a day later:
-static unsigned exam_paranoia5(void)
+static unsigned exam_paranoia5()
{
unsigned result = 0;
symbol x("x"), y("y");
}
// This one was discovered on Jun 1st 1999 and fixed the same day:
-static unsigned exam_paranoia6(void)
+static unsigned exam_paranoia6()
{
unsigned result = 0;
symbol x("x");
// This one was introduced on June 1st 1999 by some aggressive manual
// optimization. Discovered and fixed on June 2nd.
-static unsigned exam_paranoia7(void)
+static unsigned exam_paranoia7()
{
unsigned result = 0;
symbol x("x"), y("y");
// This one was a result of the rewrite of mul::max_coefficient when we
// introduced the overall_coefficient field in expairseq objects on Oct 1st
// 1999. Fixed on Oct 4th.
-static unsigned exam_paranoia8(void)
+static unsigned exam_paranoia8()
{
unsigned result = 0;
symbol x("x");
// Z[X]. multiply_lcm() forgot to multiply the x-linear term with the LCM of
// the coefficient's denominators (2 in this case). Introduced on Jan 25th
// 2000 and fixed on Jan 31th.
-static unsigned exam_paranoia9(void)
+static unsigned exam_paranoia9()
{
unsigned result = 0;
symbol x("x");
// and on Feb 13th 2000 I found out that things like 2^(3/2) throw an exception
// "power::eval(): pow(0,0) is undefined" instead of simplifying to 2*2^(1/2).
// It was fixed that same day.
-static unsigned exam_paranoia10(void)
+static unsigned exam_paranoia10()
{
unsigned result = 0;
// add::normal() forgot to multiply the denominator of the overall_coeff of
// its expanded and normalized children with the denominator of the expanded
// child (did you get this? Well, never mind...). Fixed on Feb 21th 2000.
-static unsigned exam_paranoia11(void)
+static unsigned exam_paranoia11()
{
unsigned result = 0;
symbol x("x");
// This one returned 0 because add::normal() incorrectly assumed that if the
// common denominator is 1, all the denominators would be 1 (they can in fact
// be +/-1). Fixed on Aug 2nd 2000.
-static unsigned exam_paranoia12(void)
+static unsigned exam_paranoia12()
{
unsigned result = 0;
symbol x("x");
// This one caused a division by 0 because heur_gcd() didn't check its
// input polynomials against 0. Fixed on Aug 4th 2000.
-static unsigned exam_paranoia13(void)
+static unsigned exam_paranoia13()
{
unsigned result = 0;
symbol a("a"), b("b"), c("c");
// A bug introduced on July 19, 2001. quo() and rem() would sometimes call
// vector::reserve() with a negative argument. Fixed on Dec 20, 2001.
-static unsigned exam_paranoia14(void)
+static unsigned exam_paranoia14()
{
unsigned result = 0;
symbol x("x");
// Under certain conditions, power::expand_add_2() could produce non-canonical
// numeric expairs. Fixed on Oct 24, 2002.
-static unsigned exam_paranoia15(void)
+static unsigned exam_paranoia15()
{
unsigned result = 0;
return result;
}
-unsigned exam_paranoia(void)
+unsigned exam_paranoia()
{
unsigned result = 0;
static symbol y[MAX_VARIABLES];
// GCD = 1
-static unsigned poly_gcd1(void)
+static unsigned poly_gcd1()
{
for (int v=1; v<=MAX_VARIABLES; v++) {
ex e1 = x;
}
// Linearly dense quartic inputs with quadratic GCDs
-static unsigned poly_gcd2(void)
+static unsigned poly_gcd2()
{
for (int v=1; v<=MAX_VARIABLES; v++) {
ex e1 = x;
}
// Sparse GCD and inputs where degrees are proportional to the number of variables
-static unsigned poly_gcd3(void)
+static unsigned poly_gcd3()
{
for (int v=1; v<=MAX_VARIABLES; v++) {
ex e1 = pow(x, v + 1);
}
// Variation of case 3; major performance degradation with PRS
-static unsigned poly_gcd3p(void)
+static unsigned poly_gcd3p()
{
for (int v=1; v<=MAX_VARIABLES; v++) {
ex e1 = pow(x, v + 1);
}
// Quadratic non-monic GCD; f and g have other quadratic factors
-static unsigned poly_gcd4(void)
+static unsigned poly_gcd4()
{
for (int v=1; v<=MAX_VARIABLES; v++) {
ex e1 = pow(x, 2) * pow(y[0], 2);
}
// Completely dense non-monic quadratic inputs with dense non-monic linear GCDs
-static unsigned poly_gcd5(void)
+static unsigned poly_gcd5()
{
for (int v=1; v<=MAX_VARIABLES; v++) {
ex e1 = x + 1;
}
// Sparse non-monic quadratic inputs with linear GCDs
-static unsigned poly_gcd5p(void)
+static unsigned poly_gcd5p()
{
for (int v=1; v<=MAX_VARIABLES; v++) {
ex e1 = x;
}
// Trivariate inputs with increasing degrees
-static unsigned poly_gcd6(void)
+static unsigned poly_gcd6()
{
symbol y("y");
}
// Trivariate polynomials whose GCD has common factors with its cofactors
-static unsigned poly_gcd7(void)
+static unsigned poly_gcd7()
{
symbol y("y");
ex p = x - y * z + 1;
return 0;
}
-unsigned exam_polygcd(void)
+unsigned exam_polygcd()
{
unsigned result = 0;
#include "exams.h"
-static unsigned exam_powerlaws1(void)
+static unsigned exam_powerlaws1()
{
// (x^a)^b = x^(a*b)
return 0;
}
-static unsigned exam_powerlaws2(void)
+static unsigned exam_powerlaws2()
{
// (a*x)^b = a^b * x^b
return 0;
}
-static unsigned exam_powerlaws3(void)
+static unsigned exam_powerlaws3()
{
// numeric evaluation
return 0;
}
-static unsigned exam_powerlaws4(void)
+static unsigned exam_powerlaws4()
{
// test for mul::eval()
return 0;
}
-static unsigned exam_powerlaws5(void)
+static unsigned exam_powerlaws5()
{
// cabinet of slightly pathological cases
return 0;
}
-unsigned exam_powerlaws(void)
+unsigned exam_powerlaws()
{
unsigned result = 0;
clog << "series expansion of " << e << " at " << point
<< " erroneously returned " << ep << " (instead of " << d
<< ")" << endl;
- (ep-d).printtree(clog);
+ clog << tree << (ep-d) << dflt;
return 1;
}
return 0;
}
// Series expansion
-static unsigned exam_series1(void)
+static unsigned exam_series1()
{
unsigned result = 0;
ex e, d;
}
// Series addition
-static unsigned exam_series2(void)
+static unsigned exam_series2()
{
unsigned result = 0;
ex e, d;
}
// Series multiplication
-static unsigned exam_series3(void)
+static unsigned exam_series3()
{
unsigned result = 0;
ex e, d;
}
// Series exponentiation
-static unsigned exam_series4(void)
+static unsigned exam_series4()
{
unsigned result = 0;
ex e, d;
}
// Order term handling
-static unsigned exam_series5(void)
+static unsigned exam_series5()
{
unsigned result = 0;
ex e, d;
}
// Series expansion of tgamma(-1)
-static unsigned exam_series6(void)
+static unsigned exam_series6()
{
ex e = tgamma(2*x);
ex d = pow(x+1,-1)*numeric(1,4) +
}
// Series expansion of tan(x==Pi/2)
-static unsigned exam_series7(void)
+static unsigned exam_series7()
{
ex e = tan(x*Pi/2);
ex d = pow(x-1,-1)/Pi*(-2) + pow(x-1,1)*Pi/6 + pow(x-1,3)*pow(Pi,3)/360
}
// Series expansion of log(sin(x==0))
-static unsigned exam_series8(void)
+static unsigned exam_series8()
{
ex e = log(sin(x));
ex d = log(x) - pow(x,2)/6 - pow(x,4)/180 - pow(x,6)/2835
}
// Series expansion of Li2(sin(x==0))
-static unsigned exam_series9(void)
+static unsigned exam_series9()
{
ex e = Li2(sin(x));
ex d = x + pow(x,2)/4 - pow(x,3)/18 - pow(x,4)/48
}
// Series expansion of Li2((x==2)^2), caring about branch-cut
-static unsigned exam_series10(void)
+static unsigned exam_series10()
{
ex e = Li2(pow(x,2));
ex d = Li2(4) + (-log(3) + I*Pi*csgn(I-I*pow(x,2))) * (x-2)
}
// Series expansion of logarithms around branch points
-static unsigned exam_series11(void)
+static unsigned exam_series11()
{
unsigned result = 0;
ex e, d;
}
// Series expansion of other functions around branch points
-static unsigned exam_series12(void)
+static unsigned exam_series12()
{
unsigned result = 0;
ex e, d;
}
-unsigned exam_pseries(void)
+unsigned exam_pseries()
{
unsigned result = 0;
vertex(ijpair ij = ijpair(0,0)) : indices(ij) { }
void increment_indices(const ijpair &ind) { indices.first += ind.first; indices.second += ind.second; }
virtual ~vertex() { }
- virtual vertex* copy(void) const = 0;
- virtual ijpair get_increment(void) const { return indices; }
+ virtual vertex* copy() const = 0;
+ virtual ijpair get_increment() const { return indices; }
virtual const ex evaluate(const symbol &x, const unsigned grad) const = 0;
bool operator==(const vertex &v) const { return (indices==v.indices); }
bool operator<(const vertex &v) const { return (indices<v.indices); }
class Sigma : public vertex {
public:
Sigma(ijpair ij = ijpair(0,0)) : vertex(ij) { }
- vertex* copy(void) const { return new Sigma(*this); }
- ijpair get_increment(void) const { return ijpair(indices.first+indices.second+1, 0); }
+ vertex* copy() const { return new Sigma(*this); }
+ ijpair get_increment() const { return ijpair(indices.first+indices.second+1, 0); }
const ex evaluate(const symbol &x, const unsigned grad) const;
private:
};
class Sigma_flipped : public Sigma {
public:
Sigma_flipped(ijpair ij = ijpair(0,0)) : Sigma(ij) { }
- vertex* copy(void) const { return new Sigma_flipped(*this); }
- ijpair get_increment(void) const { return ijpair(0, indices.first+indices.second+1); }
+ vertex* copy() const { return new Sigma_flipped(*this); }
+ ijpair get_increment() const { return ijpair(0, indices.first+indices.second+1); }
const ex evaluate(const symbol &x, const unsigned grad) const { return Sigma::evaluate(x, grad); }
private:
};
class Gamma : public vertex {
public:
Gamma(ijpair ij = ijpair(0,0)) : vertex(ij) { }
- vertex* copy(void) const { return new Gamma(*this); }
- ijpair get_increment(void) const { return ijpair(indices.first+indices.second+1, 0); }
+ vertex* copy() const { return new Gamma(*this); }
+ ijpair get_increment() const { return ijpair(indices.first+indices.second+1, 0); }
const ex evaluate(const symbol &x, const unsigned grad) const;
private:
};
class Vacuum : public vertex {
public:
Vacuum(ijpair ij = ijpair(0,0)) : vertex(ij) { }
- vertex* copy(void) const { return new Vacuum(*this); }
+ vertex* copy() const { return new Vacuum(*this); }
ijpair get_increment() const { return ijpair(0, indices.first+indices.second+1); }
const ex evaluate(const symbol &x, const unsigned grad) const;
private:
~node() { delete vert; }
void add_child(const node &, bool = false);
const ex evaluate(const symbol &x, unsigned grad) const;
- unsigned total_edges(void) const;
+ unsigned total_edges() const;
bool operator==(const node &) const;
bool operator<(const node &) const;
private:
return (product * vert->evaluate(x,grad));
}
-unsigned node::total_edges(void) const
+unsigned node::total_edges() const
{
unsigned accu = 0;
for (multiset<child>::const_iterator i=children.begin(); i!=children.end(); ++i) {
return 0;
}
-unsigned time_antipode(void)
+unsigned time_antipode()
{
unsigned result = 0;
timer jaeger_le_coultre;
return result;
}
-unsigned time_dennyfliegner(void)
+unsigned time_dennyfliegner()
{
unsigned result = 0;
#include "times.h"
-static unsigned test(void)
+static unsigned test()
{
unsigned result = 0;
const symbol x("x"), y("y"), z("z");
return result;
}
-unsigned time_fateman_expand(void)
+unsigned time_fateman_expand()
{
unsigned result = 0;
unsigned count = 0;
return result;
}
-unsigned time_gammaseries(void)
+unsigned time_gammaseries()
{
unsigned result = 0;
#include "times.h"
-static unsigned test(void)
+static unsigned test()
{
for (int i=1; i<=99; ++i)
factorial(1000+i)/factorial(900+i);
return 0;
}
-unsigned time_lw_A(void)
+unsigned time_lw_A()
{
unsigned result = 0;
unsigned count = 0;
#include "times.h"
-static unsigned test(void)
+static unsigned test()
{
numeric s;
return 0;
}
-unsigned time_lw_B(void)
+unsigned time_lw_B()
{
unsigned result = 0;
unsigned count = 0;
#include "times.h"
-static unsigned test(void)
+static unsigned test()
{
numeric x(13*17*31);
numeric y(13*19*29);
return 0;
}
-unsigned time_lw_C(void)
+unsigned time_lw_C()
{
unsigned result = 0;
unsigned count = 0;
#include "times.h"
-static unsigned test(void)
+static unsigned test()
{
ex s;
symbol y("y");
return 0;
}
-unsigned time_lw_D(void)
+unsigned time_lw_D()
{
unsigned result = 0;
unsigned count = 0;
#include "times.h"
-static unsigned test(void)
+static unsigned test()
{
ex s;
symbol y("y");
return 0;
}
-unsigned time_lw_E(void)
+unsigned time_lw_E()
{
unsigned result = 0;
unsigned count = 0;
#include "times.h"
-static unsigned test(void)
+static unsigned test()
{
symbol x("x");
symbol y("y");
return 0;
}
-unsigned time_lw_F(void)
+unsigned time_lw_F()
{
unsigned result = 0;
unsigned count = 0;
#include "times.h"
-static unsigned test(void)
+static unsigned test()
{
symbol x("x");
symbol y("y");
return 0;
}
-unsigned time_lw_G(void)
+unsigned time_lw_G()
{
unsigned result = 0;
unsigned count = 0;
return 0;
}
-unsigned time_lw_H(void)
+unsigned time_lw_H()
{
unsigned result = 0;
unsigned count = 0;
return result;
}
-unsigned time_lw_IJKL(void)
+unsigned time_lw_IJKL()
{
unsigned result = 0;
#include "times.h"
-static unsigned test(void)
+static unsigned test()
{
// Determinant of a sparse matrix that comes up in graph theory:
symbol x1("x1"), x2("x2"), x3("x3"), x4("x4"), x5("x5");
return 0;
}
-unsigned time_lw_M1(void)
+unsigned time_lw_M1()
{
unsigned result = 0;
unsigned count = 0;
static const bool do_test = false; // set to true in order to run this beast
-static unsigned test(void)
+static unsigned test()
{
// Determinant of a sparse matrix that comes up in graph theory:
symbol x1("x1"), x2("x2"), x3("x3"), x4("x4"), x5("x5");
return 0;
}
-unsigned time_lw_M2(void)
+unsigned time_lw_M2()
{
unsigned result = 0;
unsigned count = 0;
static const bool do_test = false; // set to true in order to run this beast
-static unsigned test(void)
+static unsigned test()
{
symbol p11("p11"), p12("p12"), p21("p21"), p22("p22");
symbol a12("a12"), a21("a21"), a22("a22");
return 0;
}
-unsigned time_lw_N(void)
+unsigned time_lw_N()
{
unsigned result = 0;
unsigned count = 0;
static const bool do_test = true; // set to true in order to run this beast
-static unsigned test1(void)
+static unsigned test1()
{
symbol a1("a1"), a2("a2"), a3("a3"), a4("a4"), a5("a5"), a6("a6");
symbol b1("b1"), b2("b2"), b3("b3"), b4("b4"), b5("b5"), b6("b6");
return 0;
}
-unsigned time_lw_O(void)
+unsigned time_lw_O()
{
unsigned result = 0;
unsigned count = 0;
#include "times.h"
-static unsigned test(void)
+static unsigned test()
{
// This is a pattern that comes up in graph theory:
const unsigned n = 10;
return 0;
}
-unsigned time_lw_P(void)
+unsigned time_lw_P()
{
unsigned result = 0;
unsigned count = 0;
#include "times.h"
-static unsigned test(void)
+static unsigned test()
{
// create the matrix from test P...
const unsigned n = 10;
return 0;
}
-unsigned time_lw_Pprime(void)
+unsigned time_lw_Pprime()
{
unsigned result = 0;
unsigned count = 0;
#include "times.h"
-static const bool do_test = false; // set to true in order to run this beast
+static const bool do_test = true; // set to true in order to run this beast
-static unsigned test(void)
+static unsigned test()
{
// same matrix as in test P:
const unsigned n = 10;
return 0;
}
-unsigned time_lw_Q(void)
+unsigned time_lw_Q()
{
unsigned result = 0;
unsigned count = 0;
#include "times.h"
-static const bool do_test = false; // set to true in order to run this beast
+static const bool do_test = true; // set to true in order to run this beast
-static unsigned test(void)
+static unsigned test()
{
// same matrix as in test P':
const unsigned n = 10;
return 0;
}
-unsigned time_lw_Qprime(void)
+unsigned time_lw_Qprime()
{
unsigned result = 0;
unsigned count = 0;
return result;
}
-unsigned time_toeplitz(void)
+unsigned time_toeplitz()
{
unsigned result = 0;
return result;
}
-unsigned time_vandermonde(void)
+unsigned time_vandermonde()
{
unsigned result = 0;
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "times.h"
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <unistd.h>
-timer::timer(void) : on(false)
+#include "timer.h"
+
+timer::timer() : on(false)
{
getrusage(RUSAGE_SELF, &used1);
getrusage(RUSAGE_SELF, &used2);
}
-void timer::start(void)
+void timer::start()
{
on = true;
getrusage(RUSAGE_SELF, &used1);
getrusage(RUSAGE_SELF, &used2);
}
-void timer::stop(void)
+void timer::stop()
{
on = false;
getrusage(RUSAGE_SELF, &used2);
}
-void timer::reset(void)
+void timer::reset()
{
getrusage(RUSAGE_SELF, &used1);
getrusage(RUSAGE_SELF, &used2);
}
-double timer::read(void)
+double timer::read()
{
double elapsed;
if (this->running())
return 0.01*int(elapsed*100+0.5);
}
-bool timer::running(void)
+bool timer::running()
{
return on;
}
--- /dev/null
+/** @file timer.h
+ *
+ * A simple stop watch class. */
+
+/*
+ * GiNaC Copyright (C) 1999-2003 Johannes Gutenberg University Mainz, Germany
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef TIMER_H
+#define TIMER_H
+
+#include <sys/resource.h>
+
+class timer {
+public:
+ timer();
+ void start();
+ void stop();
+ void reset();
+ double read();
+ bool running();
+private:
+ bool on;
+ struct rusage used1, used2;
+};
+
+#endif // ndef TIMER_H
#ifndef CHECKS_H
#define CHECKS_H
-#include <sys/resource.h>
#include <cstdlib>
#include <iostream>
#include <sstream>
using namespace std;
using namespace GiNaC;
-class timer {
-public:
- timer();
- void start(void);
- void stop(void);
- void reset(void);
- double read(void);
- bool running(void);
-private:
- bool on;
- struct rusage used1, used2;
-};
+#include "timer.h"
// prototypes for all individual timings should be unsigned fcn():
unsigned time_dennyfliegner();
dnl (don't we all *love* M4?)...
GINACLIB_MAJOR_VERSION=1
-GINACLIB_MINOR_VERSION=0
-GINACLIB_MICRO_VERSION=14
-GINACLIB_INTERFACE_AGE=1
-GINACLIB_BINARY_AGE=14
+GINACLIB_MINOR_VERSION=2
+GINACLIB_MICRO_VERSION=0
+GINACLIB_INTERFACE_AGE=0
+GINACLIB_BINARY_AGE=0
GINACLIB_VERSION=$GINACLIB_MAJOR_VERSION.$GINACLIB_MINOR_VERSION.$GINACLIB_MICRO_VERSION
AC_SUBST(GINACLIB_MAJOR_VERSION)
AC_CHECK_HEADER(typeinfo, , GINAC_ERROR([The standard <typeinfo> header file could not be found.]))
AC_CHECK_HEADER(stdexcept, , GINAC_ERROR([The standard <stdexcept> header file could not be found.]))
AC_CHECK_HEADER(algorithm, , GINAC_ERROR([The standard <algorithm> header file could not be found.]))
+AC_CHECK_HEADER(limits, , GINAC_ERROR([The standard <limits> header file could not be found.]))
dnl We need to have Bruno Haible's CLN installed.
dnl (CLN versions >= 1.1.0 must have installed cln.m4 at a visible place,
-ginac (1.0.14-1) unstable; urgency=low
+ginac (1.1.0-1) unstable; urgency=low
- * New upstream (bugfix only) release.
-
- -- Christian Bauer <cbauer@ginac.de> Sat, 1 Mar 2003 17:29:13 +0100
+ * New upstream release; binary incompatible, so it's libginac1.1 now.
+ * Adjusted to Standards-Version 3.5.8.
-ginac (1.0.13-1) unstable; urgency=low
-
- * New upstream (bugfix only) release.
-
- -- Christian Bauer <cbauer@ginac.de> Mon, 27 Jan 2003 17:56:07 +0100
-
-ginac (1.0.12-1) unstable; urgency=low
-
- * New upstream (bugfix only) release.
-
- -- Christian Bauer <cbauer@ginac.de> Thu, 31 Oct 2002 16:21:05 +0100
+ -- Richard Kreckel <kreckel@ginac.de> Thu, 4 Apr 2003 12:11:21 +0200
ginac (1.0.11-1) unstable; urgency=low
* New upstream (bugfix only) release.
- -- Richard Kreckel <kreckel@ginac.de> Wed, 18 Sep 2002 16:45:05 +0200
-
-ginac (1.0.10-1) unstable; urgency=low
-
- * New upstream (bugfix only) release.
-
- -- Richard Kreckel <kreckel@ginac.de> Wed, 24 Jul 2002 18:03:00 +0200
+ -- Richard Kreckel <kreckel@ginac.de> Wed, 18 Sep 2002 16:45:05 +0100
ginac (1.0.8-1) unstable; urgency=low
Section: math
Priority: optional
Maintainer: Richard Kreckel <kreckel@ginac.de>
-Standards-Version: 3.1.1
-Build-Depends: debhelper, libcln-dev, libgmp3-dev, libreadline4-dev, flex, bison
+Build-Depends: debhelper (>> 3.0.0), libcln-dev, libgmp3-dev, libreadline4-dev, flex, bison
+Standards-Version: 3.5.8
-Package: libginac0
+Package: libginac1.1
Architecture: any
Section: libs
Depends: ${shlibs:Depends}
programming language.
.
This package provides the runtime library. See <http://www.ginac.de/> for
- detailed information about the GiNaC framework.
+ detailed information about GiNaC.
Package: libginac-dev
Architecture: any
-Section: devel
-Depends: libginac0 (= ${Source-Version}), libc6-dev, g++, libcln-dev
+Section: libdevel
+Depends: libginac1.1 (= ${Source-Version}), libc6-dev, g++, libcln-dev
Recommends: info | info-browser
Suggests: ginac-tools
Description: The GiNaC framework (development files)
programming language.
.
This package provides header files, a static library plus a tutorial as info
- file. See <http://www.ginac.de/> for detailed information about the GiNaC
- framework.
+ file. See <http://www.ginac.de/> for detailed information about GiNaC.
Package: ginac-tools
Architecture: any
.
This package provides some additional tools, like the popular ginsh (GiNaC
interactive shell) and viewgar (for inspecting GiNaC archive files). See
- <http://www.ginac.de/> for detailed information about the GiNaC framework.
+ <http://www.ginac.de/> for detailed information about GiNaC.
-This package was debianized by Richard Kreckel kreckel@ginac.de on
+This package was debianized by Richard Kreckel <kreckel@ginac.de> on
Thu, 29 Mar 2001 20:30:40 +0100.
It was downloaded from <http://www.ginac.de/>
--- /dev/null
+NEWS
+README
+AUTHORS
#!/bin/sh
set -e
-install-info --quiet --section Math Math -- /usr/share/info/ginac.info
+
+if [ "$1" = "configure" ]; then
+ install-info --quiet --section Math Math -- /usr/share/info/ginac.info
+fi
#DEBHELPER#
--- /dev/null
+usr/lib/libginac*.so.*
+++ /dev/null
-#!/bin/sh
-set -e
-if [ "$1" = "configure" ]; then
- ldconfig
-fi
-#DEBHELPER#
#!/usr/bin/make -f
-package=ginac
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
-version=$(shell expr `pwd` : '.*-\([0-9.]*\)')
-version_major=$(shell expr `pwd` : '.*-\([0-9]*\).[0-9.]*')
+# This is the debhelper compatability version to use.
+export DH_COMPAT=4
+# This has to be exported to make some magic below work.
+export DH_OPTIONS
-build:
+# These are used for cross-compiling and for saving the configure script
+# from having to guess our platform (since we know it already)
+DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
+DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
+
+
+ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS)))
+ export CXXFLAGS = -O0
+else
+ export CXXFLAGS = -O2 -fomit-frame-pointer -finline-limit=1200
+endif
+ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
+ INSTALL_PROGRAM += -s
+endif
+
+config.status: configure
dh_testdir
- ./configure --prefix=/usr
- $(MAKE) CXXFLAGS="-O2"
- touch build
+ # Add here commands to configure the package.
+ ./configure --host=$(DEB_HOST_GNU_TYPE) --build=$(DEB_BUILD_GNU_TYPE) --prefix=/usr --mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info
+
+build: build-arch
+
+build-arch: build-arch-stamp
+build-arch-stamp: config.status
+ # Add here commands to compile the arch part of the package.
+ $(MAKE) prefix=$(CURDIR)/debian/tmp/usr infodir=$(CURDIR)/debian/tmp/usr/share/info mandir=$(CURDIR)/debian/tmp/usr/share/man
clean:
dh_testdir
- dh_clean
- -rm -f build
+ dh_testroot
+ rm -f build-arch-stamp config-stamp
-$(MAKE) distclean
- -rm -f `find . -name "*~"`
- -rm -rf debian/tmp `find debian/* -type d ! -name CVS` debian/files* core
- -rm -f debian/*substvars
+ dh_clean
-binary-indep: build
+install: install-arch
+install-arch:
dh_testdir
dh_testroot
+ dh_clean -k -a
+ dh_installdirs -a
+ # Add here commands to install the arch part of the package into
+ # debian/tmp.
+ $(MAKE) install prefix=$(CURDIR)/debian/tmp/usr
+ mkdir -p $(CURDIR)/debian/tmp/usr/X11R6/include/X11/pixmaps
+ cp $(CURDIR)/debian/ginac.xpm $(CURDIR)/debian/tmp/usr/X11R6/include/X11/pixmaps/
-binary-arch: build
+# Must not depend on anything. This is to be called by
+# binary-arch/binary-multi
+# in another 'make' thread.
+binary-common:
dh_testdir
dh_testroot
- dh_installdirs
- # When is Automake going to honor FHS?
- $(MAKE) install prefix=`pwd`/debian/tmp/usr infodir=`pwd`/debian/tmp/usr/share/info mandir=`pwd`/debian/tmp/usr/share/man
- # Automake generated Makefile.in do install-info, which is bad for us:
- -rm -f `pwd`/debian/tmp/usr/share/info/dir*
- dh_installdocs ChangeLog NEWS README
- dh_installchangelogs
+ dh_installdocs
dh_installmenu
- mkdir -p `pwd`/debian/tmp/usr/X11R6/include/X11/pixmaps
- cp `pwd`/debian/ginac.xpm `pwd`/debian/tmp/usr/X11R6/include/X11/pixmaps/
+ dh_installman
+ dh_installinfo
+ dh_installchangelogs ChangeLog
dh_movefiles
+ dh_link
dh_strip
dh_compress
dh_fixperms
dh_makeshlibs
- dh_installdeb
- dh_shlibdeps
+ dh_shlibdeps --libpackage=libginac1.1 -l debian/libginac1.1/usr/lib
dh_gencontrol
+ dh_installdeb
dh_md5sums
dh_builddeb
-binary: binary-indep binary-arch
+# Build architecture dependant packages using the common target.
+binary-arch: build-arch install-arch
+ $(MAKE) -f debian/rules DH_OPTIONS=-a binary-common
-.PHONY: binary binary-arch binary-indep clean
+binary: binary-arch
+.PHONY: build clean binary-arch binary install install-arch
-libginac-1.0 0 libginac0 (>= 1.0.0)
+libginac-1.1 0 libginac1.1 (>= 1.1.0)
-# Doxyfile 1.2.5
+# Doxyfile 1.2.18
-# This file describes the settings to be used by doxygen for a project
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
#
# All text after a hash (#) is considered a comment and will be ignored
# The format is:
#---------------------------------------------------------------------------
# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
-# by quotes) that should identify the project.
+# by quotes) that should identify the project.
PROJECT_NAME = GiNaC
# If a relative path is entered, it will be relative to the location
# where doxygen was started. If left blank the current directory will be used.
-OUTPUT_DIRECTORY = .
+OUTPUT_DIRECTORY =
# The OUTPUT_LANGUAGE tag is used to specify the language in which all
# documentation generated by doxygen is written. Doxygen will use this
# information to generate all constant output in the proper language.
# The default language is English, other supported languages are:
-# Dutch, French, Italian, Czech, Swedish, German, Finnish, Japanese,
-# Korean, Hungarian, Norwegian, Spanish, Romanian, Russian, Croatian,
-# Polish, Portuguese and Slovene.
+# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch,
+# Finnish, French, German, Greek, Hungarian, Italian, Japanese, Japanese-en
+# (Japanese with english messages), Korean, Norwegian, Polish, Portuguese,
+# Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish and Ukrainian.
OUTPUT_LANGUAGE = English
# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
# documentation are documented, even if no documentation was available.
# Private class members and static file members will be hidden unless
-# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
EXTRACT_ALL = YES
# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
-# will be included in the documentation.
+# will be included in the documentation.
EXTRACT_PRIVATE = YES
# If the EXTRACT_STATIC tag is set to YES all static members of a file
-# will be included in the documentation.
+# will be included in the documentation.
EXTRACT_STATIC = YES
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = YES
+
# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
# undocumented members of documented classes, files or namespaces.
# If set to NO (the default) these members will be included in the
# various overviews, but no documentation section is generated.
-# This option has no effect if EXTRACT_ALL is enabled.
+# This option has no effect if EXTRACT_ALL is enabled.
HIDE_UNDOC_MEMBERS = NO
# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
# undocumented classes that are normally visible in the class hierarchy.
# If set to NO (the default) these class will be included in the various
-# overviews. This option has no effect if EXTRACT_ALL is enabled.
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
HIDE_UNDOC_CLASSES = NO
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
# include brief member descriptions after the members that are listed in
# the file and class documentation (similar to JavaDoc).
-# Set to NO to disable this.
+# Set to NO to disable this.
BRIEF_MEMBER_DESC = YES
# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
# the brief description of a member or function before the detailed description.
# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
-# brief descriptions will be completely suppressed.
+# brief descriptions will be completely suppressed.
REPEAT_BRIEF = YES
# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
# Doxygen will generate a detailed section even if there is only a brief
-# description.
+# description.
ALWAYS_DETAILED_SEC = NO
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited
+# members of a class in the documentation of that class as if those members were
+# ordinary class members. Constructors, destructors and assignment operators of
+# the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
# path before files name in the file list and in the header files. If set
-# to NO the shortest path that makes the file name unique will be used.
+# to NO the shortest path that makes the file name unique will be used.
FULL_PATH_NAMES = NO
# The INTERNAL_DOCS tag determines if documentation
# that is typed after a \internal command is included. If the tag is set
# to NO (the default) then the documentation will be excluded.
-# Set it to YES to include the internal documentation.
+# Set it to YES to include the internal documentation.
INTERNAL_DOCS = NO
-# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
-# generate a class diagram (in Html and LaTeX) for classes with base or
-# super classes. Setting the tag to NO turns the diagrams off.
-
-CLASS_DIAGRAMS = YES
-
-# If the SOURCE_BROWSER tag is set to YES then a list of source files will
-# be generated. Documented entities will be cross-referenced with these sources.
-
-SOURCE_BROWSER = YES
-
-# Setting the INLINE_SOURCES tag to YES will include the body
-# of functions and classes directly in the documentation.
-
-INLINE_SOURCES = NO
-
# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
# doxygen to hide any special comment blocks from generated source code
-# fragments. Normal C and C++ comments will always remain visible.
+# fragments. Normal C and C++ comments will always remain visible.
STRIP_CODE_COMMENTS = YES
CASE_SENSE_NAMES = YES
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
# will show members with their full class and namespace scopes in the
-# documentation. If set to YES the scope will be hidden.
+# documentation. If set to YES the scope will be hidden.
HIDE_SCOPE_NAMES = NO
# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
# will generate a verbatim copy of the header file for each class for
-# which an include is specified. Set to NO to disable this.
+# which an include is specified. Set to NO to disable this.
VERBATIM_HEADERS = NO
# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
# will put list of the files that are included by a file in the documentation
-# of that file.
+# of that file.
SHOW_INCLUDE_FILES = YES
# will interpret the first line (until the first dot) of a JavaDoc-style
# comment as the brief description. If set to NO, the JavaDoc
# comments will behave just like the Qt-style comments (thus requiring an
-# explict @brief command for a brief description.
+# explict @brief command for a brief description.
JAVADOC_AUTOBRIEF = YES
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member
+# documentation.
+
+DETAILS_AT_TOP = NO
+
# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
# member inherits the documentation from any documented member that it
-# reimplements.
+# reimplements.
INHERIT_DOCS = YES
# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
-# is inserted in the documentation for inline members.
+# is inserted in the documentation for inline members.
INLINE_INFO = YES
# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
# will sort the (detailed) documentation of file and class members
# alphabetically by member name. If set to NO the members will appear in
-# declaration order.
+# declaration order.
SORT_MEMBER_DOCS = NO
DISTRIBUTE_GROUP_DOC = NO
# The TAB_SIZE tag can be used to set the number of spaces in a tab.
-# Doxygen uses this value to replace tabs by spaces in code fragments.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
TAB_SIZE = 4
-# The ENABLE_SECTIONS tag can be used to enable conditional
-# documentation sections, marked by \if sectionname ... \endif.
-
-ENABLED_SECTIONS =
-
# The GENERATE_TODOLIST tag can be used to enable (YES) or
# disable (NO) the todo list. This list is created by putting \todo
# commands in the documentation.
GENERATE_TESTLIST = NO
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = NO
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= NO
+
# This tag can be used to specify a number of aliases that acts
# as commands in the documentation. An alias has the form "name=value".
# For example adding "sideeffect=\par Side Effects:\n" will allow you to
# put the command \sideeffect (or @sideeffect) in the documentation, which
# will result in a user defined paragraph with heading "Side Effects:".
-# You can put \n's in the value part of an alias to insert newlines.
+# You can put \n's in the value part of an alias to insert newlines.
ALIASES =
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
# the initial value of a variable or define consist of for it to appear in
# the documentation. If the initializer consists of more lines than specified
# here it will be hidden. Use a value of 0 to hide initializers completely.
# The appearance of the initializer of individual variables and defines in the
# documentation can be controlled using \showinitializer or \hideinitializer
-# command in the documentation regardless of this setting.
+# command in the documentation regardless of this setting.
MAX_INITIALIZER_LINES = 30
# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
# only. Doxygen will then generate output that is more tailored for C.
# For instance some of the names that are used will be different. The list
-# of all members will be omitted, etc.
+# of all members will be omitted, etc.
OPTIMIZE_OUTPUT_FOR_C = NO
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources
+# only. Doxygen will then generate output that is more tailored for Java.
+# For instance namespaces will be presented as packages, qualified scopes
+# will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
#---------------------------------------------------------------------------
# configuration options related to warning and progress messages
#---------------------------------------------------------------------------
# The QUIET tag can be used to turn on/off the messages that are generated
-# by doxygen. Possible values are YES and NO. If left blank NO is used.
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
QUIET = NO
# The WARNINGS tag can be used to turn on/off the warning messages that are
# generated by doxygen. Possible values are YES and NO. If left blank
-# NO is used.
+# NO is used.
WARNINGS = NO
# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
-# automatically be disabled.
+# automatically be disabled.
WARN_IF_UNDOCUMENTED = YES
# The WARN_FORMAT tag determines the format of the warning messages that
# doxygen can produce. The string should contain the $file, $line, and $text
# tags, which will be replaced by the file and line number from which the
-# warning originated and the warning text.
+# warning originated and the warning text.
WARN_FORMAT = "$file:$line: $text"
# The WARN_LOGFILE tag can be used to specify a file to which warning
# and error messages should be written. If left blank the output is written
-# to stderr.
+# to stderr.
WARN_LOGFILE =
# The INPUT tag can be used to specify the files and/or directories that contain
# documented source files. You may enter file names like "myfile.cpp" or
# directories like "/usr/src/myproject". Separate the files or directories
-# with spaces.
+# with spaces.
INPUT = ../../ginac
# If the value of the INPUT tag contains directories, you can use the
# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
# and *.h) to filter out the source-files in the directories. If left
-# blank all files are included.
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp
+# *.h++ *.idl *.odl
FILE_PATTERNS = *.cpp *.h
# The RECURSIVE tag can be used to turn specify whether or not subdirectories
# should be searched for input files as well. Possible values are YES and NO.
-# If left blank NO is used.
+# If left blank NO is used.
RECURSIVE = NO
# The EXCLUDE tag can be used to specify files and/or directories that should
# excluded from the INPUT source files. This way you can easily exclude a
-# subdirectory from a directory tree whose root is specified with the INPUT tag.
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
EXCLUDE =
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories
+# that are symbolic links (a Unix filesystem feature) are excluded from the input.
+
+EXCLUDE_SYMLINKS = NO
+
# If the value of the INPUT tag contains directories, you can use the
# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
-# certain files from those directories.
+# certain files from those directories.
EXCLUDE_PATTERNS =
# The EXAMPLE_PATH tag can be used to specify one or more files or
# directories that contain example code fragments that are included (see
-# the \include command).
+# the \include command).
EXAMPLE_PATH =
# If the value of the EXAMPLE_PATH tag contains directories, you can use the
# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
# and *.h) to filter out the source-files in the directories. If left
-# blank all files are included.
+# blank all files are included.
EXAMPLE_PATTERNS =
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
# The IMAGE_PATH tag can be used to specify one or more files or
# directories that contain image that are included in the documentation (see
-# the \image command).
+# the \image command).
IMAGE_PATH =
# by executing (via popen()) the command <filter> <input-file>, where <filter>
# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
# input file. Doxygen will then use the output that the filter program writes
-# to standard output.
+# to standard output.
INPUT_FILTER =
# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
# INPUT_FILTER) will be used to filter the input files when producing source
-# files to browse.
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
FILTER_SOURCE_FILES = NO
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+
+SOURCE_BROWSER = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default)
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES (the default)
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = YES
+
#---------------------------------------------------------------------------
# configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
# of all compounds will be generated. Enable this if the project
-# contains a lot of classes, structs, unions or interfaces.
+# contains a lot of classes, structs, unions or interfaces.
ALPHABETICAL_INDEX = YES
# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
-# in which this list will be split (can be a number in the range [1..20])
+# in which this list will be split (can be a number in the range [1..20])
COLS_IN_ALPHA_INDEX = 5
# In case all classes in a project start with a common prefix, all
# classes will be put under the same header in the alphabetical index.
# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
-# should be ignored while generating the index headers.
+# should be ignored while generating the index headers.
IGNORE_PREFIX =
#---------------------------------------------------------------------------
# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
-# generate HTML output.
+# generate HTML output.
GENERATE_HTML = YES
# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `html' will be used as the default path.
+# put in front of it. If left blank `html' will be used as the default path.
HTML_OUTPUT = .
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
# The HTML_HEADER tag can be used to specify a personal HTML header for
# each generated HTML page. If it is left blank doxygen will generate a
# standard header.
# The HTML_STYLESHEET tag can be used to specify a user defined cascading
# style sheet that is used by each HTML page. It can be used to
# fine-tune the look of the HTML output. If the tag is left blank doxygen
-# will generate a default style sheet
+# will generate a default style sheet
HTML_STYLESHEET =
# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
# files or namespaces will be aligned in HTML using tables. If set to
-# NO a bullet list will be used.
+# NO a bullet list will be used.
HTML_ALIGN_MEMBERS = YES
# If the GENERATE_HTMLHELP tag is set to YES, additional index files
# will be generated that can be used as input for tools like the
# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)
-# of the generated HTML documentation.
+# of the generated HTML documentation.
GENERATE_HTMLHELP = NO
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output dir.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non empty doxygen will try to run
+# the html help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the Html help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
# top of each HTML page. The value NO (the default) enables the index and
-# the value YES disables it.
+# the value YES disables it.
DISABLE_INDEX = NO
# This tag can be used to set the number of enum values (range [1..20])
-# that doxygen will group on one line in the generated HTML documentation.
+# that doxygen will group on one line in the generated HTML documentation.
ENUM_VALUES_PER_LINE = 4
# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
# generated containing a tree-like index structure (just like the one that
# is generated for HTML Help). For this to work a browser that supports
-# JavaScript and frames is required (for instance Netscape 4.0+
-# or Internet explorer 4.0+).
+# JavaScript and frames is required (for instance Mozilla, Netscape 4.0+,
+# or Internet explorer 4.0+). Note that for large projects the tree generation
+# can take a very long time. In such cases it is better to disable this feature.
+# Windows users are probably better off using the HTML help feature.
GENERATE_TREEVIEW = NO
#---------------------------------------------------------------------------
# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
-# generate Latex output.
+# generate Latex output.
GENERATE_LATEX = NO
# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `latex' will be used as the default path.
+# put in front of it. If left blank `latex' will be used as the default path.
LATEX_OUTPUT = latex
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
# LaTeX documents. This may be useful for small projects and may help to
-# save some trees in general.
+# save some trees in general.
COMPACT_LATEX = NO
# The PAPER_TYPE tag can be used to set the paper type that is used
# by the printer. Possible values are: a4, a4wide, letter, legal and
-# executive. If left blank a4wide will be used.
+# executive. If left blank a4wide will be used.
PAPER_TYPE = a4wide
# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
-# packages that should be included in the LaTeX output.
+# packages that should be included in the LaTeX output.
EXTRA_PACKAGES =
# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
# the generated latex document. The header should contain everything until
# the first chapter. If it is left blank doxygen will generate a
-# standard header. Notice: only use this tag if you know what you are doing!
+# standard header. Notice: only use this tag if you know what you are doing!
LATEX_HEADER =
# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
# is prepared for conversion to pdf (using ps2pdf). The pdf file will
# contain links (just like the HTML output) instead of page references
-# This makes the output suitable for online browsing using a pdf viewer.
+# This makes the output suitable for online browsing using a pdf viewer.
PDF_HYPERLINKS = NO
# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
# plain latex in the generated Makefile. Set this option to YES to get a
-# higher quality PDF documentation.
+# higher quality PDF documentation.
USE_PDFLATEX = NO
# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
# command to the generated LaTeX files. This will instruct LaTeX to keep
# running if errors occur, instead of asking the user for help.
-# This option is also used when generating formulas in HTML.
+# This option is also used when generating formulas in HTML.
LATEX_BATCHMODE = NO
# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `rtf' will be used as the default path.
+# put in front of it. If left blank `rtf' will be used as the default path.
RTF_OUTPUT = rtf
# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
# RTF documents. This may be useful for small projects and may help to
-# save some trees in general.
+# save some trees in general.
COMPACT_RTF = NO
# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
# will contain hyperlink fields. The RTF file will
# contain links (just like the HTML output) instead of page references.
-# This makes the output suitable for online browsing using a WORD or other.
+# This makes the output suitable for online browsing using WORD or other
# programs which support those fields.
-# Note: wordpad (write) and others do not support links.
+# Note: wordpad (write) and others do not support links.
RTF_HYPERLINKS = NO
# Load stylesheet definitions from file. Syntax is similar to doxygen's
# config file, i.e. a series of assigments. You only have to provide
-# replacements, missing definitions are set to their default value.
+# replacements, missing definitions are set to their default value.
RTF_STYLESHEET_FILE =
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
#---------------------------------------------------------------------------
# configuration options related to the man page output
#---------------------------------------------------------------------------
# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
-# generate man pages
+# generate man pages
GENERATE_MAN = NO
# The MAN_OUTPUT tag is used to specify where the man pages will be put.
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `man' will be used as the default path.
+# put in front of it. If left blank `man' will be used as the default path.
MAN_OUTPUT = man
# The MAN_EXTENSION tag determines the extension that is added to
-# the generated man pages (default is the subroutine's section .3)
+# the generated man pages (default is the subroutine's section .3)
MAN_EXTENSION = .3
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_XML = NO
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
#---------------------------------------------------------------------------
# Configuration options related to the preprocessor
#---------------------------------------------------------------------------
# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
# evaluate all C-preprocessor directives found in the sources and include
-# files.
+# files.
ENABLE_PREPROCESSING = YES
# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
# names in the source code. If set to NO (the default) only conditional
# compilation will be performed. Macro expansion can be done in a controlled
-# way by setting EXPAND_ONLY_PREDEF to YES.
+# way by setting EXPAND_ONLY_PREDEF to YES.
MACRO_EXPANSION = YES
# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
# then the macro expansion is limited to the macros specified with the
-# PREDEFINED and EXPAND_AS_PREDEFINED tags.
+# PREDEFINED and EXPAND_AS_PREDEFINED tags.
EXPAND_ONLY_PREDEF = YES
# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
-# in the INCLUDE_PATH (see below) will be search if a #include is found.
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
SEARCH_INCLUDES = YES
# The INCLUDE_PATH tag can be used to specify one or more directories that
# contain include files that are not input files but should be processed by
-# the preprocessor.
+# the preprocessor.
INCLUDE_PATH =
# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
# patterns (like *.h and *.hpp) to filter out the header-files in the
# directories. If left blank, the patterns specified with FILE_PATTERNS will
-# be used.
+# be used.
-INCLUDE_FILE_PATTERNS = *.h
+INCLUDE_FILE_PATTERNS = *.h
# The PREDEFINED tag can be used to specify one or more macro names that
# are defined before the preprocessor is started (similar to the -D option of
# gcc). The argument of the tag is a list of macros of the form: name
# or name=definition (no spaces). If the definition and the = are
-# omitted =1 is assumed.
+# omitted =1 is assumed.
PREDEFINED = "GINAC_DECLARE_REGISTERED_CLASS_NO_CTORS(class, base)=" \
"GINAC_DECLARE_REGISTERED_CLASS(class, base)="
# If the MACRO_EXPANSION and EXPAND_PREDEF_ONLY tags are set to YES then
# this tag can be used to specify a list of macro names that should be expanded.
# The macro definition that is found in the sources will be used.
-# Use the PREDEFINED tag if you want to use a different macro definition.
+# Use the PREDEFINED tag if you want to use a different macro definition.
EXPAND_AS_DEFINED =
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse the
+# parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
#---------------------------------------------------------------------------
# Configuration::addtions related to external references
#---------------------------------------------------------------------------
-# The TAGFILES tag can be used to specify one or more tagfiles.
+# The TAGFILES tag can be used to specify one or more tagfiles.
TAGFILES =
# When a file name is specified after GENERATE_TAGFILE, doxygen will create
-# a tag file that is based on the input files it reads.
+# a tag file that is based on the input files it reads.
GENERATE_TAGFILE =
# If the ALLEXTERNALS tag is set to YES all external classes will be listed
# in the class index. If set to NO only the inherited external classes
-# will be listed.
+# will be listed.
ALLEXTERNALS = NO
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
# The PERL_PATH should be the absolute path and name of the perl script
-# interpreter (i.e. the result of `which perl').
+# interpreter (i.e. the result of `which perl').
PERL_PATH = /usr/bin/perl
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in Html, RTF and LaTeX) for classes with base or
+# super classes. Setting the tag to NO turns the diagrams off. Note that this
+# option is superceded by the HAVE_DOT option below. This is only a fallback. It is
+# recommended to install and use dot, since it yield more powerful graphs.
+
+CLASS_DIAGRAMS = YES
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
# available from the path. This tool is part of Graphviz, a graph visualization
# toolkit from AT&T and Lucent Bell Labs. The other options in this section
-# have no effect if this option is set to NO (the default)
+# have no effect if this option is set to NO (the default)
HAVE_DOT = NO
# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
# will generate a graph for each documented class showing the direct and
# indirect implementation dependencies (inheritance, containment, and
-# class references variables) of the class with other documented classes.
+# class references variables) of the class with other documented classes.
COLLABORATION_GRAPH = YES
-# If the ENABLE_PREPROCESSING, INCLUDE_GRAPH, and HAVE_DOT tags are set to
-# YES then doxygen will generate a graph for each documented file showing
-# the direct and indirect include dependencies of the file with other
-# documented files.
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
INCLUDE_GRAPH = YES
-# If the ENABLE_PREPROCESSING, INCLUDED_BY_GRAPH, and HAVE_DOT tags are set to
-# YES then doxygen will generate a graph for each documented header file showing
-# the documented files that directly or indirectly include this file
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
INCLUDED_BY_GRAPH = YES
# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
-# will graphical hierarchy of all classes instead of a textual one.
+# will graphical hierarchy of all classes instead of a textual one.
GRAPHICAL_HIERARCHY = YES
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT = png
+
# The tag DOT_PATH can be used to specify the path where the dot tool can be
-# found. If left blank, it is assumed the dot tool can be found on the path.
+# found. If left blank, it is assumed the dot tool can be found on the path.
DOT_PATH =
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width
# (in pixels) of the graphs generated by dot. If a graph becomes larger than
# this value, doxygen will try to truncate the graph, so that it fits within
# the specified constraint. Beware that most browsers cannot cope with very
-# large images.
+# large images.
MAX_DOT_GRAPH_WIDTH = 1024
# (in pixels) of the graphs generated by dot. If a graph becomes larger than
# this value, doxygen will try to truncate the graph, so that it fits within
# the specified constraint. Beware that most browsers cannot cope with very
-# large images.
+# large images.
MAX_DOT_GRAPH_HEIGHT = 1024
# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
# generate a legend page explaining the meaning of the various boxes and
-# arrows in the dot generated graphs.
+# arrows in the dot generated graphs.
GENERATE_LEGEND = YES
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermedate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
+
#---------------------------------------------------------------------------
# Configuration::addtions related to the search engine
#---------------------------------------------------------------------------
# The SEARCHENGINE tag specifies whether or not a search engine should be
-# used. If set to NO the values of all tags below this one will be ignored.
+# used. If set to NO the values of all tags below this one will be ignored.
SEARCHENGINE = NO
# The CGI_NAME tag should be the name of the CGI script that
# starts the search engine (doxysearch) with the correct parameters.
-# A script with this name will be generated by doxygen.
+# A script with this name will be generated by doxygen.
CGI_NAME = search.cgi
# The CGI_URL tag should be the absolute URL to the directory where the
# cgi binaries are located. See the documentation of your http daemon for
-# details.
+# details.
CGI_URL =
# The DOC_URL tag should be the absolute URL to the directory where the
# documentation is located. If left blank the absolute path to the
-# documentation, with file:// prepended to it, will be used.
+# documentation, with file:// prepended to it, will be used.
DOC_URL =
# The DOC_ABSPATH tag should be the absolute path to the directory where the
# documentation is located. If left blank the directory on the local machine
-# will be used.
+# will be used.
DOC_ABSPATH =
# The BIN_ABSPATH tag must point to the directory where the doxysearch binary
-# is installed.
+# is installed.
-BIN_ABSPATH = /usr/local/bin/
+BIN_ABSPATH = /usr/bin/
# The EXT_DOC_PATHS tag can be used to specify one or more paths to
# documentation generated for other projects. This allows doxysearch to search
-# the documentation for these projects as well.
+# the documentation for these projects as well.
EXT_DOC_PATHS =
-# Doxyfile 1.2.5
+# Doxyfile 1.2.18
-# This file describes the settings to be used by doxygen for a project
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
#
# All text after a hash (#) is considered a comment and will be ignored
# The format is:
#---------------------------------------------------------------------------
# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
-# by quotes) that should identify the project.
+# by quotes) that should identify the project.
PROJECT_NAME = GiNaC
# If a relative path is entered, it will be relative to the location
# where doxygen was started. If left blank the current directory will be used.
-OUTPUT_DIRECTORY = .
+OUTPUT_DIRECTORY =
# The OUTPUT_LANGUAGE tag is used to specify the language in which all
# documentation generated by doxygen is written. Doxygen will use this
# information to generate all constant output in the proper language.
# The default language is English, other supported languages are:
-# Dutch, French, Italian, Czech, Swedish, German, Finnish, Japanese,
-# Korean, Hungarian, Norwegian, Spanish, Romanian, Russian, Croatian,
-# Polish, Portuguese and Slovene.
+# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch,
+# Finnish, French, German, Greek, Hungarian, Italian, Japanese, Japanese-en
+# (Japanese with english messages), Korean, Norwegian, Polish, Portuguese,
+# Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish and Ukrainian.
OUTPUT_LANGUAGE = English
# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
# documentation are documented, even if no documentation was available.
# Private class members and static file members will be hidden unless
-# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
EXTRACT_ALL = YES
# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
-# will be included in the documentation.
+# will be included in the documentation.
EXTRACT_PRIVATE = YES
# If the EXTRACT_STATIC tag is set to YES all static members of a file
-# will be included in the documentation.
+# will be included in the documentation.
EXTRACT_STATIC = YES
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = YES
+
# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
# undocumented members of documented classes, files or namespaces.
# If set to NO (the default) these members will be included in the
# various overviews, but no documentation section is generated.
-# This option has no effect if EXTRACT_ALL is enabled.
+# This option has no effect if EXTRACT_ALL is enabled.
HIDE_UNDOC_MEMBERS = NO
# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
# undocumented classes that are normally visible in the class hierarchy.
# If set to NO (the default) these class will be included in the various
-# overviews. This option has no effect if EXTRACT_ALL is enabled.
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
HIDE_UNDOC_CLASSES = NO
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
# include brief member descriptions after the members that are listed in
# the file and class documentation (similar to JavaDoc).
-# Set to NO to disable this.
+# Set to NO to disable this.
BRIEF_MEMBER_DESC = YES
# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
# the brief description of a member or function before the detailed description.
# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
-# brief descriptions will be completely suppressed.
+# brief descriptions will be completely suppressed.
REPEAT_BRIEF = YES
# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
# Doxygen will generate a detailed section even if there is only a brief
-# description.
+# description.
ALWAYS_DETAILED_SEC = NO
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited
+# members of a class in the documentation of that class as if those members were
+# ordinary class members. Constructors, destructors and assignment operators of
+# the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
# path before files name in the file list and in the header files. If set
-# to NO the shortest path that makes the file name unique will be used.
+# to NO the shortest path that makes the file name unique will be used.
FULL_PATH_NAMES = NO
# The INTERNAL_DOCS tag determines if documentation
# that is typed after a \internal command is included. If the tag is set
# to NO (the default) then the documentation will be excluded.
-# Set it to YES to include the internal documentation.
+# Set it to YES to include the internal documentation.
INTERNAL_DOCS = NO
-# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
-# generate a class diagram (in Html and LaTeX) for classes with base or
-# super classes. Setting the tag to NO turns the diagrams off.
-
-CLASS_DIAGRAMS = YES
-
-# If the SOURCE_BROWSER tag is set to YES then a list of source files will
-# be generated. Documented entities will be cross-referenced with these sources.
-
-SOURCE_BROWSER =
-
-# Setting the INLINE_SOURCES tag to YES will include the body
-# of functions and classes directly in the documentation.
-
-INLINE_SOURCES = NO
-
# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
# doxygen to hide any special comment blocks from generated source code
-# fragments. Normal C and C++ comments will always remain visible.
+# fragments. Normal C and C++ comments will always remain visible.
STRIP_CODE_COMMENTS = YES
CASE_SENSE_NAMES = YES
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
# will show members with their full class and namespace scopes in the
-# documentation. If set to YES the scope will be hidden.
+# documentation. If set to YES the scope will be hidden.
HIDE_SCOPE_NAMES = NO
# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
# will generate a verbatim copy of the header file for each class for
-# which an include is specified. Set to NO to disable this.
+# which an include is specified. Set to NO to disable this.
VERBATIM_HEADERS = NO
# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
# will put list of the files that are included by a file in the documentation
-# of that file.
+# of that file.
SHOW_INCLUDE_FILES = YES
# will interpret the first line (until the first dot) of a JavaDoc-style
# comment as the brief description. If set to NO, the JavaDoc
# comments will behave just like the Qt-style comments (thus requiring an
-# explict @brief command for a brief description.
+# explict @brief command for a brief description.
JAVADOC_AUTOBRIEF = YES
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member
+# documentation.
+
+DETAILS_AT_TOP = NO
+
# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
# member inherits the documentation from any documented member that it
-# reimplements.
+# reimplements.
INHERIT_DOCS = YES
# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
-# is inserted in the documentation for inline members.
+# is inserted in the documentation for inline members.
INLINE_INFO = YES
# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
# will sort the (detailed) documentation of file and class members
# alphabetically by member name. If set to NO the members will appear in
-# declaration order.
+# declaration order.
SORT_MEMBER_DOCS = NO
DISTRIBUTE_GROUP_DOC = NO
# The TAB_SIZE tag can be used to set the number of spaces in a tab.
-# Doxygen uses this value to replace tabs by spaces in code fragments.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
TAB_SIZE = 4
-# The ENABLE_SECTIONS tag can be used to enable conditional
-# documentation sections, marked by \if sectionname ... \endif.
-
-ENABLED_SECTIONS =
-
# The GENERATE_TODOLIST tag can be used to enable (YES) or
# disable (NO) the todo list. This list is created by putting \todo
# commands in the documentation.
GENERATE_TESTLIST = NO
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = NO
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= NO
+
# This tag can be used to specify a number of aliases that acts
# as commands in the documentation. An alias has the form "name=value".
# For example adding "sideeffect=\par Side Effects:\n" will allow you to
# put the command \sideeffect (or @sideeffect) in the documentation, which
# will result in a user defined paragraph with heading "Side Effects:".
-# You can put \n's in the value part of an alias to insert newlines.
+# You can put \n's in the value part of an alias to insert newlines.
ALIASES =
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
# the initial value of a variable or define consist of for it to appear in
# the documentation. If the initializer consists of more lines than specified
# here it will be hidden. Use a value of 0 to hide initializers completely.
# The appearance of the initializer of individual variables and defines in the
# documentation can be controlled using \showinitializer or \hideinitializer
-# command in the documentation regardless of this setting.
+# command in the documentation regardless of this setting.
MAX_INITIALIZER_LINES = 30
# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
# only. Doxygen will then generate output that is more tailored for C.
# For instance some of the names that are used will be different. The list
-# of all members will be omitted, etc.
+# of all members will be omitted, etc.
OPTIMIZE_OUTPUT_FOR_C = NO
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources
+# only. Doxygen will then generate output that is more tailored for Java.
+# For instance namespaces will be presented as packages, qualified scopes
+# will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
#---------------------------------------------------------------------------
# configuration options related to warning and progress messages
#---------------------------------------------------------------------------
# The QUIET tag can be used to turn on/off the messages that are generated
-# by doxygen. Possible values are YES and NO. If left blank NO is used.
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
QUIET = NO
# The WARNINGS tag can be used to turn on/off the warning messages that are
# generated by doxygen. Possible values are YES and NO. If left blank
-# NO is used.
+# NO is used.
WARNINGS = NO
# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
-# automatically be disabled.
+# automatically be disabled.
WARN_IF_UNDOCUMENTED = YES
# The WARN_FORMAT tag determines the format of the warning messages that
# doxygen can produce. The string should contain the $file, $line, and $text
# tags, which will be replaced by the file and line number from which the
-# warning originated and the warning text.
+# warning originated and the warning text.
WARN_FORMAT = "$file:$line: $text"
# The WARN_LOGFILE tag can be used to specify a file to which warning
# and error messages should be written. If left blank the output is written
-# to stderr.
+# to stderr.
WARN_LOGFILE =
# The INPUT tag can be used to specify the files and/or directories that contain
# documented source files. You may enter file names like "myfile.cpp" or
# directories like "/usr/src/myproject". Separate the files or directories
-# with spaces.
+# with spaces.
INPUT = ../../ginac
# If the value of the INPUT tag contains directories, you can use the
# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
# and *.h) to filter out the source-files in the directories. If left
-# blank all files are included.
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp
+# *.h++ *.idl *.odl
FILE_PATTERNS = *.cpp *.h
# The RECURSIVE tag can be used to turn specify whether or not subdirectories
# should be searched for input files as well. Possible values are YES and NO.
-# If left blank NO is used.
+# If left blank NO is used.
RECURSIVE = NO
# The EXCLUDE tag can be used to specify files and/or directories that should
# excluded from the INPUT source files. This way you can easily exclude a
-# subdirectory from a directory tree whose root is specified with the INPUT tag.
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
EXCLUDE =
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories
+# that are symbolic links (a Unix filesystem feature) are excluded from the input.
+
+EXCLUDE_SYMLINKS = NO
+
# If the value of the INPUT tag contains directories, you can use the
# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
-# certain files from those directories.
+# certain files from those directories.
EXCLUDE_PATTERNS =
# The EXAMPLE_PATH tag can be used to specify one or more files or
# directories that contain example code fragments that are included (see
-# the \include command).
+# the \include command).
EXAMPLE_PATH =
# If the value of the EXAMPLE_PATH tag contains directories, you can use the
# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
# and *.h) to filter out the source-files in the directories. If left
-# blank all files are included.
+# blank all files are included.
EXAMPLE_PATTERNS =
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
# The IMAGE_PATH tag can be used to specify one or more files or
# directories that contain image that are included in the documentation (see
-# the \image command).
+# the \image command).
IMAGE_PATH =
# by executing (via popen()) the command <filter> <input-file>, where <filter>
# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
# input file. Doxygen will then use the output that the filter program writes
-# to standard output.
+# to standard output.
INPUT_FILTER =
# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
# INPUT_FILTER) will be used to filter the input files when producing source
-# files to browse.
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
FILTER_SOURCE_FILES = NO
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+
+SOURCE_BROWSER =
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default)
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES (the default)
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = YES
+
#---------------------------------------------------------------------------
# configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
# of all compounds will be generated. Enable this if the project
-# contains a lot of classes, structs, unions or interfaces.
+# contains a lot of classes, structs, unions or interfaces.
ALPHABETICAL_INDEX = YES
# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
-# in which this list will be split (can be a number in the range [1..20])
+# in which this list will be split (can be a number in the range [1..20])
COLS_IN_ALPHA_INDEX = 5
# In case all classes in a project start with a common prefix, all
# classes will be put under the same header in the alphabetical index.
# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
-# should be ignored while generating the index headers.
+# should be ignored while generating the index headers.
IGNORE_PREFIX =
#---------------------------------------------------------------------------
# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
-# generate HTML output.
+# generate HTML output.
GENERATE_HTML = NO
# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `html' will be used as the default path.
+# put in front of it. If left blank `html' will be used as the default path.
HTML_OUTPUT = .
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
# The HTML_HEADER tag can be used to specify a personal HTML header for
# each generated HTML page. If it is left blank doxygen will generate a
# standard header.
# The HTML_STYLESHEET tag can be used to specify a user defined cascading
# style sheet that is used by each HTML page. It can be used to
# fine-tune the look of the HTML output. If the tag is left blank doxygen
-# will generate a default style sheet
+# will generate a default style sheet
HTML_STYLESHEET =
# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
# files or namespaces will be aligned in HTML using tables. If set to
-# NO a bullet list will be used.
+# NO a bullet list will be used.
HTML_ALIGN_MEMBERS = YES
# If the GENERATE_HTMLHELP tag is set to YES, additional index files
# will be generated that can be used as input for tools like the
# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)
-# of the generated HTML documentation.
+# of the generated HTML documentation.
GENERATE_HTMLHELP = NO
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output dir.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non empty doxygen will try to run
+# the html help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the Html help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
# top of each HTML page. The value NO (the default) enables the index and
-# the value YES disables it.
+# the value YES disables it.
DISABLE_INDEX = NO
# This tag can be used to set the number of enum values (range [1..20])
-# that doxygen will group on one line in the generated HTML documentation.
+# that doxygen will group on one line in the generated HTML documentation.
ENUM_VALUES_PER_LINE = 4
# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
# generated containing a tree-like index structure (just like the one that
# is generated for HTML Help). For this to work a browser that supports
-# JavaScript and frames is required (for instance Netscape 4.0+
-# or Internet explorer 4.0+).
+# JavaScript and frames is required (for instance Mozilla, Netscape 4.0+,
+# or Internet explorer 4.0+). Note that for large projects the tree generation
+# can take a very long time. In such cases it is better to disable this feature.
+# Windows users are probably better off using the HTML help feature.
GENERATE_TREEVIEW = NO
#---------------------------------------------------------------------------
# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
-# generate Latex output.
+# generate Latex output.
GENERATE_LATEX = YES
# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `latex' will be used as the default path.
+# put in front of it. If left blank `latex' will be used as the default path.
LATEX_OUTPUT = latex
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
# LaTeX documents. This may be useful for small projects and may help to
-# save some trees in general.
+# save some trees in general.
COMPACT_LATEX = NO
# The PAPER_TYPE tag can be used to set the paper type that is used
# by the printer. Possible values are: a4, a4wide, letter, legal and
-# executive. If left blank a4wide will be used.
+# executive. If left blank a4wide will be used.
PAPER_TYPE = a4wide
# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
-# packages that should be included in the LaTeX output.
+# packages that should be included in the LaTeX output.
EXTRA_PACKAGES =
# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
# the generated latex document. The header should contain everything until
# the first chapter. If it is left blank doxygen will generate a
-# standard header. Notice: only use this tag if you know what you are doing!
+# standard header. Notice: only use this tag if you know what you are doing!
LATEX_HEADER =
# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
# is prepared for conversion to pdf (using ps2pdf). The pdf file will
# contain links (just like the HTML output) instead of page references
-# This makes the output suitable for online browsing using a pdf viewer.
+# This makes the output suitable for online browsing using a pdf viewer.
PDF_HYPERLINKS = NO
# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
# plain latex in the generated Makefile. Set this option to YES to get a
-# higher quality PDF documentation.
+# higher quality PDF documentation.
USE_PDFLATEX = NO
# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
# command to the generated LaTeX files. This will instruct LaTeX to keep
# running if errors occur, instead of asking the user for help.
-# This option is also used when generating formulas in HTML.
+# This option is also used when generating formulas in HTML.
LATEX_BATCHMODE = NO
# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `rtf' will be used as the default path.
+# put in front of it. If left blank `rtf' will be used as the default path.
RTF_OUTPUT = rtf
# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
# RTF documents. This may be useful for small projects and may help to
-# save some trees in general.
+# save some trees in general.
COMPACT_RTF = NO
# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
# will contain hyperlink fields. The RTF file will
# contain links (just like the HTML output) instead of page references.
-# This makes the output suitable for online browsing using a WORD or other.
+# This makes the output suitable for online browsing using WORD or other
# programs which support those fields.
-# Note: wordpad (write) and others do not support links.
+# Note: wordpad (write) and others do not support links.
RTF_HYPERLINKS = NO
# Load stylesheet definitions from file. Syntax is similar to doxygen's
# config file, i.e. a series of assigments. You only have to provide
-# replacements, missing definitions are set to their default value.
+# replacements, missing definitions are set to their default value.
RTF_STYLESHEET_FILE =
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
#---------------------------------------------------------------------------
# configuration options related to the man page output
#---------------------------------------------------------------------------
# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
-# generate man pages
+# generate man pages
GENERATE_MAN = NO
# The MAN_OUTPUT tag is used to specify where the man pages will be put.
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `man' will be used as the default path.
+# put in front of it. If left blank `man' will be used as the default path.
MAN_OUTPUT = man
# The MAN_EXTENSION tag determines the extension that is added to
-# the generated man pages (default is the subroutine's section .3)
+# the generated man pages (default is the subroutine's section .3)
MAN_EXTENSION = .3
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_XML = NO
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
#---------------------------------------------------------------------------
# Configuration options related to the preprocessor
#---------------------------------------------------------------------------
# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
# evaluate all C-preprocessor directives found in the sources and include
-# files.
+# files.
ENABLE_PREPROCESSING = YES
# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
# names in the source code. If set to NO (the default) only conditional
# compilation will be performed. Macro expansion can be done in a controlled
-# way by setting EXPAND_ONLY_PREDEF to YES.
+# way by setting EXPAND_ONLY_PREDEF to YES.
MACRO_EXPANSION = YES
# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
# then the macro expansion is limited to the macros specified with the
-# PREDEFINED and EXPAND_AS_PREDEFINED tags.
+# PREDEFINED and EXPAND_AS_PREDEFINED tags.
EXPAND_ONLY_PREDEF = YES
# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
-# in the INCLUDE_PATH (see below) will be search if a #include is found.
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
SEARCH_INCLUDES = YES
# The INCLUDE_PATH tag can be used to specify one or more directories that
# contain include files that are not input files but should be processed by
-# the preprocessor.
+# the preprocessor.
INCLUDE_PATH =
# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
# patterns (like *.h and *.hpp) to filter out the header-files in the
# directories. If left blank, the patterns specified with FILE_PATTERNS will
-# be used.
+# be used.
-INCLUDE_FILE_PATTERNS = *.h
+INCLUDE_FILE_PATTERNS = *.h
# The PREDEFINED tag can be used to specify one or more macro names that
# are defined before the preprocessor is started (similar to the -D option of
# gcc). The argument of the tag is a list of macros of the form: name
# or name=definition (no spaces). If the definition and the = are
-# omitted =1 is assumed.
+# omitted =1 is assumed.
PREDEFINED = "GINAC_DECLARE_REGISTERED_CLASS_NO_CTORS(class, base)=" \
"GINAC_DECLARE_REGISTERED_CLASS(class, base)="
# If the MACRO_EXPANSION and EXPAND_PREDEF_ONLY tags are set to YES then
# this tag can be used to specify a list of macro names that should be expanded.
# The macro definition that is found in the sources will be used.
-# Use the PREDEFINED tag if you want to use a different macro definition.
+# Use the PREDEFINED tag if you want to use a different macro definition.
EXPAND_AS_DEFINED =
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse the
+# parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
#---------------------------------------------------------------------------
# Configuration::addtions related to external references
#---------------------------------------------------------------------------
-# The TAGFILES tag can be used to specify one or more tagfiles.
+# The TAGFILES tag can be used to specify one or more tagfiles.
TAGFILES =
# When a file name is specified after GENERATE_TAGFILE, doxygen will create
-# a tag file that is based on the input files it reads.
+# a tag file that is based on the input files it reads.
GENERATE_TAGFILE =
# If the ALLEXTERNALS tag is set to YES all external classes will be listed
# in the class index. If set to NO only the inherited external classes
-# will be listed.
+# will be listed.
ALLEXTERNALS = NO
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
# The PERL_PATH should be the absolute path and name of the perl script
-# interpreter (i.e. the result of `which perl').
+# interpreter (i.e. the result of `which perl').
PERL_PATH = /usr/bin/perl
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in Html, RTF and LaTeX) for classes with base or
+# super classes. Setting the tag to NO turns the diagrams off. Note that this
+# option is superceded by the HAVE_DOT option below. This is only a fallback. It is
+# recommended to install and use dot, since it yield more powerful graphs.
+
+CLASS_DIAGRAMS = YES
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
# available from the path. This tool is part of Graphviz, a graph visualization
# toolkit from AT&T and Lucent Bell Labs. The other options in this section
-# have no effect if this option is set to NO (the default)
+# have no effect if this option is set to NO (the default)
HAVE_DOT = NO
# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
# will generate a graph for each documented class showing the direct and
# indirect implementation dependencies (inheritance, containment, and
-# class references variables) of the class with other documented classes.
+# class references variables) of the class with other documented classes.
COLLABORATION_GRAPH = YES
-# If the ENABLE_PREPROCESSING, INCLUDE_GRAPH, and HAVE_DOT tags are set to
-# YES then doxygen will generate a graph for each documented file showing
-# the direct and indirect include dependencies of the file with other
-# documented files.
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
INCLUDE_GRAPH = NO
-# If the ENABLE_PREPROCESSING, INCLUDED_BY_GRAPH, and HAVE_DOT tags are set to
-# YES then doxygen will generate a graph for each documented header file showing
-# the documented files that directly or indirectly include this file
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
INCLUDED_BY_GRAPH = NO
# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
-# will graphical hierarchy of all classes instead of a textual one.
+# will graphical hierarchy of all classes instead of a textual one.
GRAPHICAL_HIERARCHY = YES
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT = png
+
# The tag DOT_PATH can be used to specify the path where the dot tool can be
-# found. If left blank, it is assumed the dot tool can be found on the path.
+# found. If left blank, it is assumed the dot tool can be found on the path.
DOT_PATH =
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width
# (in pixels) of the graphs generated by dot. If a graph becomes larger than
# this value, doxygen will try to truncate the graph, so that it fits within
# the specified constraint. Beware that most browsers cannot cope with very
-# large images.
+# large images.
MAX_DOT_GRAPH_WIDTH = 1024
# (in pixels) of the graphs generated by dot. If a graph becomes larger than
# this value, doxygen will try to truncate the graph, so that it fits within
# the specified constraint. Beware that most browsers cannot cope with very
-# large images.
+# large images.
MAX_DOT_GRAPH_HEIGHT = 1024
# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
# generate a legend page explaining the meaning of the various boxes and
-# arrows in the dot generated graphs.
+# arrows in the dot generated graphs.
GENERATE_LEGEND = YES
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermedate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
+
#---------------------------------------------------------------------------
# Configuration::addtions related to the search engine
#---------------------------------------------------------------------------
# The SEARCHENGINE tag specifies whether or not a search engine should be
-# used. If set to NO the values of all tags below this one will be ignored.
+# used. If set to NO the values of all tags below this one will be ignored.
SEARCHENGINE = NO
# The CGI_NAME tag should be the name of the CGI script that
# starts the search engine (doxysearch) with the correct parameters.
-# A script with this name will be generated by doxygen.
+# A script with this name will be generated by doxygen.
CGI_NAME = search.cgi
# The CGI_URL tag should be the absolute URL to the directory where the
# cgi binaries are located. See the documentation of your http daemon for
-# details.
+# details.
CGI_URL =
# The DOC_URL tag should be the absolute URL to the directory where the
# documentation is located. If left blank the absolute path to the
-# documentation, with file:// prepended to it, will be used.
+# documentation, with file:// prepended to it, will be used.
DOC_URL =
# The DOC_ABSPATH tag should be the absolute path to the directory where the
# documentation is located. If left blank the directory on the local machine
-# will be used.
+# will be used.
DOC_ABSPATH =
# The BIN_ABSPATH tag must point to the directory where the doxysearch binary
-# is installed.
+# is installed.
-BIN_ABSPATH = /usr/local/bin/
+BIN_ABSPATH = /usr/bin/
# The EXT_DOC_PATHS tag can be used to specify one or more paths to
# documentation generated for other projects. This allows doxysearch to search
-# the documentation for these projects as well.
+# the documentation for these projects as well.
EXT_DOC_PATHS =
ginacreferencedir = `test -z "@REFERENCE_TARGETS@" || echo @datadir@/doc/GiNaC/reference`
ginacreference_DATA = @REFERENCE_TARGETS@
-CLEANFILES = *.html *.gif doxygen.css *.ps latex/*
+CLEANFILES = *.html *.png doxygen.css *.ps latex/*
EXTRA_DIST = DoxyfileHTML DoxyfileTEX Doxyfooter
install-data-local:
echo " $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(ginacreferencedir)/$$p"; \
$(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(ginacreferencedir)/$$p; \
done
- @for p in `echo $(srcdir)/*.gif | sed -e 's,[^ ]*/,,g' -e 's,\*\.gif,,'`; do \
+ @for p in `echo $(srcdir)/*.png | sed -e 's,[^ ]*/,,g' -e 's,\*\.png,,'`; do \
echo " $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(ginacreferencedir)/$$p"; \
$(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(ginacreferencedir)/$$p; \
done
uninstall-local:
rm -f $(DESTDIR)$(ginacreferencedir)/doxygen.css
rm -f $(DESTDIR)$(ginacreferencedir)/*.html
- rm -f $(DESTDIR)$(ginacreferencedir)/*.gif
+ rm -f $(DESTDIR)$(ginacreferencedir)/*.png
The @code{pole_error} class has a member function
@example
-int pole_error::degree(void) const;
+int pole_error::degree() const;
@end example
that returns the order of the singularity (or 0 when the pole is
using namespace std;
using namespace GiNaC;
-int main(void)
+int main()
@{
try @{
...
@cindex @code{prepend()}
@cindex @code{remove_first()}
@cindex @code{remove_last()}
+@cindex @code{remove_all()}
The GiNaC class @code{lst} serves for holding a @dfn{list} of arbitrary
expressions. They are not as ubiquitous as in many other computer algebra
...
@end example
+As with the standard @code{list<T>} container, accessing random elements of a
+@code{lst} is generally an operation of order @math{O(N)}. Faster read-only
+sequential access to the elements of a list is possible with the
+iterator types provided by the @code{lst} class:
+
+@example
+typedef ... lst::const_iterator;
+typedef ... lst::const_reverse_iterator;
+lst::const_iterator lst::begin() const;
+lst::const_iterator lst::end() const;
+lst::const_reverse_iterator lst::rbegin() const;
+lst::const_reverse_iterator lst::rend() const;
+@end example
+
+For example, to print the elements of a list individually you can use:
+
+@example
+ ...
+ // O(N)
+ for (lst::const_iterator i = l.begin(); i != l.end(); ++i)
+ cout << *i << endl;
+ ...
+@end example
+
+which is one order faster than
+
+@example
+ ...
+ // O(N^2)
+ for (size_t i = 0; i < l.nops(); ++i)
+ cout << l.op(i) << endl;
+ ...
+@end example
+
+These iterators also allow you to use some of the algorithms provided by
+the C++ standard library:
+
+@example
+ ...
+ // print the elements of the list (requires #include <iterator>)
+ copy(l.begin(), l.end(), ostream_iterator<ex>(cout, "\n"));
+
+ // sum up the elements of the list (requires #include <numeric>)
+ ex sum = accumulate(l.begin(), l.end(), ex(0));
+ cout << sum << endl; // prints '2+2*x+2*y'
+ ...
+@end example
+
@code{lst} is one of the few GiNaC classes that allow in-place modifications
(the only other one is @code{matrix}). You can modify single elements:
@example
...
+ l[1] = 42; // l is now @{x, 42, y, x+y@}
l.let_op(1) = 7; // l is now @{x, 7, y, x+y@}
...
@end example
...
@end example
+You can remove all the elements of a list with @code{remove_all()}:
+
+@example
+ ...
+ l.remove_all(); // l is now empty
+ ...
+@end example
+
You can bring the elements of a list into a canonical order with @code{sort()}:
@example
@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:
+direct one) is to use the methods provided by the @code{matrix} class:
@example
matrix matrix::add(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;
+matrix matrix::transpose() const;
@end example
All of these methods return the result as a new matrix object. Here is an
@cindex @code{trace()}
@cindex @code{charpoly()}
@example
-ex matrix::determinant(unsigned algo = determinant_algo::automatic) const;
-ex matrix::trace(void) const;
+ex matrix::determinant(unsigned algo=determinant_algo::automatic) const;
+ex matrix::trace() 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.
+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.
+
+@cindex @code{inverse()}
+@cindex @code{solve()}
+Matrices may also be inverted using the @code{ex matrix::inverse()}
+method and linear systems may be solved with:
+
+@example
+matrix matrix::solve(const matrix & vars, const matrix & rhs, unsigned algo=solve_algo::automatic) const;
+@end example
+
+Assuming the matrix object this method is applied on is an @code{m}
+times @code{n} matrix, then @code{vars} must be a @code{n} times
+@code{p} matrix of symbolic indeterminates and @code{rhs} a @code{m}
+times @code{p} matrix. The returned matrix then has dimension @code{n}
+times @code{p} and in the case of an underdetermined system will still
+contain some of the indeterminates from @code{vars}. If the system is
+overdetermined, an exception is thrown.
@node Indexed objects, Non-commutative objects, Matrices, Basic Concepts
symbol A("A");
cout << indexed(A, i, j) << endl;
// -> A.i.j
+ cout << index_dimensions << indexed(A, i, j) << endl;
+ // -> A.i[3].j[3]
+ cout << dflt; // reset cout to default output format (dimensions hidden)
...
@end example
the symbol @code{A} as its base expression and the two indices @code{i} and
@code{j}.
+The dimensions of indices are normally not visible in the output, but one
+can request them to be printed with the @code{index_dimensions} manipulator,
+as shown above.
+
Note the difference between the indices @code{i} and @code{j} which are of
class @code{idx}, and the index values which are the symbols @code{i_sym}
and @code{j_sym}. The indices of indexed objects cannot directly be symbols
The methods
@example
-ex idx::get_value(void);
-ex idx::get_dimension(void);
+ex idx::get_value();
+ex idx::get_dimension();
@end example
return the value and dimension of an @code{idx} object. If you have an index
There are also the methods
@example
-bool idx::is_numeric(void);
-bool idx::is_symbolic(void);
-bool idx::is_dim_numeric(void);
-bool idx::is_dim_symbolic(void);
+bool idx::is_numeric();
+bool idx::is_symbolic();
+bool idx::is_dim_numeric();
+bool idx::is_dim_symbolic();
@end example
for checking whether the value and dimension are numeric or symbolic
constructor. The two methods
@example
-bool varidx::is_covariant(void);
-bool varidx::is_contravariant(void);
+bool varidx::is_covariant();
+bool varidx::is_contravariant();
@end example
allow you to check the variance of a @code{varidx} object (use @code{ex_to<varidx>()}
method
@example
-ex varidx::toggle_variance(void);
+ex varidx::toggle_variance();
@end example
which makes a new index with the same value and dimension but the opposite
methods
@example
-bool spinidx::is_dotted(void);
-bool spinidx::is_undotted(void);
+bool spinidx::is_dotted();
+bool spinidx::is_undotted();
@end example
allow you to check whether or not a @code{spinidx} object is dotted (use
Finally, the two methods
@example
-ex spinidx::toggle_dot(void);
-ex spinidx::toggle_variance_dot(void);
+ex spinidx::toggle_dot();
+ex spinidx::toggle_variance_dot();
@end example
create a new index with the same value and dimension but opposite dottedness
@end example
@cindex @code{get_free_indices()}
-@cindex Dummy index
+@cindex dummy index
@subsection Dummy indices
GiNaC treats certain symbolic index pairs as @dfn{dummy indices} meaning
there is the method
@example
-ex ex::simplify_indexed(void);
+ex ex::simplify_indexed();
ex ex::simplify_indexed(const scalar_products & sp);
@end example
obtained with the two member functions
@example
-unsigned ex::return_type(void) const;
-unsigned ex::return_type_tinfo(void) const;
+unsigned ex::return_type() const;
+unsigned ex::return_type_tinfo() const;
@end example
The @code{return_type()} function returns one of three values (defined in
* Substituting Expressions::
* Pattern Matching and Advanced Substitutions::
* Applying a Function on Subexpressions::
+* Visitors and Tree Traversal::
* Polynomial Arithmetic:: Working with polynomials.
* Rational Expressions:: Working with rational functions.
* Symbolic Differentiation::
* Series Expansion:: Taylor and Laurent expansion.
* Symmetrization::
* Built-in Functions:: List of predefined mathematical functions.
+* Solving Linear Systems of Equations::
* Input/Output:: Input and output of expressions.
@end menu
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;
+unsigned ex::return_type() const;
+unsigned ex::return_type_tinfo() const;
@end example
When the test made by @code{is_a<T>()} returns true, it is safe to call
GiNaC provides the two methods
@example
-unsigned ex::nops();
-ex ex::op(unsigned i);
+size_t ex::nops();
+ex ex::op(size_t i);
@end example
for accessing the subexpressions in the container-like GiNaC classes like
@end example
works a bit like @code{has()} but it doesn't stop upon finding the first
-match. Instead, it inserts all found matches into 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
+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
@}
@end example
+@subsection Algebraic substitutions
+The @code{subs()} method has an extra, optional, argument. This argument can
+be used to pass one of the @code{subs_options} to it. The only option that is
+currently available is the @code{subs_algebraic} option which affects
+products and powers. If you want to substitute some factors of a product, you
+only need to list these factors in your pattern. Furthermore, if an (integer)
+power of some expression occurs in your pattern and in the expression that you
+want the substitution to occur in, it can be substituted as many times as
+possible, without getting negative powers.
+
+An example clarifies it all (hopefully):
+
+@example
+cout << (a*a*a*a+b*b*b*b+pow(x+y,4)).subs(wild()*wild()==pow(wild(),3),
+ subs_options::subs_algebraic) << endl;
+// --> (y+x)^6+b^6+a^6
+
+cout << ((a+b+c)*(a+b+c)).subs(a+b==x,subs_options::subs_algebraic) << endl;
+// --> (c+b+a)^2
+// Powers and products are smart, but addition is just the same.
+
+cout << ((a+b+c)*(a+b+c)).subs(a+b+wild()==x+wild(), subs_options::subs_algebraic)
+ << endl;
+// --> (x+c)^2
+// As I said: addition is just the same.
+
+cout << (pow(a,5)*pow(b,7)+2*b).subs(b*b*a==x,subs_options::subs_algebraic) << endl;
+// --> x^3*b*a^2+2*b
+
+cout << (pow(a,-5)*pow(b,-7)+2*b).subs(1/(b*b*a)==x,subs_options::subs_algebraic)
+ << endl;
+// --> 2*b+x^3*b^(-1)*a^(-2)
+
+cout << (4*x*x*x-2*x*x+5*x-1).subs(x==a,subs_options::subs_algebraic) << endl;
+// --> -1-2*a^2+4*a^3+5*a
+
+cout << (4*x*x*x-2*x*x+5*x-1).subs(pow(x,wild())==pow(a,wild()),
+ subs_options::subs_algebraic) << endl;
+// --> -1+5*x+4*x^3-2*x^2
+// You should not really need this kind of patterns very often now.
+// But perhaps this it's-not-a-bug-it's-a-feature (c/sh)ould still change.
+
+cout << ex(sin(1+sin(x))).subs(sin(wild())==cos(wild()),
+ subs_options::subs_algebraic) << endl;
+// --> cos(1+cos(x))
+
+cout << expand((a*sin(x+y)*sin(x+y)+a*cos(x+y)*cos(x+y)+b)
+ .subs((pow(cos(wild()),2)==1-pow(sin(wild()),2)),
+ subs_options::subs_algebraic)) << endl;
+// --> b+a
+@end example
+
-@node Applying a Function on Subexpressions, Polynomial Arithmetic, Pattern Matching and Advanced Substitutions, Methods and Functions
+@node Applying a Function on Subexpressions, Visitors and Tree Traversal, Pattern Matching and Advanced Substitutions, Methods and Functions
@c node-name, next, previous, up
@section Applying a Function on Subexpressions
-@cindex Tree traversal
+@cindex tree traversal
@cindex @code{map()}
Sometimes you may want to perform an operation on specific parts of an
return ex_to<matrix>(e).trace();
else if (is_a<add>(e)) @{
ex sum = 0;
- for (unsigned i=0; i<e.nops(); i++)
+ for (size_t i=0; i<e.nops(); i++)
sum += calc_trace(e.op(i));
return sum;
@} else if (is_a<mul>)(e)) @{
@end example
-@node Polynomial Arithmetic, Rational Expressions, Applying a Function on Subexpressions, Methods and Functions
+@node Visitors and Tree Traversal, Polynomial Arithmetic, Applying a Function on Subexpressions, Methods and Functions
+@c node-name, next, previous, up
+@section Visitors and Tree Traversal
+@cindex tree traversal
+@cindex @code{visitor} (class)
+@cindex @code{accept()}
+@cindex @code{visit()}
+@cindex @code{traverse()}
+@cindex @code{traverse_preorder()}
+@cindex @code{traverse_postorder()}
+
+Suppose that you need a function that returns a list of all indices appearing
+in an arbitrary expression. The indices can have any dimension, and for
+indices with variance you always want the covariant version returned.
+
+You can't use @code{get_free_indices()} because you also want to include
+dummy indices in the list, and you can't use @code{find()} as it needs
+specific index dimensions (and it would require two passes: one for indices
+with variance, one for plain ones).
+
+The obvious solution to this problem is a tree traversal with a type switch,
+such as the following:
+
+@example
+void gather_indices_helper(const ex & e, lst & l)
+@{
+ if (is_a<varidx>(e)) @{
+ const varidx & vi = ex_to<varidx>(e);
+ l.append(vi.is_covariant() ? vi : vi.toggle_variance());
+ @} else if (is_a<idx>(e)) @{
+ l.append(e);
+ @} else @{
+ size_t n = e.nops();
+ for (size_t i = 0; i < n; ++i)
+ gather_indices_helper(e.op(i), l);
+ @}
+@}
+
+lst gather_indices(const ex & e)
+@{
+ lst l;
+ gather_indices_helper(e, l);
+ l.sort();
+ l.unique();
+ return l;
+@}
+@end example
+
+This works fine but fans of object-oriented programming will feel
+uncomfortable with the type switch. One reason is that there is a possibility
+for subtle bugs regarding derived classes. If we had, for example, written
+
+@example
+ if (is_a<idx>(e)) @{
+ ...
+ @} else if (is_a<varidx>(e)) @{
+ ...
+@end example
+
+in @code{gather_indices_helper}, the code wouldn't have worked because the
+first line "absorbs" all classes derived from @code{idx}, including
+@code{varidx}, so the special case for @code{varidx} would never have been
+executed.
+
+Also, for a large number of classes, a type switch like the above can get
+unwieldy and inefficient (it's a linear search, after all).
+@code{gather_indices_helper} only checks for two classes, but if you had to
+write a function that required a different implementation for nearly
+every GiNaC class, the result would be very hard to maintain and extend.
+
+The cleanest approach to the problem would be to add a new virtual function
+to GiNaC's class hierarchy. In our example, there would be specializations
+for @code{idx} and @code{varidx} while the default implementation in
+@code{basic} performed the tree traversal. Unfortunately, in C++ it's
+impossible to add virtual member functions to existing classes without
+changing their source and recompiling everything. GiNaC comes with source,
+so you could actually do this, but for a small algorithm like the one
+presented this would be impractical.
+
+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
+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
+@code{visit()} virtual function of the visitor that matches the type of
+object that @code{accept()} was being invoked on.
+
+Visitors in GiNaC must derive from the global @code{visitor} class as well
+as from the class @code{T::visitor} of each class @code{T} they want to
+visit, and implement the member functions @code{void visit(const T &)} for
+each class.
+
+A call of
+
+@example
+void ex::accept(visitor & v) const;
+@end example
+
+will then dispatch to the correct @code{visit()} member function of the
+specified visitor @code{v} for the type of GiNaC object at the root of the
+expression tree (e.g. a @code{symbol}, an @code{idx} or a @code{mul}).
+
+Here is an example of a visitor:
+
+@example
+class my_visitor
+ : public visitor, // this is required
+ public add::visitor, // visit add objects
+ public numeric::visitor, // visit numeric objects
+ public basic::visitor // visit basic objects
+@{
+ void visit(const add & x)
+ @{ cout << "called with an add object" << endl; @}
+
+ void visit(const numeric & x)
+ @{ cout << "called with a numeric object" << endl; @}
+
+ void visit(const basic & x)
+ @{ cout << "called with a basic object" << endl; @}
+@};
+@end example
+
+which can be used as follows:
+
+@example
+...
+ symbol x("x");
+ ex e1 = 42;
+ ex e2 = 4*x-3;
+ ex e3 = 8*x;
+
+ my_visitor v;
+ e1.accept(v);
+ // prints "called with a numeric object"
+ e2.accept(v);
+ // prints "called with an add object"
+ e3.accept(v);
+ // prints "called with a basic object"
+...
+@end example
+
+The @code{visit(const basic &)} method gets called for all objects that are
+not @code{numeric} or @code{add} and acts as an (optional) default.
+
+From a conceptual point of view, the @code{visit()} methods of the visitor
+behave like a newly added virtual function of the visited hierarchy.
+In addition, visitors can store state in member variables, and they can
+be extended by deriving a new visitor from an existing one, thus building
+hierarchies of visitors.
+
+We can now rewrite our index example from above with a visitor:
+
+@example
+class gather_indices_visitor
+ : public visitor, public idx::visitor, public varidx::visitor
+@{
+ lst l;
+
+ void visit(const idx & i)
+ @{
+ l.append(i);
+ @}
+
+ void visit(const varidx & vi)
+ @{
+ l.append(vi.is_covariant() ? vi : vi.toggle_variance());
+ @}
+
+public:
+ const lst & get_result() // utility function
+ @{
+ l.sort();
+ l.unique();
+ return l;
+ @}
+@};
+@end example
+
+What's missing is the tree traversal. We could implement it in
+@code{visit(const basic &)}, but GiNaC has predefined methods for this:
+
+@example
+void ex::traverse_preorder(visitor & v) const;
+void ex::traverse_postorder(visitor & v) const;
+void ex::traverse(visitor & v) const;
+@end example
+
+@code{traverse_preorder()} visits a node @emph{before} visiting its
+subexpressions, while @code{traverse_postorder()} visits a node @emph{after}
+visiting its subexpressions. @code{traverse()} is a synonym for
+@code{traverse_preorder()}.
+
+Here is a new implementation of @code{gather_indices()} that uses the visitor
+and @code{traverse()}:
+
+@example
+lst gather_indices(const ex & e)
+@{
+ gather_indices_visitor v;
+ e.traverse(v);
+ return v.get_result();
+@}
+@end example
+
+
+@node Polynomial Arithmetic, Rational Expressions, Visitors and Tree Traversal, Methods and Functions
@c node-name, next, previous, up
@section Polynomial arithmetic
int ex::ldegree(const ex & s);
@end example
-These functions only work reliably if the input polynomial is collected in
-terms of the object @samp{s}. Otherwise, they are only guaranteed to return
-the upper/lower bounds of the exponents. If you need accurate results, you
-have to call @code{expand()} and/or @code{collect()} on the input polynomial.
-For example
-
-@example
-> a=(x+1)^2-x^2;
-(1+x)^2-x^2;
-> degree(a,x);
-2
-> degree(expand(a),x);
-1
-@end example
-
-@code{degree()} also works on rational functions, returning the asymptotic
-degree:
-
-@example
-> degree((x+1)/(x^3+1),x);
--2
-@end example
-
-If the input is not a polynomial or rational function in the variable @samp{s},
-the behavior of @code{degree()} and @code{ldegree()} is undefined.
-
-To extract a coefficient with a certain power from an expanded
-polynomial you use
+which also work reliably on non-expanded input polynomials (they even work
+on rational functions, returning the asymptotic degree). To extract
+a coefficient with a certain power from an expanded polynomial you use
@example
ex ex::coeff(const ex & s, int n);
faster than using @code{numer()} and @code{denom()} separately.
-@subsection Converting to a rational expression
+@subsection Converting to a polynomial or rational expression
+@cindex @code{to_polynomial()}
@cindex @code{to_rational()}
Some of the methods described so far only work on polynomials or rational
general expressions by using the temporary replacement algorithm described
above. You do this by calling
+@example
+ex ex::to_polynomial(lst &l);
+@end example
+or
@example
ex ex::to_rational(lst &l);
@end example
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_rational()}, so it's possible to use it on multiple expressions
-and get consistent results.
+@code{.to_polynomial()} or @code{.to_rational()}, so it's possible to use
+it on multiple expressions and get consistent results.
+
+The difference betwerrn @code{.to_polynomial()} and @code{.to_rational()}
+is probably best illustrated with an example:
+
+@example
+@{
+ symbol x("x"), y("y");
+ 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;
+ // = 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;
+ // = -1/3*symbol4^(-1)*y+2*symbol4^(-1)*x
+ // with @{symbol4==sin(x)@}
+@}
+@end example
-For example,
+The following more useful example will print @samp{sin(x)-cos(x)}:
@example
@{
ex b = sin(x) + cos(x);
ex q;
lst l;
- divide(a.to_rational(l), b.to_rational(l), q);
+ divide(a.to_polynomial(l), b.to_polynomial(l), q);
cout << q.subs(l) << endl;
@}
@end example
-will print @samp{sin(x)-cos(x)}.
-
@node Symbolic Differentiation, Series Expansion, Rational Expressions, Methods and Functions
@c node-name, next, previous, up
$\pi$
@end tex
(for which there already exists the built-in constant @code{Pi})
-using Machin's amazing formula
+using John Machin's amazing formula
@tex
$\pi=16$~atan~$\!\left(1 \over 5 \right)-4$~atan~$\!\left(1 \over 239 \right)$.
@end tex
@ifnottex
@math{Pi==16*atan(1/5)-4*atan(1/239)}.
@end ifnottex
-We may expand the arcus tangent around @code{0} and insert the fractions
-@code{1/5} and @code{1/239}. But, as we have seen, a series in GiNaC
-carries an order term with it and the question arises what the system is
-supposed to do when the fractions are plugged into that order term. The
-solution is to use the function @code{series_to_poly()} to simply strip
-the order term off:
+This equation (and similar ones) were used for over 200 years for
+computing digits of pi (see @cite{Pi Unleashed}). We may expand the
+arcus tangent around @code{0} and insert the fractions @code{1/5} and
+@code{1/239}. However, as we have seen, a series in GiNaC carries an
+order term with it and the question arises what the system is supposed
+to do when the fractions are plugged into that order term. The solution
+is to use the function @code{series_to_poly()} to simply strip the order
+term off:
@example
#include <ginac/ginac.h>
@end example
-@node Built-in Functions, Input/Output, Symmetrization, Methods and Functions
+@node Built-in Functions, Solving Linear Systems of Equations, Symmetrization, Methods and Functions
@c node-name, next, previous, up
@section Predefined mathematical functions
compatible with C99.
-@node Input/Output, Extending GiNaC, Built-in Functions, Methods and Functions
+@node Solving Linear Systems of Equations, Input/Output, Built-in Functions, Methods and Functions
+@c node-name, next, previous, up
+@section Solving Linear Systems of Equations
+@cindex @code{lsolve()}
+
+The function @code{lsolve()} provides a convenient wrapper around some
+matrix operations that comes in handy when a system of linear equations
+needs to be solved:
+
+@example
+ex lsolve(const ex &eqns, const ex &symbols, unsigned options=solve_algo::automatic);
+@end example
+
+Here, @code{eqns} is a @code{lst} of equalities (i.e. class
+@code{relational}) while @code{symbols} is a @code{lst} of
+indeterminates. (@xref{The Class Hierarchy}, for an exposition of class
+@code{lst}).
+
+It returns the @code{lst} of solutions as an expression. As an example,
+let us solve the two equations @code{a*x+b*y==3} and @code{x-y==b}:
+
+@example
+@{
+ symbol a("a"), b("b"), x("x"), y("y");
+ lst eqns;
+ eqns.append(a*x+b*y==3).append(x-y==b);
+ lst vars;
+ vars.append(x).append(y);
+ cout << lsolve(eqns, vars) << endl;
+ // -> @{x==(3+b^2)/(b+a),y==(3-b*a)/(b+a)@}
+@end example
+
+When the linear equations @code{eqns} are underdetermined, the solution
+will contain one or more tautological entries like @code{x==x},
+depending on the rank of the system. When they are overdetermined, the
+solution will be an empty @code{lst}. Note the third optional parameter
+to @code{lsolve()}: it accepts the same parameters as
+@code{matrix::solve()}. This is because @code{lsolve} is just a wrapper
+around that method.
+
+
+@node Input/Output, Extending GiNaC, Solving Linear Systems of Equations, Methods and Functions
@c node-name, next, previous, up
@section Input and output of expressions
@cindex I/O
@cindex printing
@cindex output of expressions
-The easiest way to print an expression is to write it to a stream:
+Expressions can simply be written to any stream:
@example
@{
symbol x("x");
- ex e = 4.5+pow(x,2)*3/2;
- cout << e << endl; // prints '(4.5)+3/2*x^2'
+ ex e = 4.5*I+pow(x,2)*3/2;
+ cout << e << endl; // prints '4.5*I+3/2*x^2'
// ...
@end example
-The output format is identical to the @command{ginsh} input syntax and
+The default output format is identical to the @command{ginsh} input syntax and
to that used by most computer algebra systems, but not directly pastable
into a GiNaC C++ program (note that in the above example, @code{pow(x,2)}
is printed as @samp{x^2}).
It is possible to print expressions in a number of different formats with
-the method
+a set of stream manipulators;
@example
-void ex::print(const print_context & c, unsigned level = 0);
+std::ostream & dflt(std::ostream & os);
+std::ostream & latex(std::ostream & os);
+std::ostream & tree(std::ostream & os);
+std::ostream & csrc(std::ostream & os);
+std::ostream & csrc_float(std::ostream & os);
+std::ostream & csrc_double(std::ostream & os);
+std::ostream & csrc_cl_N(std::ostream & os);
+std::ostream & index_dimensions(std::ostream & os);
+std::ostream & no_index_dimensions(std::ostream & os);
@end example
-@cindex @code{print_context} (class)
-The type of @code{print_context} object passed in determines the format
-of the output. The possible types are defined in @file{ginac/print.h}.
-All constructors of @code{print_context} and derived classes take an
-@code{ostream &} as their first argument.
+The @code{tree}, @code{latex} and @code{csrc} formats are also available in
+@command{ginsh} via the @code{print()}, @code{print_latex()} and
+@code{print_csrc()} functions, respectively.
-To print an expression in a way that can be directly used in a C or C++
-program, you pass a @code{print_csrc} object like this:
+@cindex @code{dflt}
+All manipulators affect the stream state permanently. To reset the output
+format to the default, use the @code{dflt} manipulator:
@example
// ...
- cout << "float f = ";
- e.print(print_csrc_float(cout));
- cout << ";\n";
+ cout << latex; // all output to cout will be in LaTeX format from now on
+ cout << e << endl; // prints '4.5 i+\frac@{3@}@{2@} x^@{2@}'
+ cout << sin(x/2) << endl; // prints '\sin(\frac@{1@}@{2@} x)'
+ cout << dflt; // revert to default output format
+ cout << e << endl; // prints '4.5*I+3/2*x^2'
+ // ...
+@end example
- cout << "double d = ";
- e.print(print_csrc_double(cout));
- cout << ";\n";
+If you don't want to affect the format of the stream you're working with,
+you can output to a temporary @code{ostringstream} like this:
- cout << "cl_N n = ";
- e.print(print_csrc_cl_N(cout));
- cout << ";\n";
+@example
+ // ...
+ ostringstream s;
+ s << latex << e; // format of cout remains unchanged
+ cout << s.str() << endl; // prints '4.5 i+\frac@{3@}@{2@} x^@{2@}'
// ...
@end example
-The three possible types mostly affect the way in which floating point
-numbers are written.
+@cindex @code{csrc}
+@cindex @code{csrc_float}
+@cindex @code{csrc_double}
+@cindex @code{csrc_cl_N}
+The @code{csrc} (an alias for @code{csrc_double}), @code{csrc_float},
+@code{csrc_double} and @code{csrc_cl_N} manipulators set the output to a
+format that can be directly used in a C or C++ program. The three possible
+formats select the data types used for numbers (@code{csrc_cl_N} uses the
+classes provided by the CLN library):
-The above example will produce (note the @code{x^2} being converted to @code{x*x}):
+@example
+ // ...
+ cout << "f = " << csrc_float << e << ";\n";
+ cout << "d = " << csrc_double << e << ";\n";
+ cout << "n = " << csrc_cl_N << e << ";\n";
+ // ...
+@end example
+
+The above example will produce (note the @code{x^2} being converted to
+@code{x*x}):
@example
-float f = (3.0/2.0)*(x*x)+4.500000e+00;
-double d = (3.0/2.0)*(x*x)+4.5000000000000000e+00;
-cl_N n = cln::cl_RA("3/2")*(x*x)+cln::cl_F("4.5_17");
+f = (3.0/2.0)*(x*x)+std::complex<float>(0.0,4.5000000e+00);
+d = (3.0/2.0)*(x*x)+std::complex<double>(0.0,4.5000000000000000e+00);
+n = cln::cl_RA("3/2")*(x*x)+cln::complex(cln::cl_I("0"),cln::cl_F("4.5_17"));
@end example
-The @code{print_context} type @code{print_tree} provides a dump of the
-internal structure of an expression for debugging purposes:
+@cindex @code{tree}
+The @code{tree} manipulator allows dumping the internal structure of an
+expression for debugging purposes:
@example
// ...
- e.print(print_tree(cout));
+ cout << tree << e;
@}
@end example
@example
add, hash=0x0, flags=0x3, nops=2
- power, hash=0x9, flags=0x3, nops=2
- x (symbol), serial=3, hash=0x44a113a6, flags=0xf
- 2 (numeric), hash=0x80000042, flags=0xf
- 3/2 (numeric), hash=0x80000061, flags=0xf
+ power, hash=0x0, flags=0x3, nops=2
+ x (symbol), serial=0, hash=0xc8d5bcdd, flags=0xf
+ 2 (numeric), hash=0x6526b0fa, flags=0xf
+ 3/2 (numeric), hash=0xf9828fbd, flags=0xf
-----
overall_coeff
- 4.5L0 (numeric), hash=0x8000004b, flags=0xf
+ 4.5L0i (numeric), hash=0xa40a97e0, flags=0xf
=====
@end example
-This kind of output is also available in @command{ginsh} as the @code{print()}
-function.
-
-Another useful output format is for LaTeX parsing in mathematical mode.
-It is rather similar to the default @code{print_context} but provides
-some braces needed by LaTeX for delimiting boxes and also converts some
-common objects to conventional LaTeX names. It is possible to give symbols
-a special name for LaTeX output by supplying it as a second argument to
-the @code{symbol} constructor.
+@cindex @code{latex}
+The @code{latex} output format is for LaTeX parsing in mathematical mode.
+It is rather similar to the default format but provides some braces needed
+by LaTeX for delimiting boxes and also converts some common objects to
+conventional LaTeX names. It is possible to give symbols a special name for
+LaTeX output by supplying it as a second argument to the @code{symbol}
+constructor.
For example, the code snippet
@example
- // ...
- symbol x("x");
- ex foo = lgamma(x).series(x==0,3);
- foo.print(print_latex(std::cout));
+@{
+ symbol x("x", "\\circ");
+ ex e = lgamma(x).series(x==0,3);
+ cout << latex << e << endl;
+@}
+@end example
+
+will print
+
+@example
+ @{(-\ln(\circ))@}+@{(-\gamma_E)@} \circ+@{(\frac@{1@}@{12@} \pi^@{2@})@} \circ^@{2@}+\mathcal@{O@}(\circ^@{3@})
@end example
-will print out:
+@cindex @code{index_dimensions}
+@cindex @code{no_index_dimensions}
+Index dimensions are normally hidden in the output. To make them visible, use
+the @code{index_dimensions} manipulator. The dimensions will be written in
+square brackets behind each index value in the default and LaTeX output
+formats:
@example
- @{(-\ln(x))@}+@{(-\gamma_E)@} x+@{(1/12 \pi^2)@} x^@{2@}+\mathcal@{O@}(x^3)
+@{
+ symbol x("x"), y("y");
+ varidx mu(symbol("mu"), 4), nu(symbol("nu"), 4);
+ ex e = indexed(x, mu) * indexed(y, nu);
+
+ cout << e << endl;
+ // prints 'x~mu*y~nu'
+ cout << index_dimensions << e << endl;
+ // prints 'x~mu[4]*y~nu[4]'
+ cout << no_index_dimensions << e << endl;
+ // prints 'x~mu*y~nu'
+@}
@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
else
cout << e.bp->class_name();
cout << "(";
- unsigned n = e.nops();
+ size_t n = e.nops();
if (n)
- for (unsigned i=0; i<n; i++) @{
+ for (size_t i=0; i<n; i++) @{
my_print(e.op(i));
if (i != n-1)
cout << ",";
cout << ")";
@}
-int main(void)
+int main()
@{
my_print(pow(3, x) - 2 * sin(y / Pi)); cout << endl;
return 0;
desired symbols to the @code{>>} stream input operator.
Instead, GiNaC lets you construct an expression from a string, specifying the
-list of symbols and indices to be used:
+list of symbols to be used:
@example
@{
- symbol x("x"), y("y"), p("p");
- idx i(symbol("i"), 3);
- ex e("2*x+sin(y)+p.i", lst(x, y, p, i));
+ symbol x("x"), y("y");
+ ex e("2*x+sin(y)", lst(x, y));
@}
@end example
The input syntax is the same as that used by @command{ginsh} and the stream
-output operator @code{<<}. The symbols and indices in the string are matched
-by name to the symbols and indices in the list and if GiNaC encounters a
-symbol or index not specified in the list it will throw an exception. Only
-indices whose values are single symbols can be used (i.e. numeric indices
-or compound indices as in "A.(2*n+1)" are not allowed).
+output operator @code{<<}. The symbols in the string are matched by name to
+the symbols in the list and if GiNaC encounters a symbol not specified in
+the list it will throw an exception.
With this constructor, it's also easy to implement interactive GiNaC programs:
archive_node::propinfovector p;
n.get_properties(p);
- unsigned num = p.size();
- for (unsigned i=0; i<num; i++) @{
+ size_t num = p.size();
+ for (size_t i=0; i<num; i++) @{
const string &name = p[i].name;
if (name == "class")
continue;
cout << ")";
@}
-int main(void)
+int main()
@{
ex e = pow(2, x) - y;
archive ar(e, "e");
@menu
* What does not belong into GiNaC:: What to avoid.
* Symbolic functions:: Implementing symbolic functions.
-* Adding classes:: Defining new algebraic classes.
+* Structures:: Defining new algebraic classes (the easy way).
+* Adding classes:: Defining new algebraic classes (the hard way).
@end menu
provided by CLN are much better suited.
-@node Symbolic functions, Adding classes, What does not belong into GiNaC, Extending GiNaC
+@node Symbolic functions, Structures, What does not belong into GiNaC, Extending GiNaC
@c node-name, next, previous, up
@section Symbolic functions
symmetric functions into a canonical order.
-@node Adding classes, A Comparison With Other CAS, Symbolic functions, Extending GiNaC
+@node Structures, Adding classes, Symbolic functions, Extending GiNaC
+@c node-name, next, previous, up
+@section Structures
+
+If you are doing some very specialized things with GiNaC, or if you just
+need some more organized way to store data in your expressions instead of
+anonymous lists, you may want to implement your own algebraic classes.
+('algebraic class' means any class directly or indirectly derived from
+@code{basic} that can be used in GiNaC expressions).
+
+GiNaC offers two ways of accomplishing this: either by using the
+@code{structure<T>} template class, or by rolling your own class from
+scratch. This section will discuss the @code{structure<T>} template which
+is easier to use but more limited, while the implementation of custom
+GiNaC classes is the topic of the next section. However, you may want to
+read both sections because many common concepts and member functions are
+shared by both concepts, and it will also allow you to decide which approach
+is most suited to your needs.
+
+The @code{structure<T>} template, defined in the GiNaC header file
+@file{structure.h}, wraps a type that you supply (usually a C++ @code{struct}
+or @code{class}) into a GiNaC object that can be used in expressions.
+
+@subsection Example: scalar products
+
+Let's suppose that we need a way to handle some kind of abstract scalar
+product of the form @samp{<x|y>} in expressions. Objects of the scalar
+product class have to store their left and right operands, which can in turn
+be arbitrary expressions. Here is a possible way to represent such a
+product in a C++ @code{struct}:
+
+@example
+#include <iostream>
+using namespace std;
+
+#include <ginac/ginac.h>
+using namespace GiNaC;
+
+struct sprod_s @{
+ ex left, right;
+
+ sprod_s() @{@}
+ sprod_s(ex l, ex r) : left(l), right(r) @{@}
+@};
+@end example
+
+The default constructor is required. Now, to make a GiNaC class out of this
+data structure, we need only one line:
+
+@example
+typedef structure<sprod_s> sprod;
+@end example
+
+That's it. This line constructs an algebraic class @code{sprod} which
+contains objects of type @code{sprod_s}. We can now use @code{sprod} in
+expressions like any other GiNaC class:
+
+@example
+...
+ symbol a("a"), b("b");
+ ex e = sprod(sprod_s(a, b));
+...
+@end example
+
+Note the difference between @code{sprod} which is the algebraic class, and
+@code{sprod_s} which is the unadorned C++ structure containing the @code{left}
+and @code{right} data members. As shown above, an @code{sprod} can be
+constructed from an @code{sprod_s} object.
+
+If you find the nested @code{sprod(sprod_s())} constructor too unwieldy,
+you could define a little wrapper function like this:
+
+@example
+inline ex make_sprod(ex left, ex right)
+@{
+ return sprod(sprod_s(left, right));
+@}
+@end example
+
+The @code{sprod_s} object contained in @code{sprod} can be accessed with
+the GiNaC @code{ex_to<>()} function followed by the @code{->} operator or
+@code{get_struct()}:
+
+@example
+...
+ cout << ex_to<sprod>(e)->left << endl;
+ // -> a
+ cout << ex_to<sprod>(e).get_struct().right << endl;
+ // -> b
+...
+@end example
+
+You only have read access to the members of @code{sprod_s}.
+
+The type definition of @code{sprod} is enough to write your own algorithms
+that deal with scalar products, for example:
+
+@example
+ex swap_sprod(ex p)
+@{
+ if (is_a<sprod>(p)) @{
+ const sprod_s & sp = ex_to<sprod>(p).get_struct();
+ return make_sprod(sp.right, sp.left);
+ @} else
+ return p;
+@}
+
+...
+ f = swap_sprod(e);
+ // f is now <b|a>
+...
+@end example
+
+@subsection Structure output
+
+While the @code{sprod} type is useable it still leaves something to be
+desired, most notably proper output:
+
+@example
+...
+ cout << e << endl;
+ // -> [structure object]
+...
+@end example
+
+By default, any structure types you define will be printed as
+@samp{[structure object]}. To override this, you can specialize the
+template's @code{print()} member function. The member functions of
+GiNaC classes are described in more detail in the next section, but
+it shouldn't be hard to figure out what's going on here:
+
+@example
+void sprod::print(const print_context & c, unsigned level) const
+@{
+ // tree debug output handled by superclass
+ if (is_a<print_tree>(c))
+ inherited::print(c, level);
+
+ // get the contained sprod_s object
+ const sprod_s & sp = get_struct();
+
+ // print_context::s is a reference to an ostream
+ c.s << "<" << sp.left << "|" << sp.right << ">";
+@}
+@end example
+
+Now we can print expressions containing scalar products:
+
+@example
+...
+ cout << e << endl;
+ // -> <a|b>
+ cout << swap_sprod(e) << endl;
+ // -> <b|a>
+...
+@end example
+
+@subsection Comparing structures
+
+The @code{sprod} class defined so far still has one important drawback: all
+scalar products are treated as being equal because GiNaC doesn't know how to
+compare objects of type @code{sprod_s}. This can lead to some confusing
+and undesired behavior:
+
+@example
+...
+ cout << make_sprod(a, b) - make_sprod(a*a, b*b) << endl;
+ // -> 0
+ cout << make_sprod(a, b) + make_sprod(a*a, b*b) << endl;
+ // -> 2*<a|b> or 2*<a^2|b^2> (which one is undefined)
+...
+@end example
+
+To remedy this, we first need to define the operators @code{==} and @code{<}
+for objects of type @code{sprod_s}:
+
+@example
+inline bool operator==(const sprod_s & lhs, const sprod_s & rhs)
+@{
+ return lhs.left.is_equal(rhs.left) && lhs.right.is_equal(rhs.right);
+@}
+
+inline bool operator<(const sprod_s & lhs, const sprod_s & rhs)
+@{
+ return lhs.left.compare(rhs.left) < 0 ? true : lhs.right.compare(rhs.right) < 0;
+@}
+@end example
+
+The ordering established by the @code{<} operator doesn't have to make any
+algebraic sense, but it needs to be well defined. Note that we can't use
+expressions like @code{lhs.left == rhs.left} or @code{lhs.left < rhs.left}
+in the implementation of these operators because they would construct
+GiNaC @code{relational} objects which in the case of @code{<} do not
+establish a well defined ordering (for arbitrary expressions, GiNaC can't
+decide which one is algebraically 'less').
+
+Next, we need to change our definition of the @code{sprod} type to let
+GiNaC know that an ordering relation exists for the embedded objects:
+
+@example
+typedef structure<sprod_s, compare_std_less> sprod;
+@end example
+
+@code{sprod} objects then behave as expected:
+
+@example
+...
+ cout << make_sprod(a, b) - make_sprod(a*a, b*b) << endl;
+ // -> <a|b>-<a^2|b^2>
+ cout << make_sprod(a, b) + make_sprod(a*a, b*b) << endl;
+ // -> <a|b>+<a^2|b^2>
+ cout << make_sprod(a, b) - make_sprod(a, b) << endl;
+ // -> 0
+ cout << make_sprod(a, b) + make_sprod(a, b) << endl;
+ // -> 2*<a|b>
+...
+@end example
+
+The @code{compare_std_less} policy parameter tells GiNaC to use the
+@code{std::less} and @code{std::equal_to} functors to compare objects of
+type @code{sprod_s}. By default, these functors forward their work to the
+standard @code{<} and @code{==} operators, which we have overloaded.
+Alternatively, we could have specialized @code{std::less} and
+@code{std::equal_to} for class @code{sprod_s}.
+
+GiNaC provides two other comparison policies for @code{structure<T>}
+objects: the default @code{compare_all_equal}, and @code{compare_bitwise}
+which does a bit-wise comparison of the contained @code{T} objects.
+This should be used with extreme care because it only works reliably with
+built-in integral types, and it also compares any padding (filler bytes of
+undefined value) that the @code{T} class might have.
+
+@subsection Subexpressions
+
+Our scalar product class has two subexpressions: the left and right
+operands. It might be a good idea to make them accessible via the standard
+@code{nops()} and @code{op()} methods:
+
+@example
+size_t sprod::nops() const
+@{
+ return 2;
+@}
+
+ex sprod::op(size_t i) const
+@{
+ switch (i) @{
+ case 0:
+ return get_struct().left;
+ case 1:
+ return get_struct().right;
+ default:
+ throw std::range_error("sprod::op(): no such operand");
+ @}
+@}
+@end example
+
+Implementing @code{nops()} and @code{op()} for container types such as
+@code{sprod} has two other nice side effects:
+
+@itemize @bullet
+@item
+@code{has()} works as expected
+@item
+GiNaC generates better hash keys for the objects (the default implementation
+of @code{calchash()} takes subexpressions into account)
+@end itemize
+
+@cindex @code{let_op()}
+There is a non-const variant of @code{op()} called @code{let_op()} that
+allows replacing subexpressions:
+
+@example
+ex & sprod::let_op(size_t i)
+@{
+ // every non-const member function must call this
+ ensure_if_modifiable();
+
+ switch (i) @{
+ case 0:
+ return get_struct().left;
+ case 1:
+ return get_struct().right;
+ default:
+ throw std::range_error("sprod::let_op(): no such operand");
+ @}
+@}
+@end example
+
+Once we have provided @code{let_op()} we also get @code{subs()} and
+@code{map()} for free. In fact, every container class that returns a non-null
+@code{nops()} value must either implement @code{let_op()} or provide custom
+implementations of @code{subs()} and @code{map()}.
+
+In turn, the availability of @code{map()} enables the recursive behavior of a
+couple of other default method implementations, in particular @code{evalf()},
+@code{evalm()}, @code{normal()}, @code{diff()} and @code{expand()}. Although
+we probably want to provide our own version of @code{expand()} for scalar
+products that turns expressions like @samp{<a+b|c>} into @samp{<a|c>+<b|c>}.
+This is left as an exercise for the reader.
+
+The @code{structure<T>} template defines many more member functions that
+you can override by specialization to customize the behavior of your
+structures. You are referred to the next section for a description of
+some of these (especially @code{eval()}). There is, however, one topic
+that shall be addressed here, as it demonstrates one peculiarity of the
+@code{structure<T>} template: archiving.
+
+@subsection Archiving structures
+
+If you don't know how the archiving of GiNaC objects is implemented, you
+should first read the next section and then come back here. You're back?
+Good.
+
+To implement archiving for structures it is not enough to provide
+specializations for the @code{archive()} member function and the
+unarchiving constructor (the @code{unarchive()} function has a default
+implementation). You also need to provide a unique name (as a string literal)
+for each structure type you define. This is because in GiNaC archives,
+the class of an object is stored as a string, the class name.
+
+By default, this class name (as returned by the @code{class_name()} member
+function) is @samp{structure} for all structure classes. This works as long
+as you have only defined one structure type, but if you use two or more you
+need to provide a different name for each by specializing the
+@code{get_class_name()} member function. Here is a sample implementation
+for enabling archiving of the scalar product type defined above:
+
+@example
+const char *sprod::get_class_name() @{ return "sprod"; @}
+
+void sprod::archive(archive_node & n) const
+@{
+ inherited::archive(n);
+ n.add_ex("left", get_struct().left);
+ n.add_ex("right", get_struct().right);
+@}
+
+sprod::structure(const archive_node & n, lst & sym_lst) : inherited(n, sym_lst)
+@{
+ n.find_ex("left", get_struct().left, sym_lst);
+ n.find_ex("right", get_struct().right, sym_lst);
+@}
+@end example
+
+Note that the unarchiving constructor is @code{sprod::structure} and not
+@code{sprod::sprod}, and that we don't need to supply an
+@code{sprod::unarchive()} function.
+
+
+@node Adding classes, A Comparison With Other CAS, Structures, Extending GiNaC
@c node-name, next, previous, up
@section Adding classes
-If you are doing some very specialized things with GiNaC you may find that
-you have to implement your own algebraic classes to fit your needs. This
-section will explain how to do this by giving the example of a simple
-'string' class. After reading this section you will know how to properly
-declare a GiNaC class and what the minimum required member functions are
-that you have to implement. We only cover the implementation of a 'leaf'
-class here (i.e. one that doesn't contain subexpressions). Creating a
-container class like, for example, a class representing tensor products is
-more involved but this section should give you enough information so you can
-consult the source to GiNaC's predefined classes if you want to implement
-something more complicated.
+The @code{structure<T>} template provides an way to extend GiNaC with custom
+algebraic classes that is easy to use but has its limitations, the most
+severe of which being that you can't add any new member functions to
+structures. To be able to do this, you need to write a new class definition
+from scratch.
+
+This section will explain how to implement new algebraic classes in GiNaC by
+giving the example of a simple 'string' class. After reading this section
+you will know how to properly declare a GiNaC class and what the minimum
+required member functions are that you have to implement. We only cover the
+implementation of a 'leaf' class here (i.e. one that doesn't contain
+subexpressions). Creating a container class like, for example, a class
+representing tensor products is more involved but this section should give
+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
source (at global scope, of course, not inside a function).
@code{GINAC_DECLARE_REGISTERED_CLASS} contains, among other things the
-declarations of the default and copy constructor, the destructor, the
-assignment operator 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} implements the copy
-constructor, the destructor and the assignment operator.
-
-Now there are nine member functions we have to implement to get a working
+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.
+
+Now there are seven member functions we have to implement to get a working
class:
@itemize
@item
@code{mystring()}, the default constructor.
-@item
-@code{void destroy(bool call_parent)}, which is used in the destructor and the
-assignment operator to free dynamically allocated members. The @code{call_parent}
-specifies whether the @code{destroy()} function of the superclass is to be
-called also.
-
-@item
-@code{void copy(const mystring &other)}, which is used in the copy constructor
-and assignment operator to copy the member variables over from another
-object of the same class.
-
@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, const lst &sym_lst)}, the unarchiving
+@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, const lst &sym_lst)}, the static
+@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
by GiNaC to establish a canonical sort order for terms. It returns 0, +1 or
-1, depending on the relative order of this object and the @code{other}
Let's proceed step-by-step. The default constructor looks like this:
@example
-mystring::mystring() : inherited(TINFO_mystring)
-@{
- // dynamically allocate resources here if required
-@}
+mystring::mystring() : inherited(TINFO_mystring) @{@}
@end example
The golden rule is that in all constructors you have to set the
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
+(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). The constructor(s) are of
-course also the right place to allocate any dynamic resources you require.
-
-Next, the @code{destroy()} function:
-
-@example
-void mystring::destroy(bool call_parent)
-@{
- // free dynamically allocated resources here if required
- if (call_parent)
- inherited::destroy(call_parent);
-@}
-@end example
-
-This function is where we free all dynamically allocated resources. We
-don't have any so we're not doing anything here, but if we had, for
-example, used a C-style @code{char *} to store our string, this would be
-the place to @code{delete[]} the string storage. If @code{call_parent}
-is true, we have to call the @code{destroy()} function of the superclass
-after we're done (to mimic C++'s automatic invocation of superclass
-destructors where @code{destroy()} is called from outside a destructor).
-
-The @code{copy()} function just copies over the member variables from
-another object:
-
-@example
-void mystring::copy(const mystring &other)
-@{
- inherited::copy(other);
- str = other.str;
-@}
-@end example
-
-We can simply overwrite the member variables here. There's no need to worry
-about dynamically allocated storage. The assignment operator (which is
-automatically defined by @code{GINAC_IMPLEMENT_REGISTERED_CLASS}, as you
-recall) calls @code{destroy()} before it calls @code{copy()}. You have to
-explicitly call the @code{copy()} function of the superclass here so
-all the member variables will get copied.
+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
function:
@example
-mystring::mystring(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
+mystring::mystring(const archive_node &n, lst &sym_lst) : inherited(n, sym_lst)
@{
n.find_string("string", str);
@}
Finally, the unarchiving function:
@example
-ex mystring::unarchive(const archive_node &n, const lst &sym_lst)
+ex mystring::unarchive(const archive_node &n, lst &sym_lst)
@{
return (new mystring(n, sym_lst))->setflag(status_flags::dynallocated);
@}
Now the only thing missing is our two new constructors:
@example
-mystring::mystring(const string &s) : inherited(TINFO_mystring), str(s)
-@{
- // dynamically allocate resources here if required
-@}
-
-mystring::mystring(const char *s) : inherited(TINFO_mystring), str(s)
-@{
- // dynamically allocate resources here if required
-@}
+mystring::mystring(const string &s) : inherited(TINFO_mystring), str(s) @{@}
+mystring::mystring(const char *s) : inherited(TINFO_mystring), str(s) @{@}
@end example
No surprises here. We set the @code{str} member from the argument and
// -> 3*"wow"
@end example
-@subsection Other member functions
+@subsection Optional member functions
We have implemented only a small set of member functions to make the class
-work in the GiNaC framework. For a real algebraic class, there are probably
-some more functions that you might want to re-implement:
+work in the GiNaC framework. There are two functions that are not strictly
+required but will make operations with objects of the class more efficient:
+
+@cindex @code{calchash()}
+@cindex @code{is_equal_same_type()}
+@example
+unsigned calchash() const;
+bool is_equal_same_type(const basic &other) const;
+@end example
+
+The @code{calchash()} method returns an @code{unsigned} hash value for the
+object which will allow GiNaC to compare and canonicalize expressions much
+more efficiently. You should consult the implementation of some of the built-in
+GiNaC classes for examples of hash functions. The default implementation of
+@code{calchash()} calculates a hash value out of the @code{tinfo_key} of the
+class and all subexpressions that are accessible via @code{op()}.
+
+@code{is_equal_same_type()} works like @code{compare_same_type()} but only
+tests for equality without establishing an ordering relation, which is often
+faster. The default implementation of @code{is_equal_same_type()} just calls
+@code{compare_same_type()} and tests its result for zero.
+
+@subsection Other member functions
+
+For a real algebraic class, there are probably some more functions that you
+might want to provide:
@example
bool info(unsigned inf) const;
ex derivative(const symbol & s) const;
@end example
-If your class stores sub-expressions you will probably want to override
+If your class stores sub-expressions (see the scalar product example in the
+previous section) you will probably want to override
@cindex @code{let_op()}
@example
-unsigned nops() cont;
-ex op(int i) const;
-ex & let_op(int i);
+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;
-ex subs(const lst & ls, const lst & lr, bool no_pattern = false) const;
@end example
@code{let_op()} is a variant of @code{op()} that allows write access. The
-default implementation of @code{map()} uses it, so you have to implement
-either @code{let_op()} or @code{map()}.
-
-If your class stores any data that is not accessible via @code{op()}, you
-should also implement
-
-@cindex @code{calchash()}
-@example
-unsigned calchash(void) const;
-@end example
-
-This function returns an @code{unsigned} hash value for the object which
-will allow GiNaC to compare and canonicalize expressions much more
-efficiently. You should consult the implementation of some of the built-in
-GiNaC classes for examples of hash functions.
+default implementations of @code{subs()} and @code{map()} use it, so you have
+to implement either @code{let_op()}, or @code{subs()} and @code{map()}.
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
@cindex reference counting
@cindex copy-on-write
@cindex garbage collection
-An expression is extremely light-weight since internally it works like a
-handle to the actual representation and really holds nothing more than a
-pointer to some other object. What this means in practice is that
-whenever you create two @code{ex} and set the second equal to the first
-no copying process is involved. Instead, the copying takes place as soon
-as you try to change the second. Consider the simple sequence of code:
+In GiNaC, there is an @emph{intrusive reference-counting} mechanism at work
+where the counter belongs to the algebraic objects derived from class
+@code{basic} but is maintained by the smart pointer class @code{ptr}, of
+which @code{ex} contains an instance. If you understood that, you can safely
+skip the rest of this passage.
+
+Expressions are extremely light-weight since internally they work like
+handles to the actual representation. They really hold nothing more
+than a pointer to some other object. What this means in practice is
+that whenever you create two @code{ex} and set the second equal to the
+first no copying process is involved. Instead, the copying takes place
+as soon as you try to change the second. Consider the simple sequence
+of code:
@example
#include <iostream>
@example
#include <ginac/ginac.h>
-int main(void)
+int main()
@{
GiNaC::symbol x("x");
GiNaC::ex a = GiNaC::sin(x);
@item
@cite{Computer Algebra: Systems and Algorithms for Algebraic Computation},
-James H. Davenport, Yvon Siret, and Evelyne Tournier, ISBN 0-12-204230-1, 1988,
+James H. Davenport, Yvon Siret and Evelyne Tournier, ISBN 0-12-204230-1, 1988,
Academic Press, London
@item
@cite{The Art of Computer Programming, Vol 2: Seminumerical Algorithms},
Donald E. Knuth, ISBN 0-201-89684-2, 1998, Addison Wesley
+@item
+@cite{Pi Unleashed}, J@"org Arndt and Christoph Haenel,
+ISBN 3-540-66572-2, 2001, Springer, Heidelberg
+
@item
@cite{The Role of gamma5 in Dimensional Regularization}, Dirk Kreimer, hep-ph/9401354
prototype for exit() that conflicts with the one in stdlib.h */
extern "C" int system(const char *);
-int main(void)
+int main()
{
int major, minor, micro;
char *tmp_version;
## Process this file with automake to produce Makefile.in
lib_LTLIBRARIES = libginac.la
-libginac_la_SOURCES = add.cpp archive.cpp basic.cpp constant.cpp ex.cpp \
- expair.cpp expairseq.cpp exprseq.cpp fail.cpp function.cpp inifcns.cpp \
- inifcns_trans.cpp inifcns_zeta.cpp inifcns_gamma.cpp matrix.cpp mul.cpp \
- normal.cpp numeric.cpp operators.cpp power.cpp registrar.cpp relational.cpp \
- symbol.cpp pseries.cpp utils.cpp ncmul.cpp structure.cpp exprseq_suppl.cpp \
- lst.cpp lst_suppl.cpp input_parser.yy input_lexer.ll input_lexer.h \
- remember.h remember.cpp utils.h idx.cpp indexed.cpp tensor.cpp color.cpp \
- clifford.cpp wildcard.cpp print.cpp symmetry.cpp fderivative.cpp tostring.h
+libginac_la_SOURCES = add.cpp archive.cpp basic.cpp clifford.cpp color.cpp \
+ constant.cpp ex.cpp expair.cpp expairseq.cpp exprseq.cpp fail.cpp \
+ fderivative.cpp function.cpp idx.cpp indexed.cpp inifcns.cpp \
+ inifcns_trans.cpp inifcns_zeta.cpp inifcns_gamma.cpp lst.cpp matrix.cpp \
+ mul.cpp ncmul.cpp normal.cpp numeric.cpp operators.cpp power.cpp \
+ registrar.cpp relational.cpp remember.cpp pseries.cpp print.cpp structure.cpp \
+ symbol.cpp symmetry.cpp tensor.cpp utils.cpp wildcard.cpp \
+ input_parser.yy input_lexer.ll \
+ input_lexer.h remember.h tostring.h utils.h
libginac_la_LDFLAGS = -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \
-release $(LT_RELEASE)
ginacincludedir = $(includedir)/ginac
-ginacinclude_HEADERS = ginac.h add.h archive.h basic.h constant.h ex.h \
- expair.h expairseq.h exprseq.h fail.h flags.h function.h inifcns.h \
- lst.h matrix.h mul.h ncmul.h normal.h numeric.h operators.h power.h \
- registrar.h relational.h pseries.h structure.h symbol.h tinfos.h assertion.h \
- version.h idx.h indexed.h tensor.h color.h clifford.h wildcard.h print.h \
- symmetry.h fderivative.h
+ginacinclude_HEADERS = ginac.h add.h archive.h assertion.h basic.h clifford.h \
+ color.h constant.h container.h ex.h expair.h expairseq.h exprseq.h fail.h \
+ fderivative.h flags.h function.h idx.h indexed.h inifcns.h lst.h matrix.h \
+ mul.h ncmul.h normal.h numeric.h operators.h power.h print.h pseries.h ptr.h \
+ registrar.h relational.h structure.h symbol.h symmetry.h tensor.h tinfos.h \
+ version.h wildcard.h
LFLAGS = -Pginac_yy -olex.yy.c
YFLAGS = -p ginac_yy -d
-EXTRA_DIST = container.pl function.pl structure.pl input_parser.h version.h.in
+EXTRA_DIST = function.pl input_parser.h version.h.in
# Files which are generated by perl scripts
$(srcdir)/function.h $(srcdir)/function.cpp: $(srcdir)/function.pl
cd $(srcdir) && perl -w function.pl
-$(srcdir)/lst.h $(srcdir)/lst.cpp: $(srcdir)/container.pl
- cd $(srcdir) && perl -w container.pl lst
-
-$(srcdir)/exprseq.h $(srcdir)/exprseq.cpp: $(srcdir)/container.pl
- cd $(srcdir) && perl -w container.pl exprseq
-
# Force build of headers before compilation
-$(srcdir)/add.cpp: $(srcdir)/function.h $(srcdir)/lst.h $(srcdir)/exprseq.h
+$(srcdir)/add.cpp: $(srcdir)/function.h
#include "add.h"
#include "mul.h"
-#include "matrix.h"
#include "archive.h"
+#include "operators.h"
+#include "matrix.h"
#include "utils.h"
namespace GiNaC {
GINAC_IMPLEMENT_REGISTERED_CLASS(add, expairseq)
//////////
-// default ctor, dtor, copy ctor, assignment operator and helpers
+// default constructor
//////////
add::add()
tinfo_key = TINFO_add;
}
-DEFAULT_COPY(add)
-DEFAULT_DESTROY(add)
-
//////////
// other constructors
//////////
c.s << class_name() << '(';
op(0).print(c);
- for (unsigned i=1; i<nops(); ++i) {
+ for (size_t i=1; i<nops(); ++i) {
c.s << ',';
op(i).print(c);
}
epvector::const_iterator i = seq.begin(), end = seq.end();
while (i != end) {
GINAC_ASSERT(!is_exactly_a<add>(i->rest));
- if (is_ex_exactly_of_type(i->rest,numeric))
+ if (is_exactly_a<numeric>(i->rest))
dbgprint();
GINAC_ASSERT(!is_exactly_a<numeric>(i->rest));
++i;
return this->hold();
}
-ex add::evalm(void) const
+ex add::evalm() const
{
// Evaluate children first and add up all matrices. Stop if there's one
// term that is not a matrix.
while (it != itend) {
const ex &m = recombine_pair_to_ex(*it).evalm();
s->push_back(split_ex_to_pair(m));
- if (is_ex_of_type(m, matrix)) {
+ if (is_a<matrix>(m)) {
if (first_term) {
sum = ex_to<matrix>(m);
first_term = false;
return (new add(s, overall_coeff))->setflag(status_flags::dynallocated);
}
-ex add::simplify_ncmul(const exvector & v) const
+ex add::eval_ncmul(const exvector & v) const
{
if (seq.empty())
- return inherited::simplify_ncmul(v);
+ return inherited::eval_ncmul(v);
else
- return seq.begin()->rest.simplify_ncmul(v);
+ return seq.begin()->rest.eval_ncmul(v);
}
// protected
return inherited::compare_same_type(other);
}
-bool add::is_equal_same_type(const basic & other) const
-{
- return inherited::is_equal_same_type(other);
-}
-
-unsigned add::return_type(void) const
+unsigned add::return_type() const
{
if (seq.empty())
return return_types::commutative;
return seq.begin()->rest.return_type();
}
-unsigned add::return_type_tinfo(void) const
+unsigned add::return_type_tinfo() const
{
if (seq.empty())
return tinfo_key;
expair add::split_ex_to_pair(const ex & e) const
{
- if (is_ex_exactly_of_type(e,mul)) {
+ if (is_exactly_a<mul>(e)) {
const mul &mulref(ex_to<mul>(e));
const ex &numfactor = mulref.overall_coeff;
mul *mulcopyp = new mul(mulref);
const ex & c) const
{
GINAC_ASSERT(is_exactly_a<numeric>(c));
- if (is_ex_exactly_of_type(e, mul)) {
+ if (is_exactly_a<mul>(e)) {
const mul &mulref(ex_to<mul>(e));
const ex &numfactor = mulref.overall_coeff;
mul *mulcopyp = new mul(mulref);
mulcopyp->clearflag(status_flags::evaluated);
mulcopyp->clearflag(status_flags::hash_calculated);
mulcopyp->setflag(status_flags::dynallocated);
- if (are_ex_trivially_equal(c, _ex1))
+ if (c.is_equal(_ex1))
return expair(*mulcopyp, numfactor);
- else if (are_ex_trivially_equal(numfactor, _ex1))
+ else if (numfactor.is_equal(_ex1))
return expair(*mulcopyp, c);
else
return expair(*mulcopyp, ex_to<numeric>(numfactor).mul_dyn(ex_to<numeric>(c)));
- } else if (is_ex_exactly_of_type(e, numeric)) {
- if (are_ex_trivially_equal(c, _ex1))
+ } else if (is_exactly_a<numeric>(e)) {
+ if (c.is_equal(_ex1))
return expair(e, _ex1);
return expair(ex_to<numeric>(e).mul_dyn(ex_to<numeric>(c)), _ex1);
}
GINAC_ASSERT(is_exactly_a<numeric>(p.coeff));
GINAC_ASSERT(is_exactly_a<numeric>(c));
- if (is_ex_exactly_of_type(p.rest,numeric)) {
+ if (is_exactly_a<numeric>(p.rest)) {
GINAC_ASSERT(ex_to<numeric>(p.coeff).is_equal(_num1)); // should be normalized
return expair(ex_to<numeric>(p.rest).mul_dyn(ex_to<numeric>(c)),_ex1);
}
// functions overriding virtual functions from base classes
public:
void print(const print_context & c, unsigned level = 0) const;
- unsigned precedence(void) const {return 40;}
+ unsigned precedence() const {return 40;}
bool info(unsigned inf) const;
int degree(const ex & s) const;
int ldegree(const ex & s) const;
ex coeff(const ex & s, int n=1) const;
ex eval(int level=0) const;
- ex evalm(void) const;
+ ex evalm() const;
ex series(const relational & r, int order, unsigned options = 0) const;
ex normal(lst &sym_lst, lst &repl_lst, int level=0) const;
- numeric integer_content(void) const;
+ numeric integer_content() const;
ex smod(const numeric &xi) const;
- numeric max_coefficient(void) const;
- exvector get_free_indices(void) const;
- ex simplify_ncmul(const exvector & v) const;
+ numeric max_coefficient() const;
+ exvector get_free_indices() const;
+ ex eval_ncmul(const exvector & v) const;
protected:
ex derivative(const symbol & s) const;
- bool is_equal_same_type(const basic & other) const;
- unsigned return_type(void) const;
- unsigned return_type_tinfo(void) const;
+ unsigned return_type() const;
+ unsigned return_type_tinfo() const;
ex thisexpairseq(const epvector & v, const ex & oc) const;
ex thisexpairseq(epvector * vp, const ex & oc) const;
expair split_ex_to_pair(const ex & e) const;
#include "archive.h"
#include "registrar.h"
#include "ex.h"
+#include "lst.h"
#include "config.h"
#include "tostring.h"
* @return ID of archived node */
archive_node_id archive::add_node(const archive_node &n)
{
- // Search for node in nodes vector
- std::vector<archive_node>::const_iterator i = nodes.begin(), iend = nodes.end();
- archive_node_id id = 0;
- while (i != iend) {
- if (i->has_same_ex_as(n))
- return id;
- i++; id++;
+ // Look if expression is known to be in some node already.
+ if (n.has_ex()) {
+ mapit i = exprtable.find(n.get_ex());
+ if (i != exprtable.end())
+ return i->second;
+ nodes.push_back(n);
+ exprtable[n.get_ex()] = nodes.size() - 1;
+ return nodes.size() - 1;
}
// Not found, add archive_node to nodes vector
nodes.push_back(n);
- return id;
+ return nodes.size()-1;
}
found:
// Recursively unarchive all nodes, starting at the root node
- return nodes[i->root].unarchive(sym_lst);
+ lst sym_lst_copy = sym_lst;
+ return nodes[i->root].unarchive(sym_lst_copy);
}
ex archive::unarchive_ex(const lst &sym_lst, unsigned index) const
throw (std::range_error("index of archived expression out of range"));
// Recursively unarchive all nodes, starting at the root node
- return nodes[exprs[index].root].unarchive(sym_lst);
+ lst sym_lst_copy = sym_lst;
+ return nodes[exprs[index].root].unarchive(sym_lst_copy);
}
ex archive::unarchive_ex(const lst &sym_lst, std::string &name, unsigned index) const
name = unatomize(exprs[index].name);
// Recursively unarchive all nodes, starting at the root node
- return nodes[exprs[index].root].unarchive(sym_lst);
+ lst sym_lst_copy = sym_lst;
+ return nodes[exprs[index].root].unarchive(sym_lst_copy);
}
-unsigned archive::num_expressions(void) const
+unsigned archive::num_expressions() const
{
return exprs.size();
}
}
-/** Copy constructor of archive_node. */
-archive_node::archive_node(const archive_node &other)
- : a(other.a), props(other.props), has_expression(other.has_expression), e(other.e)
-{
-}
-
-
/** Assignment operator of archive_node. */
const archive_node &archive_node::operator=(const archive_node &other)
{
if (this != &other) {
- a = other.a;
+ // archive &a member doesn't get copied
props = other.props;
has_expression = other.has_expression;
e = other.e;
return false;
}
-bool archive_node::find_ex(const std::string &name, ex &ret, const lst &sym_lst, unsigned index) const
+bool archive_node::find_ex(const std::string &name, ex &ret, lst &sym_lst, unsigned index) const
{
archive_atom name_atom = a.atomize(name);
std::vector<property>::const_iterator i = props.begin(), iend = props.end();
/** Convert archive node to GiNaC expression. */
-ex archive_node::unarchive(const lst &sym_lst) const
+ex archive_node::unarchive(lst &sym_lst) const
{
// Already unarchived? Then return cached unarchived expression.
if (has_expression)
}
-/** Assignment operator of property_info. */
-const archive_node::property_info &archive_node::property_info::operator=(const property_info &other)
-{
- if (this != &other) {
- type = other.type;
- name = other.name;
- count = other.count;
- }
- return *this;
-}
-
-/** Assignment operator of property. */
-const archive_node::property &archive_node::property::operator=(const property &other)
-{
- if (this != &other) {
- type = other.type;
- name = other.name;
- value = other.value;
- }
- return *this;
-}
-
-
-void archive::clear(void)
+void archive::clear()
{
atoms.clear();
exprs.clear();
nodes.clear();
+ exprtable.clear();
}
/** Delete cached unarchived expressions in all archive_nodes (mainly for debugging). */
-void archive::forget(void)
+void archive::forget()
{
for_each(nodes.begin(), nodes.end(), std::mem_fun_ref(&archive_node::forget));
}
/** Delete cached unarchived expressions from node (for debugging). */
-void archive_node::forget(void)
+void archive_node::forget()
{
has_expression = false;
e = 0;
/** Create a dummy archive. The intention is to fill archive_node's default
* ctor, which is currently a Cint-requirement. */
-archive* archive_node::dummy_ar_creator(void)
+archive* archive_node::dummy_ar_creator()
{
static archive* some_ar = new archive;
return some_ar;
#include <iosfwd>
#include <string>
#include <vector>
+#include <map>
namespace GiNaC {
-class lst;
class archive;
struct property_info {
property_info() {}
property_info(property_type t, const std::string &n, unsigned c = 1) : type(t), name(n), count(c) {}
- ~property_info() {}
-
- property_info(const property_info &other) : type(other.type), name(other.name), count(other.count) {}
- const property_info &operator=(const property_info &other);
property_type type; /**< Data type of property. */
std::string name; /**< Name of property. */
archive_node() : a(*dummy_ar_creator()), has_expression(false) {} // hack for cint which always requires a default constructor
archive_node(archive &ar) : a(ar), has_expression(false) {}
archive_node(archive &ar, const ex &expr);
- ~archive_node() {}
- archive_node(const archive_node &other);
const archive_node &operator=(const archive_node &other);
/** Add property of type "bool" to node. */
/** Retrieve property of type "ex" from node.
* @return "true" if property was found, "false" otherwise */
- bool find_ex(const std::string &name, ex &ret, const lst &sym_lst, unsigned index = 0) const;
+ bool find_ex(const std::string &name, ex &ret, lst &sym_lst, unsigned index = 0) const;
/** Retrieve property of type "ex" from node, returning the node of
* the sub-expression. */
/** Return vector of properties stored in node. */
void get_properties(propinfovector &v) const;
- ex unarchive(const lst &sym_lst) const;
+ ex unarchive(lst &sym_lst) const;
bool has_same_ex_as(const archive_node &other) const;
+ bool has_ex() const {return has_expression;}
+ ex get_ex() const {return e;}
- void forget(void);
+ void forget();
void printraw(std::ostream &os) const;
private:
- static archive* dummy_ar_creator(void);
+ static archive* dummy_ar_creator();
/** Archived property (data type, name and associated data) */
struct property {
property() {}
property(archive_atom n, property_type t, unsigned v) : type(t), name(n), value(v) {}
- ~property() {}
-
- property(const property &other) : type(other.type), name(other.name), value(other.value) {}
- const property &operator=(const property &other);
property_type type; /**< Data type of property. */
archive_atom name; /**< Name of property. */
ex unarchive_ex(const lst &sym_lst, std::string &name, unsigned index = 0) const;
/** Return number of archived expressions. */
- unsigned num_expressions(void) const;
+ unsigned num_expressions() const;
/** Return reference to top node of an expression specified by index. */
const archive_node &get_top_node(unsigned index = 0) const;
/** Clear all archived expressions. */
- void clear(void);
+ void clear();
archive_node_id add_node(const archive_node &n);
archive_node &get_node(archive_node_id id);
- void forget(void);
+ void forget();
void printraw(std::ostream &os) const;
private:
private:
/** Vector of atomized strings (using a vector allows faster unarchiving). */
mutable std::vector<std::string> atoms;
+
+ /** Map of stored expressions to nodes for faster archiving */
+ typedef std::map<ex, archive_node_id, ex_is_less>::iterator mapit;
+ mutable std::map<ex, archive_node_id, ex_is_less> exprtable;
};
#include "lst.h"
#include "ncmul.h"
#include "relational.h"
+#include "operators.h"
#include "wildcard.h"
#include "print.h"
#include "archive.h"
namespace GiNaC {
-GINAC_IMPLEMENT_REGISTERED_CLASS_NO_CTORS(basic, void)
+GINAC_IMPLEMENT_REGISTERED_CLASS(basic, void)
//////////
-// default ctor, dtor, copy ctor, assignment operator and helpers
+// default constructor, destructor, copy constructor and assignment operator
//////////
// public
-basic::basic(const basic & other) : tinfo_key(TINFO_basic), flags(0), refcount(0)
+/** basic copy constructor: implicitly assumes that the other class is of
+ * the exact same type (as it's used by duplicate()), so it can copy the
+ * tinfo_key and the hash value. */
+basic::basic(const basic & other) : tinfo_key(other.tinfo_key), flags(other.flags & ~status_flags::dynallocated), hashvalue(other.hashvalue), refcount(0)
{
- copy(other);
+ GINAC_ASSERT(typeid(*this) == typeid(other));
}
+/** basic assignment operator: the other object might be of a derived class. */
const basic & basic::operator=(const basic & other)
{
- if (this != &other) {
- destroy(true);
- copy(other);
+ unsigned fl = other.flags & ~status_flags::dynallocated;
+ if (tinfo_key != other.tinfo_key) {
+ // The other object is of a derived class, so clear the flags as they
+ // might no longer apply (especially hash_calculated). Oh, and don't
+ // copy the tinfo_key: it is already set correctly for this object.
+ flags = 0;
+ } else {
+ // The objects are of the exact same class, so copy the hash value.
+ hashvalue = other.hashvalue;
}
+ flags = fl;
+ refcount = 0;
return *this;
}
// protected
-// none (all conditionally inlined)
+// none (all inlined)
//////////
-// other ctors
+// other constructors
//////////
-// none (all conditionally inlined)
+// none (all inlined)
//////////
// archiving
//////////
/** Construct object from archive_node. */
-basic::basic(const archive_node &n, const lst &sym_lst) : flags(0), refcount(0)
+basic::basic(const archive_node &n, lst &sym_lst) : flags(0), refcount(0)
{
// Reconstruct tinfo_key from class name
std::string class_name;
* level for placing parentheses and formatting */
void basic::print(const print_context & c, unsigned level) const
{
- if (is_of_type(c, print_tree)) {
+ if (is_a<print_tree>(c)) {
c.s << std::string(level, ' ') << class_name()
<< std::hex << ", hash=0x" << hashvalue << ", flags=0x" << flags << std::dec
<< ", nops=" << nops()
<< std::endl;
- for (unsigned i=0; i<nops(); ++i)
+ for (size_t i=0; i<nops(); ++i)
op(i).print(c, level + static_cast<const print_tree &>(c).delta_indent);
} else
* debugger because it might not know what cout is. This method can be
* invoked with no argument and it will simply print to stdout.
*
- * @see basic::print */
-void basic::dbgprint(void) const
+ * @see basic::print
+ * @see basic::dbgprinttree */
+void basic::dbgprint() const
{
this->print(std::cerr);
std::cerr << std::endl;
/** Little wrapper around printtree to be called within a debugger.
*
- * @see basic::dbgprint
- * @see basic::printtree */
-void basic::dbgprinttree(void) const
+ * @see basic::dbgprint */
+void basic::dbgprinttree() const
{
this->print(print_tree(std::cerr));
}
/** Return relative operator precedence (for parenthizing output). */
-unsigned basic::precedence(void) const
+unsigned basic::precedence() const
{
return 70;
}
-/** Create a new copy of this on the heap. One can think of this as simulating
- * a virtual copy constructor which is needed for instance by the refcounted
- * construction of an ex from a basic. */
-basic * basic::duplicate() const
-{
- return new basic(*this);
-}
-
/** Information about the object.
*
* @see class info_flags */
}
/** Number of operands/members. */
-unsigned basic::nops() const
+size_t basic::nops() const
{
// iterating from 0 to nops() on atomic objects should be an empty loop,
// and accessing their elements is a range error. Container objects should
}
/** Return operand/member at position i. */
-ex basic::op(int i) const
+ex basic::op(size_t i) const
{
- return (const_cast<basic *>(this))->let_op(i);
+ throw(std::range_error(std::string("basic::op(): ") + class_name() + std::string(" has no operands")));
}
/** Return modifyable operand/member at position i. */
-ex & basic::let_op(int i)
+ex & basic::let_op(size_t i)
{
- throw(std::out_of_range("op() out of range"));
+ ensure_if_modifiable();
+ throw(std::range_error(std::string("basic::let_op(): ") + class_name() + std::string(" has no operands")));
}
ex basic::operator[](const ex & index) const
{
- if (is_ex_exactly_of_type(index,numeric))
- return op(ex_to<numeric>(index).to_int());
+ if (is_exactly_a<numeric>(index))
+ return op(static_cast<size_t>(ex_to<numeric>(index).to_int()));
- throw(std::invalid_argument("non-numeric indices not supported by this type"));
+ throw(std::invalid_argument(std::string("non-numeric indices not supported by ") + class_name()));
}
-ex basic::operator[](int i) const
+ex basic::operator[](size_t i) const
{
return op(i);
}
+ex & basic::operator[](const ex & index)
+{
+ if (is_exactly_a<numeric>(index))
+ return let_op(ex_to<numeric>(index).to_int());
+
+ throw(std::invalid_argument(std::string("non-numeric indices not supported by ") + class_name()));
+}
+
+ex & basic::operator[](size_t i)
+{
+ return let_op(i);
+}
+
/** Test for occurrence of a pattern. An object 'has' a pattern if it matches
* the pattern itself or one of the children 'has' it. As a consequence
* (according to the definition of children) given e=x+y+z, e.has(x) is true
lst repl_lst;
if (match(pattern, repl_lst))
return true;
- for (unsigned i=0; i<nops(); i++)
+ for (size_t i=0; i<nops(); i++)
if (op(i).has(pattern))
return true;
* sub-expressions (one level only, not recursively). */
ex basic::map(map_function & f) const
{
- unsigned num = nops();
+ size_t num = nops();
if (num == 0)
return *this;
basic *copy = duplicate();
copy->setflag(status_flags::dynallocated);
copy->clearflag(status_flags::hash_calculated | status_flags::expanded);
- ex e(*copy);
- for (unsigned i=0; i<num; i++)
- e.let_op(i) = f(e.op(i));
- return e.eval();
+ for (size_t i=0; i<num; i++)
+ copy->let_op(i) = f(copy->op(i));
+ return *copy;
}
/** Return degree of highest power in object s. */
ex basic::collect(const ex & s, bool distributed) const
{
ex x;
- if (is_ex_of_type(s, lst)) {
+ if (is_a<lst>(s)) {
// List of objects specified
if (s.nops() == 0)
else if (distributed) {
// Get lower/upper degree of all symbols in list
- int num = s.nops();
+ size_t num = s.nops();
struct sym_info {
ex sym;
int ldeg, deg;
};
sym_info *si = new sym_info[num];
ex c = *this;
- for (int i=0; i<num; i++) {
+ for (size_t i=0; i<num; i++) {
si[i].sym = s.op(i);
si[i].ldeg = si[i].cnt = this->ldegree(si[i].sym);
si[i].deg = this->degree(si[i].sym);
// Calculate coeff*x1^c1*...*xn^cn
ex y = _ex1;
- for (int i=0; i<num; i++) {
+ for (size_t i=0; i<num; i++) {
int cnt = si[i].cnt;
y *= power(si[i].sym, cnt);
}
x += y * si[num - 1].coeff;
// Increment counters
- int n = num - 1;
+ size_t n = num - 1;
while (true) {
++si[n].cnt;
if (si[n].cnt <= si[n].deg) {
c = *this;
else
c = si[n - 1].coeff;
- for (int i=n; i<num; i++)
+ for (size_t i=n; i<num; i++)
c = si[i].coeff = c.coeff(si[i].sym, si[i].cnt);
break;
}
// Recursive form
x = *this;
- for (int n=s.nops()-1; n>=0; n--)
+ size_t n = s.nops() - 1;
+ while (true) {
x = x.collect(s[n]);
+ if (n == 0)
+ break;
+ n--;
+ }
}
} else {
ex basic::eval(int level) const
{
// There is nothing to do for basic objects:
- return this->hold();
+ return hold();
}
/** Function object to be applied by basic::evalf(). */
} map_evalm;
/** Evaluate sums, products and integer powers of matrices. */
-ex basic::evalm(void) const
+ex basic::evalm() const
{
if (nops() == 0)
return *this;
Bog is the king of Pattern.
*/
- if (is_ex_exactly_of_type(pattern, wildcard)) {
+ if (is_exactly_a<wildcard>(pattern)) {
// Wildcard matches anything, but check whether we already have found
// a match for that wildcard first (if so, it the earlier match must
// be the same expression)
- for (unsigned i=0; i<repl_lst.nops(); i++) {
- if (repl_lst.op(i).op(0).is_equal(pattern))
- return is_equal(ex_to<basic>(repl_lst.op(i).op(1)));
+ for (lst::const_iterator it = repl_lst.begin(); it != repl_lst.end(); ++it) {
+ if (it->op(0).is_equal(pattern))
+ return is_equal(ex_to<basic>(it->op(1)));
}
repl_lst.append(pattern == *this);
return true;
return false;
// Otherwise the subexpressions must match one-to-one
- for (unsigned i=0; i<nops(); i++)
+ for (size_t i=0; i<nops(); i++)
if (!op(i).match(pattern.op(i), repl_lst))
return false;
}
}
-/** Substitute a set of objects by arbitrary expressions. The ex returned
- * will already be evaluated. */
-ex basic::subs(const lst & ls, const lst & lr, bool no_pattern) const
+/** Helper function for subs(). Does not recurse into subexpressions. */
+ex basic::subs_one_level(const lst & ls, const lst & lr, unsigned options) const
{
GINAC_ASSERT(ls.nops() == lr.nops());
- if (no_pattern) {
- for (unsigned i=0; i<ls.nops(); i++) {
- if (is_equal(ex_to<basic>(ls.op(i))))
- return lr.op(i);
+ lst::const_iterator its, itr;
+
+ if (options & subs_options::subs_no_pattern) {
+ for (its = ls.begin(), itr = lr.begin(); its != ls.end(); ++its, ++itr) {
+ if (is_equal(ex_to<basic>(*its)))
+ return *itr;
}
} else {
- for (unsigned i=0; i<ls.nops(); i++) {
+ for (its = ls.begin(), itr = lr.begin(); its != ls.end(); ++its, ++itr) {
lst repl_lst;
- if (match(ex_to<basic>(ls.op(i)), repl_lst))
- return lr.op(i).subs(repl_lst, true); // avoid infinite recursion when re-substituting the wildcards
+ if (match(ex_to<basic>(*its), repl_lst))
+ return itr->subs(repl_lst, options | subs_options::subs_no_pattern); // avoid infinite recursion when re-substituting the wildcards
}
}
return *this;
}
+/** Substitute a set of objects by arbitrary expressions. The ex returned
+ * will already be evaluated. */
+ex basic::subs(const lst & ls, const lst & lr, unsigned options) const
+{
+ size_t num = nops();
+ if (num) {
+
+ // Substitute in subexpressions
+ for (size_t i=0; i<num; i++) {
+ const ex & orig_op = op(i);
+ const ex & subsed_op = orig_op.subs(ls, lr, options);
+ if (!are_ex_trivially_equal(orig_op, subsed_op)) {
+
+ // Something changed, clone the object
+ basic *copy = duplicate();
+ copy->setflag(status_flags::dynallocated);
+ copy->clearflag(status_flags::hash_calculated | status_flags::expanded);
+
+ // Substitute the changed operand
+ copy->let_op(i++) = subsed_op;
+
+ // Substitute the other operands
+ for (; i<num; i++)
+ copy->let_op(i) = op(i).subs(ls, lr, options);
+
+ // Perform substitutions on the new object as a whole
+ return copy->subs_one_level(ls, lr, options);
+ }
+ }
+ }
+
+ // Nothing changed or no subexpressions
+ return subs_one_level(ls, lr, options);
+}
+
/** Default interface of nth derivative ex::diff(s, n). It should be called
* instead of ::derivative(s) for first derivatives and for nth derivatives it
* just recurses down.
}
/** Return a vector containing the free indices of an expression. */
-exvector basic::get_free_indices(void) const
+exvector basic::get_free_indices() const
{
return exvector(); // return an empty exvector
}
-ex basic::simplify_ncmul(const exvector & v) const
+ex basic::eval_ncmul(const exvector & v) const
{
- return simplified_ncmul(v);
+ return hold_ncmul(v);
}
// protected
return true;
}
-unsigned basic::return_type(void) const
+unsigned basic::return_type() const
{
return return_types::commutative;
}
-unsigned basic::return_type_tinfo(void) const
+unsigned basic::return_type_tinfo() const
{
return tinfo();
}
* members. For this reason it is well suited for container classes but
* atomic classes should override this implementation because otherwise they
* would all end up with the same hashvalue. */
-unsigned basic::calchash(void) const
+unsigned basic::calchash() const
{
unsigned v = golden_ratio_hash(tinfo());
- for (unsigned i=0; i<nops(); i++) {
- v = rotate_left_31(v);
+ for (size_t i=0; i<nops(); i++) {
+ v = rotate_left(v);
v ^= (const_cast<basic *>(this))->op(i).gethash();
}
-
- // mask out numeric hashes:
- v &= 0x7FFFFFFFU;
-
+
// store calculated hash value only if object is already evaluated
if (flags & status_flags::evaluated) {
setflag(status_flags::hash_calculated);
* replacement arguments: 1) a relational like object==ex and 2) a list of
* relationals lst(object1==ex1,object2==ex2,...), which is converted to
* subs(lst(object1,object2,...),lst(ex1,ex2,...)). */
-ex basic::subs(const ex & e, bool no_pattern) const
+ex basic::subs(const ex & e, unsigned options) const
{
if (e.info(info_flags::relation_equal)) {
- return subs(lst(e), no_pattern);
+ return subs(lst(e), options);
}
if (!e.info(info_flags::list)) {
throw(std::invalid_argument("basic::subs(ex): argument must be a list"));
}
+
+ // Split list into two
lst ls;
lst lr;
- for (unsigned i=0; i<e.nops(); i++) {
- ex r = e.op(i);
+ GINAC_ASSERT(is_a<lst>(e));
+ for (lst::const_iterator it = ex_to<lst>(e).begin(); it != ex_to<lst>(e).end(); ++it) {
+ ex r = *it;
if (!r.info(info_flags::relation_equal)) {
throw(std::invalid_argument("basic::subs(ex): argument must be a list of equations"));
}
ls.append(r.op(0));
lr.append(r.op(1));
}
- return subs(ls, lr, no_pattern);
+ return subs(ls, lr, options);
}
-/** Compare objects to establish canonical ordering.
+/** Compare objects syntactically to establish canonical ordering.
* All compare functions return: -1 for *this less than other, 0 equal,
* 1 greater. */
int basic::compare(const basic & other) const
{
- unsigned hash_this = gethash();
- unsigned hash_other = other.gethash();
-
+ const unsigned hash_this = gethash();
+ const unsigned hash_other = other.gethash();
if (hash_this<hash_other) return -1;
if (hash_this>hash_other) return 1;
-
- unsigned typeid_this = tinfo();
- unsigned typeid_other = other.tinfo();
-
- if (typeid_this<typeid_other) {
-// std::cout << "hash collision, different types: "
-// << *this << " and " << other << std::endl;
-// this->print(print_tree(std::cout));
-// std::cout << " and ";
-// other.print(print_tree(std::cout));
-// std::cout << std::endl;
- return -1;
- }
- if (typeid_this>typeid_other) {
+
+ const unsigned typeid_this = tinfo();
+ const unsigned typeid_other = other.tinfo();
+ if (typeid_this==typeid_other) {
+ GINAC_ASSERT(typeid(*this)==typeid(other));
+// int cmpval = compare_same_type(other);
+// if (cmpval!=0) {
+// std::cout << "hash collision, same type: "
+// << *this << " and " << other << std::endl;
+// this->print(print_tree(std::cout));
+// std::cout << " and ";
+// other.print(print_tree(std::cout));
+// std::cout << std::endl;
+// }
+// return cmpval;
+ return compare_same_type(other);
+ } else {
// std::cout << "hash collision, different types: "
// << *this << " and " << other << std::endl;
// this->print(print_tree(std::cout));
// std::cout << " and ";
// other.print(print_tree(std::cout));
// std::cout << std::endl;
- return 1;
+ return (typeid_this<typeid_other ? -1 : 1);
}
-
- GINAC_ASSERT(typeid(*this)==typeid(other));
-
-// int cmpval = compare_same_type(other);
-// if ((cmpval!=0) && (hash_this<0x80000000U)) {
-// std::cout << "hash collision, same type: "
-// << *this << " and " << other << std::endl;
-// this->print(print_tree(std::cout));
-// std::cout << " and ";
-// other.print(print_tree(std::cout));
-// std::cout << std::endl;
-// }
-// return cmpval;
-
- return compare_same_type(other);
}
-/** Test for equality.
+/** Test for syntactic equality.
* This is only a quick test, meaning objects should be in the same domain.
* You might have to .expand(), .normal() objects first, depending on the
* domain of your computation, to get a more reliable answer.
/** Stop further evaluation.
*
* @see basic::eval */
-const basic & basic::hold(void) const
+const basic & basic::hold() const
{
return setflag(status_flags::evaluated);
}
/** Ensure the object may be modified without hurting others, throws if this
* is not the case. */
-void basic::ensure_if_modifiable(void) const
+void basic::ensure_if_modifiable() const
{
- if (this->refcount>1)
+ if (refcount > 1)
throw(std::runtime_error("cannot modify multiply referenced object"));
- clearflag(status_flags::hash_calculated);
+ clearflag(status_flags::hash_calculated | status_flags::evaluated);
}
//////////
#ifndef __GINAC_BASIC_H__
#define __GINAC_BASIC_H__
+#include <cstddef> // for size_t
#include <vector>
// CINT needs <algorithm> to work properly with <vector>
#include <algorithm>
namespace GiNaC {
class ex;
+class ex_is_less;
class symbol;
-class lst;
class numeric;
class relational;
class archive_node;
class print_context;
+template <class> class ptr;
typedef std::vector<ex> exvector;
};
+/** Degenerate base class for visitors. basic and derivative classes
+ * support Robert C. Martin's Acyclic Visitor pattern (cf.
+ * http://objectmentor.com/publications/acv.pdf). */
+class visitor {
+protected:
+ virtual ~visitor() {}
+};
+
+
/** This class is the ABC (abstract base class) of GiNaC's class hierarchy.
* It is responsible for the reference counting. */
class basic
GINAC_DECLARE_REGISTERED_CLASS_NO_CTORS(basic, void)
friend class ex;
+ friend class ptr<basic>;
- // default ctor, dtor, copy ctor, assignment operator and helpers
-public:
+ // default constructor, destructor, copy constructor and assignment operator
+protected:
basic() : tinfo_key(TINFO_basic), flags(0), refcount(0) {}
- /** basic dtor, virtual because class ex will delete objects via ptr. */
+
+public:
+ /** basic destructor, virtual because class ex will delete objects of
+ * derived classes via a basic*. */
virtual ~basic()
{
- destroy(false);
GINAC_ASSERT((!(flags & status_flags::dynallocated))||(refcount==0));
}
basic(const basic & other);
const basic & operator=(const basic & other);
+
protected:
- /** For use by copy ctor and assignment operator. */
- void copy(const basic & other)
- {
- flags = other.flags & ~status_flags::dynallocated;
- hashvalue = other.hashvalue;
- tinfo_key = other.tinfo_key;
- }
- /** For use by dtor and assignment operator. */
- virtual void destroy(bool call_parent) { }
-
- // other ctors
- /** ctor with specified tinfo_key */
+ /** Constructor with specified tinfo_key (used by derived classes instead
+ * of the default constructor to avoid assigning tinfo_key twice). */
basic(unsigned ti) : tinfo_key(ti), flags(0), refcount(0) {}
// new virtual functions which can be overridden by derived classes
public: // only const functions please (may break reference counting)
- virtual basic * duplicate() const;
+
+ /** Create a clone of this object on the heap. One can think of this as
+ * simulating a virtual copy constructor which is needed for instance by
+ * the refcounted construction of an ex from a basic. */
+ virtual basic * duplicate() const { return new basic(*this); }
+
+ // evaluation
+ virtual ex eval(int level = 0) const;
+ virtual ex evalf(int level = 0) const;
+ virtual ex evalm() const;
+protected:
+ virtual ex eval_ncmul(const exvector & v) const;
+public:
+ virtual ex eval_indexed(const basic & i) const;
+
+ // printing
virtual void print(const print_context & c, unsigned level = 0) const;
- virtual void dbgprint(void) const;
- virtual void dbgprinttree(void) const;
- virtual unsigned precedence(void) const;
+ virtual void dbgprint() const;
+ virtual void dbgprinttree() const;
+ virtual unsigned precedence() const;
+
+ // info
virtual bool info(unsigned inf) const;
- virtual unsigned nops() const;
- virtual ex op(int i) const;
- virtual ex & let_op(int i);
+
+ // operand access
+ virtual size_t nops() const;
+ virtual ex op(size_t i) const;
virtual ex operator[](const ex & index) const;
- virtual ex operator[](int i) const;
- virtual ex expand(unsigned options = 0) const;
+ virtual ex operator[](size_t i) const;
+ virtual ex & let_op(size_t i);
+ virtual ex & operator[](const ex & index);
+ virtual ex & operator[](size_t i);
+
+ // pattern matching
virtual bool has(const ex & other) const;
+ virtual bool match(const ex & pattern, lst & repl_lst) const;
+protected:
+ virtual bool match_same_type(const basic & other) const;
+public:
+
+ // substitutions
+ virtual ex subs(const lst & ls, const lst & lr, unsigned options = 0) const;
+
+ // function mapping
virtual ex map(map_function & f) const;
+
+ // visitors and tree traversal
+ virtual void accept(GiNaC::visitor & v) const
+ {
+ if (visitor *p = dynamic_cast<visitor *>(&v))
+ p->visit(*this);
+ }
+
+ // degree/coeff
virtual int degree(const ex & s) const;
virtual int ldegree(const ex & s) const;
virtual ex coeff(const ex & s, int n = 1) const;
+
+ // expand/collect
+ virtual ex expand(unsigned options = 0) const;
virtual ex collect(const ex & s, bool distributed = false) const;
- virtual ex eval(int level = 0) const;
- virtual ex evalf(int level = 0) const;
- virtual ex evalm(void) const;
+
+ // differentiation and series expansion
+protected:
+ virtual ex derivative(const symbol & s) const;
+public:
virtual ex series(const relational & r, int order, unsigned options = 0) const;
- virtual bool match(const ex & pattern, lst & repl_lst) const;
- virtual ex subs(const lst & ls, const lst & lr, bool no_pattern = false) const;
+
+ // rational functions
virtual ex normal(lst &sym_lst, lst &repl_lst, int level = 0) const;
virtual ex to_rational(lst &repl_lst) const;
- virtual numeric integer_content(void) const;
+ virtual ex to_polynomial(lst &repl_lst) const;
+
+ // polynomial algorithms
+ virtual numeric integer_content() const;
virtual ex smod(const numeric &xi) const;
- virtual numeric max_coefficient(void) const;
- virtual exvector get_free_indices(void) const;
- virtual ex eval_indexed(const basic & i) const;
+ virtual numeric max_coefficient() const;
+
+ // indexed objects
+ virtual exvector get_free_indices() const;
virtual ex add_indexed(const ex & self, const ex & other) const;
virtual ex scalar_mul_indexed(const ex & self, const numeric & other) const;
virtual bool contract_with(exvector::iterator self, exvector::iterator other, exvector & v) const;
- virtual unsigned return_type(void) const;
- virtual unsigned return_type_tinfo(void) const;
+
+ // noncommutativity
+ virtual unsigned return_type() const;
+ virtual unsigned return_type_tinfo() const;
+
protected: // functions that should be called from class ex only
- virtual ex derivative(const symbol & s) const;
virtual int compare_same_type(const basic & other) const;
virtual bool is_equal_same_type(const basic & other) const;
- virtual bool match_same_type(const basic & other) const;
- virtual unsigned calchash(void) const;
- virtual ex simplify_ncmul(const exvector & v) const;
+
+ virtual unsigned calchash() const;
// non-virtual functions in this class
public:
- ex subs(const ex & e, bool no_pattern = false) const;
- ex diff(const symbol & s, unsigned nth=1) const;
+ ex subs(const ex & e, unsigned options = 0) const;
+ ex subs_one_level(const lst & ls, const lst & lr, unsigned options) const;
+ ex diff(const symbol & s, unsigned nth = 1) const;
int compare(const basic & other) const;
bool is_equal(const basic & other) const;
- const basic & hold(void) const;
- unsigned gethash(void) const { if (flags & status_flags::hash_calculated) return hashvalue; else return calchash(); }
- unsigned tinfo(void) const {return tinfo_key;}
+ const basic & hold() const;
+ unsigned gethash() const { if (flags & status_flags::hash_calculated) return hashvalue; else return calchash(); }
+ unsigned tinfo() const {return tinfo_key;}
/** Set some status_flags. */
const basic & setflag(unsigned f) const {flags |= f; return *this;}
const basic & clearflag(unsigned f) const {flags &= ~f; return *this;}
protected:
- void ensure_if_modifiable(void) const;
+ void ensure_if_modifiable() const;
// member variables
protected:
mutable unsigned flags; ///< of type status_flags
mutable unsigned hashvalue; ///< hash value
private:
- unsigned refcount; ///< Number of reference counts
+ size_t refcount; ///< reference counter, managed by ptr<basic>
};
+
// global variables
extern int max_recursion_level;
+
// convenience type checker template functions
/** Check if obj is a T, including base classes. */
template <class T>
inline bool is_a(const basic &obj)
{
- return dynamic_cast<const T *>(&obj)!=0;
+ return dynamic_cast<const T *>(&obj) != 0;
}
/** Check if obj is a T, not including base classes. This one is just an
* inefficient default. It should in all time-critical cases be overridden
- * by template specializations that don't create a temporary. */
+ * by template specializations that use the TINFO_* constants directly. */
template <class T>
inline bool is_exactly_a(const class basic &obj)
{
- const T foo; return foo.tinfo()==obj.tinfo();
+ return obj.tinfo() == T::reg_info.tinfo_key;
}
/** Check if ex is a handle to a T, including base classes. */
#include "symmetry.h"
#include "lst.h"
#include "relational.h"
+#include "operators.h"
#include "mul.h"
#include "print.h"
#include "archive.h"
GINAC_IMPLEMENT_REGISTERED_CLASS(diracgammaR, tensor)
//////////
-// default ctor, dtor, copy ctor, assignment operator and helpers
+// default constructors
//////////
clifford::clifford() : representation_label(0)
tinfo_key = TINFO_clifford;
}
-void clifford::copy(const clifford & other)
-{
- inherited::copy(other);
- representation_label = other.representation_label;
-}
-
-DEFAULT_DESTROY(clifford)
-DEFAULT_CTORS(diracone)
-DEFAULT_CTORS(diracgamma)
-DEFAULT_CTORS(diracgamma5)
-DEFAULT_CTORS(diracgammaL)
-DEFAULT_CTORS(diracgammaR)
+DEFAULT_CTOR(diracone)
+DEFAULT_CTOR(diracgamma)
+DEFAULT_CTOR(diracgamma5)
+DEFAULT_CTOR(diracgammaL)
+DEFAULT_CTOR(diracgammaR)
//////////
// other constructors
// archiving
//////////
-clifford::clifford(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
+clifford::clifford(const archive_node &n, lst &sym_lst) : inherited(n, sym_lst)
{
unsigned rl;
n.find_unsigned("label", rl);
/** Perform automatic simplification on noncommutative product of clifford
* objects. This removes superfluous ONEs, permutes gamma5/L/R's to the front
* and removes squares of gamma objects. */
-ex clifford::simplify_ncmul(const exvector & v) const
+ex clifford::eval_ncmul(const exvector & v) const
{
exvector s;
s.reserve(v.size());
if (s.empty())
return clifford(diracone(), representation_label) * sign;
if (something_changed)
- return nonsimplified_ncmul(s) * sign;
+ return reeval_ncmul(s) * sign;
else
- return simplified_ncmul(s) * sign;
+ return hold_ncmul(s) * sign;
}
-ex clifford::thisexprseq(const exvector & v) const
+ex clifford::thiscontainer(const exvector & v) const
{
return clifford(representation_label, v);
}
-ex clifford::thisexprseq(exvector * vp) const
+ex clifford::thiscontainer(exvector * vp) const
{
return clifford(representation_label, vp);
}
return clifford(diracgammaR(), rl);
}
-ex dirac_gamma6(unsigned char rl)
-{
- return clifford(diracone(), rl) + clifford(diracgamma5(), rl);
-}
-
-ex dirac_gamma7(unsigned char rl)
-{
- return clifford(diracone(), rl) - clifford(diracgamma5(), rl);
-}
-
ex dirac_slash(const ex & e, const ex & dim, unsigned char rl)
{
// Slashed vectors are actually stored as a clifford object with the
/** Take trace of a string of an even number of Dirac gammas given a vector
* of indices. */
-static ex trace_string(exvector::const_iterator ix, unsigned num)
+static ex trace_string(exvector::const_iterator ix, size_t num)
{
// Tr gamma.mu gamma.nu = 4 g.mu.nu
if (num == 2)
return lorentz_g(ix[0], ix[1]);
- // Tr gamma.mu gamma.nu gamma.rho gamma.sig = 4 (g.mu.nu g.rho.sig + g.nu.rho g.mu.sig - g.mu.rho g.nu.sig
+ // Tr gamma.mu gamma.nu gamma.rho gamma.sig = 4 (g.mu.nu g.rho.sig + g.nu.rho g.mu.sig - g.mu.rho g.nu.sig )
else if (num == 4)
return lorentz_g(ix[0], ix[1]) * lorentz_g(ix[2], ix[3])
+ lorentz_g(ix[1], ix[2]) * lorentz_g(ix[0], ix[3])
exvector v(num - 2);
int sign = 1;
ex result;
- for (unsigned i=1; i<num; i++) {
- for (unsigned n=1, j=0; n<num; n++) {
+ for (size_t i=1; i<num; i++) {
+ for (size_t n=1, j=0; n<num; n++) {
if (n == i)
continue;
v[j++] = ix[n];
else
return _ex0;
- } else if (is_ex_exactly_of_type(e, mul)) {
+ } else if (is_exactly_a<mul>(e)) {
// Trace of product: pull out non-clifford factors
ex prod = _ex1;
- for (unsigned i=0; i<e.nops(); i++) {
+ for (size_t i=0; i<e.nops(); i++) {
const ex &o = e.op(i);
if (is_clifford_tinfo(o.return_type_tinfo(), rl))
prod *= dirac_trace(o, rl, trONE);
}
return prod;
- } else if (is_ex_exactly_of_type(e, ncmul)) {
+ } else if (is_exactly_a<ncmul>(e)) {
if (!is_clifford_tinfo(e.return_type_tinfo(), rl))
return _ex0;
// gamma5 gets moved to the front so this check is enough
bool has_gamma5 = is_a<diracgamma5>(e.op(0).op(0));
- unsigned num = e.nops();
+ size_t num = e.nops();
if (has_gamma5) {
// I/4! * epsilon0123.mu1.mu2.mu3.mu4 * Tr gamma.mu1 gamma.mu2 gamma.mu3 gamma.mu4 S_2k
// (the epsilon is always 4-dimensional)
exvector ix(num-1), bv(num-1);
- for (unsigned i=1; i<num; i++)
+ for (size_t i=1; i<num; i++)
base_and_index(e.op(i), bv[i-1], ix[i-1]);
num--;
int *iv = new int[num];
ex result;
- for (unsigned i=0; i<num-3; i++) {
+ for (size_t i=0; i<num-3; i++) {
ex idx1 = ix[i];
- for (unsigned j=i+1; j<num-2; j++) {
+ for (size_t j=i+1; j<num-2; j++) {
ex idx2 = ix[j];
- for (unsigned k=j+1; k<num-1; k++) {
+ for (size_t k=j+1; k<num-1; k++) {
ex idx3 = ix[k];
- for (unsigned l=k+1; l<num; l++) {
+ for (size_t l=k+1; l<num; l++) {
ex idx4 = ix[l];
iv[0] = i; iv[1] = j; iv[2] = k; iv[3] = l;
exvector v;
v.reserve(num - 4);
- for (unsigned n=0, t=4; n<num; n++) {
+ for (size_t n=0, t=4; n<num; n++) {
if (n == i || n == j || n == k || n == l)
continue;
iv[t++] = n;
}
exvector iv(num), bv(num);
- for (unsigned i=0; i<num; i++)
+ for (size_t i=0; i<num; i++)
base_and_index(e.op(i), bv[i], iv[i]);
return trONE * (trace_string(iv.begin(), num) * mul(bv)).simplify_indexed();
// Scan for any ncmul objects
lst srl;
ex aux = e.to_rational(srl);
- for (unsigned i=0; i<srl.nops(); i++) {
+ for (size_t i=0; i<srl.nops(); i++) {
- ex lhs = srl.op(i).lhs();
- ex rhs = srl.op(i).rhs();
+ ex o = srl.op(i);
+ ex lhs = o.lhs();
+ ex rhs = o.rhs();
- if (is_ex_exactly_of_type(rhs, ncmul)
+ if (is_exactly_a<ncmul>(rhs)
&& rhs.return_type() == return_types::noncommutative
&& is_clifford_tinfo(rhs.return_type_tinfo())) {
// Expand product, if necessary
ex rhs_expanded = rhs.expand();
if (!is_a<ncmul>(rhs_expanded)) {
- srl.let_op(i) = (lhs == canonicalize_clifford(rhs_expanded));
+ srl[i] = (lhs == canonicalize_clifford(rhs_expanded));
continue;
} else if (!is_a<clifford>(rhs.op(0)))
exvector v;
v.reserve(rhs.nops());
- for (unsigned j=0; j<rhs.nops(); j++)
+ for (size_t j=0; j<rhs.nops(); j++)
v.push_back(rhs.op(j));
// Stupid recursive bubble sort because we only want to swap adjacent gammas
it[0] = save1;
it[1] = save0;
sum -= ncmul(v, true);
- srl.let_op(i) = (lhs == canonicalize_clifford(sum));
+ srl[i] = (lhs == canonicalize_clifford(sum));
goto next_sym;
}
++it;
void print(const print_context & c, unsigned level = 0) const;
protected:
- ex simplify_ncmul(const exvector & v) const;
+ ex eval_ncmul(const exvector & v) const;
bool match_same_type(const basic & other) const;
- ex thisexprseq(const exvector & v) const;
- ex thisexprseq(exvector * vp) const;
- unsigned return_type(void) const { return return_types::noncommutative; }
- unsigned return_type_tinfo(void) const { return TINFO_clifford + representation_label; }
+ ex thiscontainer(const exvector & v) const;
+ ex thiscontainer(exvector * vp) const;
+ unsigned return_type() const { return return_types::noncommutative; }
+ unsigned return_type_tinfo() const { return TINFO_clifford + representation_label; }
// non-virtual functions in this class
public:
- unsigned char get_representation_label(void) const {return representation_label;}
+ unsigned char get_representation_label() const {return representation_label;}
// member variables
private:
* @return newly constructed object */
ex dirac_gammaR(unsigned char rl = 0);
-// These functions are deprecated. Use dirac_gammaL/R() instead.
-ex dirac_gamma6(unsigned char rl = 0);
-ex dirac_gamma7(unsigned char rl = 0);
-
/** Create a term of the form e_mu * gamma~mu with a unique index mu.
*
* @param dim Dimension of index
#include "idx.h"
#include "ncmul.h"
#include "symmetry.h"
+#include "operators.h"
#include "numeric.h"
#include "mul.h"
#include "power.h" // for sqrt()
GINAC_IMPLEMENT_REGISTERED_CLASS(su3d, tensor)
//////////
-// default ctor, dtor, copy ctor, assignment operator and helpers
+// default constructors
//////////
color::color() : representation_label(0)
tinfo_key = TINFO_color;
}
-void color::copy(const color & other)
-{
- inherited::copy(other);
- representation_label = other.representation_label;
-}
-
-DEFAULT_DESTROY(color)
-DEFAULT_CTORS(su3one)
-DEFAULT_CTORS(su3t)
-DEFAULT_CTORS(su3f)
-DEFAULT_CTORS(su3d)
+DEFAULT_CTOR(su3one)
+DEFAULT_CTOR(su3t)
+DEFAULT_CTOR(su3f)
+DEFAULT_CTOR(su3d)
//////////
// other constructors
// archiving
//////////
-color::color(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
+color::color(const archive_node &n, lst &sym_lst) : inherited(n, sym_lst)
{
unsigned rl;
n.find_unsigned("label", rl);
/** Perform automatic simplification on noncommutative product of color
* objects. This removes superfluous ONEs. */
-ex color::simplify_ncmul(const exvector & v) const
+ex color::eval_ncmul(const exvector & v) const
{
exvector s;
s.reserve(v.size());
// Remove superfluous ONEs
exvector::const_iterator it = v.begin(), itend = v.end();
while (it != itend) {
- if (!is_ex_of_type(it->op(0), su3one))
+ if (!is_a<su3one>(it->op(0)))
s.push_back(*it);
it++;
}
if (s.empty())
return color(su3one(), representation_label);
else
- return simplified_ncmul(s);
+ return hold_ncmul(s);
}
-ex color::thisexprseq(const exvector & v) const
+ex color::thiscontainer(const exvector & v) const
{
return color(representation_label, v);
}
-ex color::thisexprseq(exvector * vp) const
+ex color::thiscontainer(exvector * vp) const
{
return color(representation_label, vp);
}
GINAC_ASSERT(is_a<su3t>(self->op(0)));
unsigned char rl = ex_to<color>(*self).get_representation_label();
- if (is_ex_exactly_of_type(other->op(0), su3t)) {
+ if (is_exactly_a<su3t>(other->op(0))) {
// Contraction only makes sense if the represenation labels are equal
GINAC_ASSERT(is_a<color>(*other));
// T.a T.b T.a = -1/6 T.b
} else if (other - self == 2
- && is_ex_of_type(self[1], color)) {
+ && is_a<color>(self[1])) {
*self = numeric(-1, 6);
*other = _ex1;
return true;
} else {
exvector::iterator it = self + 1;
while (it != other) {
- if (!is_ex_of_type(*it, color)) {
+ if (!is_a<color>(*it)) {
return false;
}
it++;
GINAC_ASSERT(self->nops() == 4);
GINAC_ASSERT(is_a<su3d>(self->op(0)));
- if (is_ex_exactly_of_type(other->op(0), su3d)) {
+ if (is_exactly_a<su3d>(other->op(0))) {
// Find the dummy indices of the contraction
exvector self_indices = ex_to<indexed>(*self).get_indices();
return true;
}
- } else if (is_ex_exactly_of_type(other->op(0), su3t)) {
+ } else if (is_exactly_a<su3t>(other->op(0))) {
// d.abc T.b T.c = 5/6 T.a
if (other+1 != v.end()
- && is_ex_exactly_of_type(other[1].op(0), su3t)
+ && is_exactly_a<su3t>(other[1].op(0))
&& ex_to<indexed>(*self).has_dummy_index_for(other[1].op(1))) {
exvector self_indices = ex_to<indexed>(*self).get_indices();
GINAC_ASSERT(self->nops() == 4);
GINAC_ASSERT(is_a<su3f>(self->op(0)));
- if (is_ex_exactly_of_type(other->op(0), su3f)) { // f*d is handled by su3d class
+ if (is_exactly_a<su3f>(other->op(0))) { // f*d is handled by su3d class
// Find the dummy indices of the contraction
exvector dummy_indices;
return true;
}
- } else if (is_ex_exactly_of_type(other->op(0), su3t)) {
+ } else if (is_exactly_a<su3t>(other->op(0))) {
// f.abc T.b T.c = 3/2 I T.a
if (other+1 != v.end()
- && is_ex_exactly_of_type(other[1].op(0), su3t)
+ && is_exactly_a<su3t>(other[1].op(0))
&& ex_to<indexed>(*self).has_dummy_index_for(other[1].op(1))) {
exvector self_indices = ex_to<indexed>(*self).get_indices();
ex color_T(const ex & a, unsigned char rl)
{
- if (!is_ex_of_type(a, idx))
+ if (!is_a<idx>(a))
throw(std::invalid_argument("indices of color_T must be of type idx"));
if (!ex_to<idx>(a).get_dim().is_equal(8))
throw(std::invalid_argument("index dimension for color_T must be 8"));
ex color_f(const ex & a, const ex & b, const ex & c)
{
- if (!is_ex_of_type(a, idx) || !is_ex_of_type(b, idx) || !is_ex_of_type(c, idx))
+ if (!is_a<idx>(a) || !is_a<idx>(b) || !is_a<idx>(c))
throw(std::invalid_argument("indices of color_f must be of type idx"));
if (!ex_to<idx>(a).get_dim().is_equal(8) || !ex_to<idx>(b).get_dim().is_equal(8) || !ex_to<idx>(c).get_dim().is_equal(8))
throw(std::invalid_argument("index dimension for color_f must be 8"));
ex color_d(const ex & a, const ex & b, const ex & c)
{
- if (!is_ex_of_type(a, idx) || !is_ex_of_type(b, idx) || !is_ex_of_type(c, idx))
+ if (!is_a<idx>(a) || !is_a<idx>(b) || !is_a<idx>(c))
throw(std::invalid_argument("indices of color_d must be of type idx"));
if (!ex_to<idx>(a).get_dim().is_equal(8) || !ex_to<idx>(b).get_dim().is_equal(8) || !ex_to<idx>(c).get_dim().is_equal(8))
throw(std::invalid_argument("index dimension for color_d must be 8"));
ex color_trace(const ex & e, unsigned char rl)
{
- if (is_ex_of_type(e, color)) {
+ if (is_a<color>(e)) {
if (ex_to<color>(e).get_representation_label() == rl
- && is_ex_of_type(e.op(0), su3one))
+ && is_a<su3one>(e.op(0)))
return _ex3;
else
return _ex0;
- } else if (is_ex_exactly_of_type(e, mul)) {
+ } else if (is_exactly_a<mul>(e)) {
// Trace of product: pull out non-color factors
ex prod = _ex1;
- for (unsigned i=0; i<e.nops(); i++) {
+ for (size_t i=0; i<e.nops(); i++) {
const ex &o = e.op(i);
if (is_color_tinfo(o.return_type_tinfo(), rl))
prod *= color_trace(o, rl);
}
return prod;
- } else if (is_ex_exactly_of_type(e, ncmul)) {
+ } else if (is_exactly_a<ncmul>(e)) {
if (!is_color_tinfo(e.return_type_tinfo(), rl))
return _ex0;
// Expand product, if necessary
ex e_expanded = e.expand();
- if (!is_ex_of_type(e_expanded, ncmul))
+ if (!is_a<ncmul>(e_expanded))
return color_trace(e_expanded, rl);
- unsigned num = e.nops();
+ size_t num = e.nops();
if (num == 2) {
exvector v1;
v1.reserve(num - 2);
- for (unsigned i=0; i<num-2; i++)
+ for (size_t i=0; i<num-2; i++)
v1.push_back(e.op(i));
exvector v2 = v1;
// functions overriding virtual functions from base classes
protected:
+ ex eval_ncmul(const exvector & v) const;
bool match_same_type(const basic & other) const;
- ex simplify_ncmul(const exvector & v) const;
- ex thisexprseq(const exvector & v) const;
- ex thisexprseq(exvector * vp) const;
- unsigned return_type(void) const { return return_types::noncommutative; }
- unsigned return_type_tinfo(void) const { return TINFO_color + representation_label; }
+ ex thiscontainer(const exvector & v) const;
+ ex thiscontainer(exvector * vp) const;
+ unsigned return_type() const { return return_types::noncommutative; }
+ unsigned return_type_tinfo() const { return TINFO_color + representation_label; }
// non-virtual functions in this class
public:
- unsigned char get_representation_label(void) const {return representation_label;}
+ unsigned char get_representation_label() const {return representation_label;}
// member variables
private:
GINAC_IMPLEMENT_REGISTERED_CLASS(constant, basic)
//////////
-// default ctor, dtor, copy ctor, assignment operator and helpers
+// default constructor
//////////
// public
-constant::constant() : basic(TINFO_constant), ef(0), number(0), serial(next_serial++) {}
-
-// protected
-
-/** For use by copy ctor and assignment operator. */
-void constant::copy(const constant & other)
-{
- inherited::copy(other);
- name = other.name;
- TeX_name = other.TeX_name;
- serial = other.serial;
- ef = other.ef;
- if (other.number != 0)
- number = new numeric(*other.number);
- else
- number = 0;
-}
-
-void constant::destroy(bool call_parent)
+constant::constant() : basic(TINFO_constant), ef(0), serial(next_serial++)
{
- delete number;
- if (call_parent)
- inherited::destroy(call_parent);
+ setflag(status_flags::evaluated | status_flags::expanded);
}
//////////
-// other ctors
+// other constructors
//////////
// public
constant::constant(const std::string & initname, evalffunctype efun, const std::string & texname)
- : basic(TINFO_constant), name(initname), ef(efun), number(0), serial(next_serial++)
+ : basic(TINFO_constant), name(initname), ef(efun), serial(next_serial++)
{
if (texname.empty())
TeX_name = "\\mbox{" + name + "}";
}
constant::constant(const std::string & initname, const numeric & initnumber, const std::string & texname)
- : basic(TINFO_constant), name(initname), ef(0), number(new numeric(initnumber)), serial(next_serial++)
+ : basic(TINFO_constant), name(initname), ef(0), number(initnumber), serial(next_serial++)
{
if (texname.empty())
TeX_name = "\\mbox{" + name + "}";
// archiving
//////////
-constant::constant(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst) {}
+constant::constant(const archive_node &n, lst &sym_lst) : inherited(n, sym_lst) {}
-ex constant::unarchive(const archive_node &n, const lst &sym_lst)
+ex constant::unarchive(const archive_node &n, lst &sym_lst)
{
// Find constant by name (!! this is bad: 'twould be better if there
// was a list of all global constants that we could search)
{
if (ef!=0) {
return ef();
- } else if (number != 0) {
- return number->evalf();
+ } else {
+ return number.evalf();
}
return *this;
}
return serial == o.serial;
}
-unsigned constant::calchash(void) const
+unsigned constant::calchash() const
{
hashvalue = golden_ratio_hash(tinfo() ^ serial);
- // mask out numeric hashes:
- hashvalue &= 0x7FFFFFFFU;
-
+
setflag(status_flags::hash_calculated);
-
+
return hashvalue;
}
namespace GiNaC {
-typedef ex (*evalffunctype)(void);
+typedef ex (*evalffunctype)();
/** This class holds constants, symbols with specific numerical value. Each
* object of this class must either provide their own function to evaluate it
// member functions
- // other ctors
+ // other constructors
public:
constant(const std::string & initname, evalffunctype efun = 0, const std::string & texname = std::string());
constant(const std::string & initname, const numeric & initnumber, const std::string & texname = std::string());
protected:
ex derivative(const symbol & s) const;
bool is_equal_same_type(const basic & other) const;
- unsigned calchash(void) const;
+ unsigned calchash() const;
// new virtual functions which can be overridden by derived classes
// none
std::string name; ///< printname of this constant
std::string TeX_name; ///< LaTeX name
evalffunctype ef;
- numeric *number; ///< numerical value this constant evalf()s to
+ ex number; ///< numerical value this constant evalf()s to
unsigned serial; ///< unique serial number for comparison
static unsigned next_serial;
};
--- /dev/null
+/** @file container.h
+ *
+ * Wrapper template for making GiNaC classes out of STL containers. */
+
+/*
+ * GiNaC Copyright (C) 1999-2003 Johannes Gutenberg University Mainz, Germany
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __GINAC_CONTAINER_H__
+#define __GINAC_CONTAINER_H__
+
+#include <iterator>
+#include <stdexcept>
+#include <algorithm>
+#include <vector>
+#include <list>
+
+#include "ex.h"
+#include "print.h"
+#include "archive.h"
+#include "assertion.h"
+
+namespace GiNaC {
+
+
+/** Helper template for encapsulating the reserve() mechanics of STL containers. */
+template <template <class> class C>
+class container_storage {
+protected:
+ typedef C<ex> STLT;
+
+ container_storage() {}
+ container_storage(size_t n, const ex & e) : seq(n, e) {}
+
+ template <class In>
+ container_storage(In b, In e) : seq(b, e) {}
+
+ void reserve(size_t) {}
+ static void reserve(STLT &, size_t) {}
+
+ STLT seq;
+
+ // disallow destruction of container through a container_storage*
+protected:
+ ~container_storage() {}
+};
+
+template <>
+inline void container_storage<std::vector>::reserve(size_t n) { seq.reserve(n); }
+
+template <>
+inline void container_storage<std::vector>::reserve(std::vector<ex> & v, size_t n) { v.reserve(n); }
+
+
+/** Wrapper template for making GiNaC classes out of STL containers. */
+template <template <class> class C>
+class container : public basic, public container_storage<C> {
+ GINAC_DECLARE_REGISTERED_CLASS(container, basic)
+
+ typedef typename container_storage<C>::STLT STLT;
+
+public:
+ typedef typename STLT::const_iterator const_iterator;
+ typedef typename STLT::const_reverse_iterator const_reverse_iterator;
+
+protected:
+ // helpers
+ static unsigned get_tinfo() { return TINFO_fail; }
+ static char get_open_delim() { return '('; }
+ static char get_close_delim() { return ')'; }
+
+ // constructors
+public:
+ container(STLT const & s, bool discardable = false)
+ {
+ if (discardable)
+ seq.swap(const_cast<STLT &>(s));
+ else
+ seq = s;
+ }
+
+ explicit container(STLT * vp)
+ {
+ GINAC_ASSERT(vp);
+ seq.swap(*vp);
+ delete vp;
+ }
+
+ container(exvector::const_iterator b, exvector::const_iterator e)
+ : inherited(get_tinfo()), container_storage<C>(b, e) {}
+
+ explicit container(const ex & p1)
+ : inherited(get_tinfo()), container_storage<C>(1, p1) {}
+
+ container(const ex & p1, const ex & p2) : inherited(get_tinfo())
+ {
+ reserve(seq, 2);
+ seq.push_back(p1); seq.push_back(p2);
+ }
+
+ container(const ex & p1, const ex & p2, const ex & p3) : inherited(get_tinfo())
+ {
+ reserve(seq, 3);
+ seq.push_back(p1); seq.push_back(p2); seq.push_back(p3);
+ }
+
+ container(const ex & p1, const ex & p2, const ex & p3,
+ const ex & p4) : inherited(get_tinfo())
+ {
+ reserve(seq, 4);
+ seq.push_back(p1); seq.push_back(p2); seq.push_back(p3);
+ seq.push_back(p4);
+ }
+
+ container(const ex & p1, const ex & p2, const ex & p3,
+ const ex & p4, const ex & p5) : inherited(get_tinfo())
+ {
+ reserve(seq, 5);
+ seq.push_back(p1); seq.push_back(p2); seq.push_back(p3);
+ seq.push_back(p4); seq.push_back(p5);
+ }
+
+ container(const ex & p1, const ex & p2, const ex & p3,
+ const ex & p4, const ex & p5, const ex & p6) : inherited(get_tinfo())
+ {
+ reserve(seq, 6);
+ seq.push_back(p1); seq.push_back(p2); seq.push_back(p3);
+ seq.push_back(p4); seq.push_back(p5); seq.push_back(p6);
+ }
+
+ container(const ex & p1, const ex & p2, const ex & p3,
+ const ex & p4, const ex & p5, const ex & p6,
+ const ex & p7) : inherited(get_tinfo())
+ {
+ reserve(seq, 7);
+ seq.push_back(p1); seq.push_back(p2); seq.push_back(p3);
+ seq.push_back(p4); seq.push_back(p5); seq.push_back(p6);
+ seq.push_back(p7);
+ }
+
+ container(const ex & p1, const ex & p2, const ex & p3,
+ const ex & p4, const ex & p5, const ex & p6,
+ const ex & p7, const ex & p8) : inherited(get_tinfo())
+ {
+ reserve(seq, 8);
+ seq.push_back(p1); seq.push_back(p2); seq.push_back(p3);
+ seq.push_back(p4); seq.push_back(p5); seq.push_back(p6);
+ seq.push_back(p7); seq.push_back(p8);
+ }
+
+ container(const ex & p1, const ex & p2, const ex & p3,
+ const ex & p4, const ex & p5, const ex & p6,
+ const ex & p7, const ex & p8, const ex & p9) : inherited(get_tinfo())
+ {
+ reserve(seq, 9);
+ seq.push_back(p1); seq.push_back(p2); seq.push_back(p3);
+ seq.push_back(p4); seq.push_back(p5); seq.push_back(p6);
+ seq.push_back(p7); seq.push_back(p8); seq.push_back(p9);
+ }
+
+ container(const ex & p1, const ex & p2, const ex & p3,
+ const ex & p4, const ex & p5, const ex & p6,
+ const ex & p7, const ex & p8, const ex & p9,
+ const ex & p10) : inherited(get_tinfo())
+ {
+ reserve(seq, 10);
+ seq.push_back(p1); seq.push_back(p2); seq.push_back(p3);
+ seq.push_back(p4); seq.push_back(p5); seq.push_back(p6);
+ seq.push_back(p7); seq.push_back(p8); seq.push_back(p9);
+ seq.push_back(p10);
+ }
+
+ container(const ex & p1, const ex & p2, const ex & p3,
+ const ex & p4, const ex & p5, const ex & p6,
+ const ex & p7, const ex & p8, const ex & p9,
+ const ex & p10, const ex & p11) : inherited(get_tinfo())
+ {
+ reserve(seq, 11);
+ seq.push_back(p1); seq.push_back(p2); seq.push_back(p3);
+ seq.push_back(p4); seq.push_back(p5); seq.push_back(p6);
+ seq.push_back(p7); seq.push_back(p8); seq.push_back(p9);
+ seq.push_back(p10); seq.push_back(p11);
+ }
+
+ container(const ex & p1, const ex & p2, const ex & p3,
+ const ex & p4, const ex & p5, const ex & p6,
+ const ex & p7, const ex & p8, const ex & p9,
+ const ex & p10, const ex & p11, const ex & p12) : inherited(get_tinfo())
+ {
+ reserve(seq, 12);
+ seq.push_back(p1); seq.push_back(p2); seq.push_back(p3);
+ seq.push_back(p4); seq.push_back(p5); seq.push_back(p6);
+ seq.push_back(p7); seq.push_back(p8); seq.push_back(p9);
+ seq.push_back(p10); seq.push_back(p11); seq.push_back(p12);
+ }
+
+ container(const ex & p1, const ex & p2, const ex & p3,
+ const ex & p4, const ex & p5, const ex & p6,
+ const ex & p7, const ex & p8, const ex & p9,
+ const ex & p10, const ex & p11, const ex & p12,
+ const ex & p13) : inherited(get_tinfo())
+ {
+ reserve(seq, 13);
+ seq.push_back(p1); seq.push_back(p2); seq.push_back(p3);
+ seq.push_back(p4); seq.push_back(p5); seq.push_back(p6);
+ seq.push_back(p7); seq.push_back(p8); seq.push_back(p9);
+ seq.push_back(p10); seq.push_back(p11); seq.push_back(p12);
+ seq.push_back(p13);
+ }
+
+ container(const ex & p1, const ex & p2, const ex & p3,
+ const ex & p4, const ex & p5, const ex & p6,
+ const ex & p7, const ex & p8, const ex & p9,
+ const ex & p10, const ex & p11, const ex & p12,
+ const ex & p13, const ex & p14) : inherited(get_tinfo())
+ {
+ reserve(seq, 14);
+ seq.push_back(p1); seq.push_back(p2); seq.push_back(p3);
+ seq.push_back(p4); seq.push_back(p5); seq.push_back(p6);
+ seq.push_back(p7); seq.push_back(p8); seq.push_back(p9);
+ seq.push_back(p10); seq.push_back(p11); seq.push_back(p12);
+ seq.push_back(p13); seq.push_back(p14);
+ }
+
+ container(const ex & p1, const ex & p2, const ex & p3,
+ const ex & p4, const ex & p5, const ex & p6,
+ const ex & p7, const ex & p8, const ex & p9,
+ const ex & p10, const ex & p11, const ex & p12,
+ const ex & p13, const ex & p14, const ex & p15) : inherited(get_tinfo())
+ {
+ reserve(seq, 15);
+ seq.push_back(p1); seq.push_back(p2); seq.push_back(p3);
+ seq.push_back(p4); seq.push_back(p5); seq.push_back(p6);
+ seq.push_back(p7); seq.push_back(p8); seq.push_back(p9);
+ seq.push_back(p10); seq.push_back(p11); seq.push_back(p12);
+ seq.push_back(p13); seq.push_back(p14); seq.push_back(p15);
+ }
+
+ container(const ex & p1, const ex & p2, const ex & p3,
+ const ex & p4, const ex & p5, const ex & p6,
+ const ex & p7, const ex & p8, const ex & p9,
+ const ex & p10, const ex & p11, const ex & p12,
+ const ex & p13, const ex & p14, const ex & p15,
+ const ex & p16) : inherited(get_tinfo())
+ {
+ reserve(seq, 16);
+ seq.push_back(p1); seq.push_back(p2); seq.push_back(p3);
+ seq.push_back(p4); seq.push_back(p5); seq.push_back(p6);
+ seq.push_back(p7); seq.push_back(p8); seq.push_back(p9);
+ seq.push_back(p10); seq.push_back(p11); seq.push_back(p12);
+ seq.push_back(p13); seq.push_back(p14); seq.push_back(p15);
+ seq.push_back(p16);
+ }
+
+ // functions overriding virtual functions from base classes
+public:
+ void print(const print_context & c, unsigned level = 0) const;
+ bool info(unsigned inf) const { return inherited::info(inf); }
+ unsigned precedence() const { return 10; }
+ size_t nops() const { return seq.size(); }
+ ex op(size_t i) const;
+ ex & let_op(size_t i);
+ ex eval(int level = 0) const;
+ ex subs(const lst & ls, const lst & lr, unsigned options = 0) const;
+
+protected:
+ bool is_equal_same_type(const basic & other) const;
+
+ // new virtual functions which can be overridden by derived classes
+protected:
+ /** Similar to duplicate(), but with a preset sequence. Must be
+ * overridden by derived classes. */
+ virtual ex thiscontainer(const STLT & v) const { return container(v); }
+
+ /** Similar to duplicate(), but with a preset sequence (which gets
+ * deleted). Must be overridden by derived classes. */
+ virtual ex thiscontainer(STLT * vp) const { return container(vp); }
+
+ virtual void printseq(const print_context & c, char openbracket, char delim,
+ char closebracket, unsigned this_precedence,
+ unsigned upper_precedence = 0) const;
+
+ // non-virtual functions in this class
+private:
+ void sort_(std::random_access_iterator_tag)
+ {
+ std::sort(seq.begin(), seq.end(), ex_is_less());
+ }
+
+ void sort_(std::input_iterator_tag)
+ {
+ seq.sort(ex_is_less());
+ }
+
+ void unique_()
+ {
+ typename STLT::iterator p = std::unique(seq.begin(), seq.end(), ex_is_equal());
+ seq.erase(p, seq.end());
+ }
+
+public:
+ container & prepend(const ex & b);
+ container & append(const ex & b);
+ container & remove_first();
+ container & remove_last();
+ container & remove_all();
+ container & sort();
+ container & unique();
+
+ const_iterator begin() const {return seq.begin();}
+ const_iterator end() const {return seq.end();}
+ const_reverse_iterator rbegin() const {return seq.rbegin();}
+ const_reverse_iterator rend() const {return seq.rend();}
+
+protected:
+ STLT evalchildren(int level) const;
+ STLT *subschildren(const lst & ls, const lst & lr, unsigned options = 0) const;
+};
+
+/** Default constructor */
+template <template <class> class C>
+container<C>::container() : inherited(get_tinfo()) {}
+
+/** Construct object from archive_node. */
+template <template <class> class C>
+container<C>::container(const archive_node &n, lst &sym_lst) : inherited(n, sym_lst)
+{
+ for (unsigned int i=0; true; i++) {
+ ex e;
+ if (n.find_ex("seq", e, sym_lst, i))
+ seq.push_back(e);
+ else
+ break;
+ }
+}
+
+/** Unarchive the object. */
+template <template <class> class C>
+ex container<C>::unarchive(const archive_node &n, lst &sym_lst)
+{
+ return (new container(n, sym_lst))->setflag(status_flags::dynallocated);
+}
+
+/** Archive the object. */
+template <template <class> class C>
+void container<C>::archive(archive_node &n) const
+{
+ inherited::archive(n);
+ const_iterator i = seq.begin(), end = seq.end();
+ while (i != end) {
+ n.add_ex("seq", *i);
+ ++i;
+ }
+}
+
+template <template <class> class C>
+void container<C>::print(const print_context & c, unsigned level) const
+{
+ if (is_a<print_tree>(c)) {
+ c.s << std::string(level, ' ') << class_name()
+ << std::hex << ", hash=0x" << hashvalue << ", flags=0x" << flags << std::dec
+ << ", nops=" << nops()
+ << std::endl;
+ unsigned delta_indent = static_cast<const print_tree &>(c).delta_indent;
+ const_iterator i = seq.begin(), end = seq.end();
+ while (i != end) {
+ i->print(c, level + delta_indent);
+ ++i;
+ }
+ c.s << std::string(level + delta_indent,' ') << "=====" << std::endl;
+ } else if (is_a<print_python>(c)) {
+ printseq(c, '[', ',', ']', precedence(), precedence()+1);
+ } else if (is_a<print_python_repr>(c)) {
+ c.s << class_name ();
+ printseq(c, '(', ',', ')', precedence(), precedence()+1);
+ } else {
+ // always print brackets around seq, ignore upper_precedence
+ printseq(c, get_open_delim(), ',', get_close_delim(), precedence(), precedence()+1);
+ }
+}
+
+template <template <class> class C>
+ex container<C>::op(size_t i) const
+{
+ GINAC_ASSERT(i < nops());
+
+ const_iterator it = seq.begin();
+ advance(it, i);
+ return *it;
+}
+
+template <template <class> class C>
+ex & container<C>::let_op(size_t i)
+{
+ GINAC_ASSERT(i < nops());
+
+ ensure_if_modifiable();
+ typename STLT::iterator it = seq.begin();
+ advance(it, i);
+ return *it;
+}
+
+template <template <class> class C>
+ex container<C>::eval(int level) const
+{
+ if (level == 1)
+ return hold();
+ else
+ return thiscontainer(evalchildren(level));
+}
+
+template <template <class> class C>
+ex container<C>::subs(const lst & ls, const lst & lr, unsigned options) const
+{
+ STLT *vp = subschildren(ls, lr, options);
+ if (vp)
+ return ex_to<basic>(thiscontainer(vp)).subs_one_level(ls, lr, options);
+ else
+ return subs_one_level(ls, lr, options);
+}
+
+/** Compare two containers of the same type. */
+template <template <class> class C>
+int container<C>::compare_same_type(const basic & other) const
+{
+ GINAC_ASSERT(is_a<container>(other));
+ const container & o = static_cast<const container &>(other);
+
+ const_iterator it1 = seq.begin(), it1end = seq.end(),
+ it2 = o.seq.begin(), it2end = o.seq.end();
+
+ while (it1 != it1end && it2 != it2end) {
+ int cmpval = it1->compare(*it2);
+ if (cmpval)
+ return cmpval;
+ ++it1; ++it2;
+ }
+
+ return (it1 == it1end) ? (it2 == it2end ? 0 : -1) : 1;
+}
+
+template <template <class> class C>
+bool container<C>::is_equal_same_type(const basic & other) const
+{
+ GINAC_ASSERT(is_a<container>(other));
+ const container & o = static_cast<const container &>(other);
+
+ if (seq.size() != o.seq.size())
+ return false;
+
+ const_iterator it1 = seq.begin(), it1end = seq.end(), it2 = o.seq.begin();
+ while (it1 != it1end) {
+ if (!it1->is_equal(*it2))
+ return false;
+ ++it1; ++it2;
+ }
+
+ return true;
+}
+
+/** Add element at front. */
+template <template <class> class C>
+container<C> & container<C>::prepend(const ex & b)
+{
+ ensure_if_modifiable();
+ seq.push_front(b);
+ return *this;
+}
+
+/** Add element at back. */
+template <template <class> class C>
+container<C> & container<C>::append(const ex & b)
+{
+ ensure_if_modifiable();
+ seq.push_back(b);
+ return *this;
+}
+
+/** Remove first element. */
+template <template <class> class C>
+container<C> & container<C>::remove_first()
+{
+ ensure_if_modifiable();
+ seq.pop_front();
+ return *this;
+}
+
+/** Remove last element. */
+template <template <class> class C>
+container<C> & container<C>::remove_last()
+{
+ ensure_if_modifiable();
+ seq.pop_back();
+ return *this;
+}
+
+/** Remove all elements. */
+template <template <class> class C>
+container<C> & container<C>::remove_all()
+{
+ ensure_if_modifiable();
+ seq.clear();
+ return *this;
+}
+
+/** Sort elements. */
+template <template <class> class C>
+container<C> & container<C>::sort()
+{
+ ensure_if_modifiable();
+ sort_(std::iterator_traits<typename STLT::iterator>::iterator_category());
+ return *this;
+}
+
+/** Specialization of container::unique_() for std::list. */
+inline void container<std::list>::unique_()
+{
+ seq.unique(ex_is_equal());
+}
+
+/** Remove adjacent duplicate elements. */
+template <template <class> class C>
+container<C> & container<C>::unique()
+{
+ ensure_if_modifiable();
+ unique_();
+ return *this;
+}
+
+/** Print sequence of contained elements. */
+template <template <class> class C>
+void container<C>::printseq(const print_context & c, char openbracket, char delim,
+ char closebracket, unsigned this_precedence,
+ unsigned upper_precedence) const
+{
+ if (this_precedence <= upper_precedence)
+ c.s << openbracket;
+
+ if (!seq.empty()) {
+ const_iterator it = seq.begin(), itend = seq.end();
+ --itend;
+ while (it != itend) {
+ it->print(c, this_precedence);
+ c.s << delim;
+ ++it;
+ }
+ it->print(c, this_precedence);
+ }
+
+ if (this_precedence <= upper_precedence)
+ c.s << closebracket;
+}
+
+template <template <class> class C>
+typename container<C>::STLT container<C>::evalchildren(int level) const
+{
+ if (level == 1)
+ return seq;
+ else if (level == -max_recursion_level)
+ throw std::runtime_error("max recursion level reached");
+
+ STLT s;
+ reserve(s, seq.size());
+
+ --level;
+ const_iterator it = seq.begin(), itend = seq.end();
+ while (it != itend) {
+ s.push_back(it->eval(level));
+ ++it;
+ }
+
+ return s;
+}
+
+template <template <class> class C>
+typename container<C>::STLT *container<C>::subschildren(const lst & ls, const lst & lr, unsigned options) const
+{
+ // returns a NULL pointer if nothing had to be substituted
+ // returns a pointer to a newly created epvector otherwise
+ // (which has to be deleted somewhere else)
+
+ const_iterator cit = seq.begin(), end = seq.end();
+ while (cit != end) {
+ const ex & subsed_ex = cit->subs(ls, lr, options);
+ if (!are_ex_trivially_equal(*cit, subsed_ex)) {
+
+ // copy first part of seq which hasn't changed
+ STLT *s = new STLT(seq.begin(), cit);
+ reserve(*s, seq.size());
+
+ // insert changed element
+ s->push_back(subsed_ex);
+ ++cit;
+
+ // copy rest
+ while (cit != end) {
+ s->push_back(cit->subs(ls, lr, options));
+ ++cit;
+ }
+
+ return s;
+ }
+
+ ++cit;
+ }
+
+ return 0; // nothing has changed
+}
+
+} // namespace GiNaC
+
+#endif // ndef __GINAC_CONTAINER_H__
+++ /dev/null
-if (($#ARGV!=0) and ($#ARGV!=1)) {
- die 'usage: container.pl type [maxargs] (type=lst or exprseq)';
-}
-
-if ($ARGV[0] eq 'lst') {
- $type='lst';
-} elsif ($ARGV[0] eq 'exprseq') {
- $type='exprseq';
-} else {
- die 'only lst and exprseq supported';
-}
-
-if ($#ARGV==1) {
- $maxargs=$ARGV[1];
-} else {
- $maxargs=16; # must be greater or equal than the value used in function.pl
-}
-
-if ($type eq 'exprseq') {
-
- # settings for exprseq
- $CONTAINER="exprseq";
- $STLHEADER="vector";
- $reserve=1;
- $prepend=0;
- $sort=0;
- $let_op=0;
- $open_bracket='(';
- $close_bracket=')';
-
-} elsif ($type eq 'lst') {
-
- # settings for lst
- $CONTAINER="lst";
- $STLHEADER="list";
- $reserve=0;
- $prepend=1;
- $sort=1;
- $let_op=1;
- $open_bracket='{';
- $close_bracket='}';
-
-} else {
- die "invalid type $type";
-}
-
-$CONTAINER_UC=uc(${CONTAINER});
-$STLT="ex".$STLHEADER;
-
-if ($reserve) {
- $RESERVE_IMPLEMENTATION="#define RESERVE(s,size) (s).reserve(size)";
-} else {
- $RESERVE_IMPLEMENTATION="#define RESERVE(s,size) // no reserve needed for ${STLHEADER}";
-}
-
-if ($prepend) {
- $PREPEND_INTERFACE=<<END_OF_PREPEND_INTERFACE;
- virtual ${CONTAINER} & prepend(const ex & b);
- virtual ${CONTAINER} & remove_first(void);
-END_OF_PREPEND_INTERFACE
-
- $PREPEND_IMPLEMENTATION=<<END_OF_PREPEND_IMPLEMENTATION;
-${CONTAINER} & ${CONTAINER}::prepend(const ex & b)
-{
- ensure_if_modifiable();
- seq.push_front(b);
- return *this;
-}
-
-${CONTAINER} & ${CONTAINER}::remove_first(void)
-{
- ensure_if_modifiable();
- seq.pop_front();
- return *this;
-}
-END_OF_PREPEND_IMPLEMENTATION
-} else {
- $PREPEND_INTERFACE=" // no prepend possible for ${CONTAINER}";
- $PREPEND_IMPLEMENTATION="";
-}
-
-if ($sort) {
- $SORT_INTERFACE=<<END_OF_SORT_INTERFACE;
- virtual ${CONTAINER} & sort(void);
- virtual ${CONTAINER} & unique(void);
-END_OF_SORT_INTERFACE
-
- $SORT_IMPLEMENTATION=<<END_OF_SORT_IMPLEMENTATION;
-${CONTAINER} & ${CONTAINER}::sort(void)
-{
- ensure_if_modifiable();
- seq.sort(ex_is_less());
- return *this;
-}
-
-${CONTAINER} & ${CONTAINER}::unique(void)
-{
- ensure_if_modifiable();
- seq.unique(ex_is_equal());
- return *this;
-}
-END_OF_SORT_IMPLEMENTATION
-} else {
- $SORT_INTERFACE=" // no sort possible for ${CONTAINER}";
- $SORT_IMPLEMENTATION="";
-}
-
-if ($let_op) {
- $LET_OP_IMPLEMENTATION=<<END_OF_LET_OP_IMPLEMENTATION
-ex & ${CONTAINER}::let_op(int i)
-{
- GINAC_ASSERT(i>=0);
- GINAC_ASSERT(i<nops());
-
- ${STLT}::iterator it=seq.begin();
- for (int j=0; j<i; j++) {
- ++it;
- }
- return *it;
-}
-END_OF_LET_OP_IMPLEMENTATION
-} else {
- $LET_OP_IMPLEMENTATION="// ${CONTAINER}::let_op() will be implemented by user elsewhere";
-}
-
-sub generate_seq {
- my ($seq_template,$n,$separator)=@_;
- my ($res,$N);
-
- $res='';
- for ($N=1; $N<=$n; $N++) {
- $res .= eval('"' . $seq_template . '"');
- if ($N!=$n) {
- $res .= $separator;
- }
- }
- return $res;
-}
-
-sub generate_from_to {
- my ($template,$seq_template1,$seq_separator1,$seq_template2,
- $seq_separator2,$from,$to)=@_;
- my ($res,$N,$SEQ);
-
- $res='';
- for ($N=$from; $N<=$to; $N++) {
- $SEQ1=generate_seq($seq_template1,$N,$seq_separator1);
- $SEQ2=generate_seq($seq_template2,$N,$seq_separator2);
- $res .= eval('"' . $template . '"');
- $SEQ1=''; # to avoid main::SEQ1 used only once warning
- $SEQ2=''; # same as above
- }
- return $res;
-}
-
-sub generate {
- my ($template,$seq_template1,$seq_separator1,$seq_template2,
- $seq_separator2)=@_;
- return generate_from_to($template,$seq_template1,$seq_separator1,
- $seq_template2,$seq_separator2,1,$maxargs);
-}
-
-$constructors_interface=generate(
-' explicit ${CONTAINER}(${SEQ1});'."\n",
-'const ex & param${N}',', ','','');
-
-$constructors_implementation=generate(
- <<'END_OF_CONSTRUCTORS_IMPLEMENTATION','const ex & param${N}',', ',' seq.push_back(param${N});',"\n");
-${CONTAINER}::${CONTAINER}(${SEQ1}) : basic(TINFO_${CONTAINER})
-{
- RESERVE(seq,${N});
-${SEQ2}
-}
-END_OF_CONSTRUCTORS_IMPLEMENTATION
-
-$interface=<<END_OF_INTERFACE;
-/** \@file ${CONTAINER}.h
- *
- * Definition of GiNaC's ${CONTAINER}. */
-
-/*
- * This file was generated automatically by container.pl.
- * Please do not modify it directly, edit the perl script instead!
- * container.pl options: \$CONTAINER=${CONTAINER}
- * \$STLHEADER=${STLHEADER}
- * \$reserve=${reserve}
- * \$prepend=${prepend}
- * \$sort=${sort}
- * \$let_op=${let_op}
- * \$open_bracket=${open_bracket}
- * \$close_bracket=${close_bracket}
- * \$maxargs=${maxargs}
- *
- * GiNaC Copyright (C) 1999-2003 Johannes Gutenberg University Mainz, Germany
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef __GINAC_${CONTAINER_UC}_H__
-#define __GINAC_${CONTAINER_UC}_H__
-
-#include <${STLHEADER}>
-
-// CINT needs <algorithm> to work properly with <vector> and <list>
-#include <algorithm>
-
-#include "basic.h"
-#include "ex.h"
-
-namespace GiNaC {
-
-
-typedef std::${STLHEADER}<ex> ${STLT};
-
-class ${CONTAINER} : public basic
-{
- GINAC_DECLARE_REGISTERED_CLASS(${CONTAINER}, basic)
-
-public:
- ${CONTAINER}(${STLT} const & s, bool discardable = false);
- ${CONTAINER}(${STLT} * vp); // vp will be deleted
-${constructors_interface}
-
-public:
- void print(const print_context & c, unsigned level = 0) const;
- unsigned precedence(void) const {return 10;}
- bool info(unsigned inf) const;
- unsigned nops() const;
- ex & let_op(int i);
- ex map(map_function & f) const;
- ex eval(int level=0) const;
- ex subs(const lst & ls, const lst & lr, bool no_pattern = false) const;
-protected:
- bool is_equal_same_type(const basic & other) const;
-
- // new virtual functions which can be overridden by derived classes
-public:
- virtual ${CONTAINER} & append(const ex & b);
- virtual ${CONTAINER} & remove_last(void);
-${PREPEND_INTERFACE}
-${SORT_INTERFACE}
-protected:
- virtual void printseq(const print_context & c, char openbracket, char delim,
- char closebracket, unsigned this_precedence,
- unsigned upper_precedence = 0) const;
- virtual ex this${CONTAINER}(${STLT} const & v) const;
- virtual ex this${CONTAINER}(${STLT} * vp) const;
-
-protected:
- bool is_canonical() const;
- ${STLT} evalchildren(int level) const;
- ${STLT} * subschildren(const lst & ls, const lst & lr, bool no_pattern = false) const;
-
-protected:
- ${STLT} seq;
-};
-
-// utility functions
-
-/** Specialization of is_exactly_a<${CONTAINER}>(obj) for ${CONTAINER} objects. */
-template<> inline bool is_exactly_a<${CONTAINER}>(const basic & obj)
-{
- return obj.tinfo()==TINFO_${CONTAINER};
-}
-
-} // namespace GiNaC
-
-#endif // ndef __GINAC_${CONTAINER_UC}_H__
-
-END_OF_INTERFACE
-
-$implementation=<<END_OF_IMPLEMENTATION;
-/** \@file ${CONTAINER}.cpp
- *
- * Implementation of GiNaC's ${CONTAINER}. */
-
-/*
- * This file was generated automatically by container.pl.
- * Please do not modify it directly, edit the perl script instead!
- * container.pl options: \$CONTAINER=${CONTAINER}
- * \$STLHEADER=${STLHEADER}
- * \$reserve=${reserve}
- * \$prepend=${prepend}
- * \$let_op=${let_op}
- * \$open_bracket=${open_bracket}
- * \$close_bracket=${close_bracket}
- * \$maxargs=${maxargs}
- *
- * GiNaC Copyright (C) 1999-2003 Johannes Gutenberg University Mainz, Germany
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <iostream>
-#include <stdexcept>
-
-#include "${CONTAINER}.h"
-#include "ex.h"
-#include "print.h"
-#include "archive.h"
-
-namespace GiNaC {
-
-GINAC_IMPLEMENT_REGISTERED_CLASS(${CONTAINER}, basic)
-
-${RESERVE_IMPLEMENTATION}
-
-//////////
-// default ctor, dtor, copy ctor, assignment operator and helpers
-//////////
-
-// public
-
-${CONTAINER}::${CONTAINER}() : basic(TINFO_${CONTAINER}) {}
-
-// protected
-
-void ${CONTAINER}::copy(${CONTAINER} const & other)
-{
- inherited::copy(other);
- seq=other.seq;
-}
-
-void ${CONTAINER}::destroy(bool call_parent)
-{
- seq.clear();
- if (call_parent) inherited::destroy(call_parent);
-}
-
-//////////
-// other ctors
-//////////
-
-// public
-
-${CONTAINER}::${CONTAINER}(${STLT} const & s, bool discardable) : basic(TINFO_${CONTAINER})
-{
- if (discardable) {
- seq.swap(const_cast<${STLT} &>(s));
- } else {
- seq=s;
- }
-}
-
-${CONTAINER}::${CONTAINER}(${STLT} * vp) : basic(TINFO_${CONTAINER})
-{
- GINAC_ASSERT(vp!=0);
- seq.swap(*vp);
- delete vp;
-}
-
-${constructors_implementation}
-
-//////////
-// archiving
-//////////
-
-/** Construct object from archive_node. */
-${CONTAINER}::${CONTAINER}(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
-{
- for (unsigned int i=0; true; i++) {
- ex e;
- if (n.find_ex("seq", e, sym_lst, i))
- seq.push_back(e);
- else
- break;
- }
-}
-
-/** Unarchive the object. */
-ex ${CONTAINER}::unarchive(const archive_node &n, const lst &sym_lst)
-{
- return (new ${CONTAINER}(n, sym_lst))->setflag(status_flags::dynallocated);
-}
-
-/** Archive the object. */
-void ${CONTAINER}::archive(archive_node &n) const
-{
- inherited::archive(n);
- ${STLT}::const_iterator i = seq.begin(), end = seq.end();
- while (i != end) {
- n.add_ex("seq", *i);
- ++i;
- }
-}
-
-//////////
-// functions overriding virtual functions from base classes
-//////////
-
-// public
-
-void ${CONTAINER}::print(const print_context & c, unsigned level) const
-{
- if (is_a<print_tree>(c)) {
-
- c.s << std::string(level, ' ') << class_name()
- << std::hex << ", hash=0x" << hashvalue << ", flags=0x" << flags << std::dec
- << ", nops=" << nops()
- << std::endl;
- unsigned delta_indent = static_cast<const print_tree &>(c).delta_indent;
- ${STLT}::const_iterator i = seq.begin(), end = seq.end();
- while (i != end) {
- i->print(c, level + delta_indent);
- ++i;
- }
- c.s << std::string(level + delta_indent,' ') << "=====" << std::endl;
- } else if (is_a<print_python>(c)) {
- printseq(c, '[', ',', ']', precedence(), precedence()+1);
- } else if (is_a<print_python_repr>(c)) {
- c.s << class_name ();
- printseq(c, '(', ',', ')', precedence(), precedence()+1);
- } else {
- // always print brackets around seq, ignore upper_precedence
- printseq(c, '${open_bracket}', ',', '${close_bracket}', precedence(), precedence()+1);
- }
-}
-
-// ${CONTAINER}::info() will be implemented by user elsewhere";
-
-unsigned ${CONTAINER}::nops() const
-{
- return seq.size();
-}
-
-${LET_OP_IMPLEMENTATION}
-
-ex ${CONTAINER}::map(map_function & f) const
-{
- // This implementation is here because basic::map() uses let_op()
- // which is not defined for all containers
- ${STLT} s;
- RESERVE(s,seq.size());
- ${STLT}::const_iterator i = seq.begin(), end = seq.end();
- while (i != end) {
- s.push_back(f(*i));
- ++i;
- }
-
- return this${CONTAINER}(s);
-}
-
-ex ${CONTAINER}::eval(int level) const
-{
- if (level==1) {
- return this->hold();
- }
- return this${CONTAINER}(evalchildren(level));
-}
-
-ex ${CONTAINER}::subs(const lst & ls, const lst & lr, bool no_pattern) const
-{
- ${STLT} *vp = subschildren(ls, lr, no_pattern);
- if (vp)
- return ex_to<basic>(this${CONTAINER}(vp)).basic::subs(ls, lr, no_pattern);
- else
- return basic::subs(ls, lr, no_pattern);
-}
-
-// protected
-
-int ${CONTAINER}::compare_same_type(const basic & other) const
-{
- GINAC_ASSERT(is_a<${CONTAINER}>(other));
- ${CONTAINER} const & o = static_cast<const ${CONTAINER} &>(other);
-
- ${STLT}::const_iterator it1 = seq.begin(), it1end = seq.end(),
- it2 = o.seq.begin(), it2end = o.seq.end();
-
- while (it1 != it1end && it2 != it2end) {
- int cmpval = it1->compare(*it2);
- if (cmpval)
- return cmpval;
- ++it1; ++it2;
- }
-
- return (it1 == it1end) ? (it2 == it2end ? 0 : -1) : 1;
-}
-
-bool ${CONTAINER}::is_equal_same_type(const basic & other) const
-{
- GINAC_ASSERT(is_a<${CONTAINER}>(other));
- ${CONTAINER} const &o = static_cast<const ${CONTAINER} &>(other);
-
- if (seq.size() != o.seq.size())
- return false;
-
- ${STLT}::const_iterator it1 = seq.begin(), it1end = seq.end(),
- it2 = o.seq.begin();
-
- while (it1 != it1end) {
- if (!it1->is_equal(*it2))
- return false;
- ++it1; ++it2;
- }
-
- return true;
-}
-
-//////////
-// new virtual functions which can be overridden by derived classes
-//////////
-
-// public
-
-${CONTAINER} & ${CONTAINER}::append(const ex & b)
-{
- ensure_if_modifiable();
- seq.push_back(b);
- return *this;
-}
-
-${CONTAINER} & ${CONTAINER}::remove_last(void)
-{
- ensure_if_modifiable();
- seq.pop_back();
- return *this;
-}
-
-${PREPEND_IMPLEMENTATION}
-
-${SORT_IMPLEMENTATION}
-
-// protected
-
-void ${CONTAINER}::printseq(const print_context & c, char openbracket, char delim,
- char closebracket, unsigned this_precedence,
- unsigned upper_precedence) const
-{
- if (this_precedence <= upper_precedence)
- c.s << openbracket;
-
- if (!seq.empty()) {
- ${STLT}::const_iterator it = seq.begin(), itend = seq.end();
- --itend;
- while (it != itend) {
- it->print(c, this_precedence);
- c.s << delim;
- ++it;
- }
- it->print(c, this_precedence);
- }
-
- if (this_precedence <= upper_precedence)
- c.s << closebracket;
-}
-
-ex ${CONTAINER}::this${CONTAINER}(${STLT} const & v) const
-{
- return ${CONTAINER}(v);
-}
-
-ex ${CONTAINER}::this${CONTAINER}(${STLT} * vp) const
-{
- return ${CONTAINER}(vp);
-}
-
-//////////
-// non-virtual functions in this class
-//////////
-
-// public
-
-// none
-
-// protected
-
-bool ${CONTAINER}::is_canonical() const
-{
- if (seq.size()<=1) { return 1; }
-
- ${STLT}::const_iterator it = seq.begin(), itend = seq.end();
- ${STLT}::const_iterator it_last=it;
- for (++it; it!=itend; it_last=it, ++it) {
- if (it_last->compare(*it)>0) {
- if (it_last->compare(*it)>0) {
- std::cout << *it_last << ">" << *it << "\\n";
- return 0;
- }
- }
- }
- return 1;
-}
-
-
-${STLT} ${CONTAINER}::evalchildren(int level) const
-{
- ${STLT} s;
- RESERVE(s,seq.size());
-
- if (level==1) {
- return seq;
- }
- if (level == -max_recursion_level) {
- throw(std::runtime_error("max recursion level reached"));
- }
- --level;
- ${STLT}::const_iterator it = seq.begin(), itend = seq.end();
- while (it != itend) {
- s.push_back(it->eval(level));
- ++it;
- }
- return s;
-}
-
-${STLT} * ${CONTAINER}::subschildren(const lst & ls, const lst & lr, bool no_pattern) const
-{
- // returns a NULL pointer if nothing had to be substituted
- // returns a pointer to a newly created epvector otherwise
- // (which has to be deleted somewhere else)
-
- ${STLT}::const_iterator cit = seq.begin(), end = seq.end();
- while (cit != end) {
- const ex & subsed_ex = cit->subs(ls, lr, no_pattern);
- if (!are_ex_trivially_equal(*cit, subsed_ex)) {
-
- // something changed, copy seq, subs and return it
- ${STLT} *s=new ${STLT};
- RESERVE(*s, seq.size());
-
- // copy parts of seq which are known not to have changed
- ${STLT}::const_iterator cit2 = seq.begin();
- while (cit2 != cit) {
- s->push_back(*cit2);
- ++cit2;
- }
-
- // copy first changed element
- s->push_back(subsed_ex);
- ++cit2;
-
- // copy rest
- while (cit2 != end) {
- s->push_back(cit2->subs(ls, lr, no_pattern));
- ++cit2;
- }
- return s;
- }
- ++cit;
- }
-
- return 0; // nothing has changed
-}
-
-} // namespace GiNaC
-
-END_OF_IMPLEMENTATION
-
-print "Creating interface file ${CONTAINER}.h...";
-open OUT,">${CONTAINER}.h" or die "cannot open ${CONTAINER}.h";
-print OUT $interface;
-close OUT;
-print "ok.\n";
-
-print "Creating implementation file ${CONTAINER}.cpp...";
-open OUT,">${CONTAINER}.cpp" or die "cannot open ${CONTAINER}.cpp";
-print OUT $implementation;
-close OUT;
-print "ok.\n";
-
-print "done.\n";
namespace GiNaC {
//////////
-// other ctors
+// other constructors
//////////
// none (all inlined)
* @see print_context */
void ex::print(const print_context & c, unsigned level) const
{
- GINAC_ASSERT(bp!=0);
bp->print(c, level);
}
-/** Print expression to stream in a tree-like format suitable for debugging. */
-void ex::printtree(std::ostream & os) const
-{
- GINAC_ASSERT(bp!=0);
- bp->print(print_tree(os));
-}
-
/** Little wrapper arount print to be called within a debugger. */
-void ex::dbgprint(void) const
+void ex::dbgprint() const
{
- GINAC_ASSERT(bp!=0);
bp->dbgprint();
}
/** Little wrapper arount printtree to be called within a debugger. */
-void ex::dbgprinttree(void) const
+void ex::dbgprinttree() const
{
- GINAC_ASSERT(bp!=0);
bp->dbgprinttree();
}
ex ex::expand(unsigned options) const
{
- GINAC_ASSERT(bp!=0);
if (options == 0 && (bp->flags & status_flags::expanded)) // The "expanded" flag only covers the standard options; someone might want to re-expand with different options
return *bp;
else
* @return partial derivative as a new expression */
ex ex::diff(const symbol & s, unsigned nth) const
{
- GINAC_ASSERT(bp!=0);
-
if (!nth)
return *this;
else
return true;
}
bool any_found = false;
- for (unsigned i=0; i<nops(); i++)
+ for (size_t i=0; i<nops(); i++)
if (op(i).find(pattern, found))
any_found = true;
return any_found;
}
-ex ex::operator[](const ex & index) const
+/** Traverse expression tree with given visitor, preorder traversal. */
+void ex::traverse_preorder(visitor & v) const
{
- GINAC_ASSERT(bp!=0);
- return (*bp)[index];
+ accept(v);
+
+ size_t n = nops();
+ for (size_t i = 0; i < n; ++i)
+ op(i).traverse_preorder(v);
}
-ex ex::operator[](int i) const
+/** Traverse expression tree with given visitor, postorder traversal. */
+void ex::traverse_postorder(visitor & v) const
{
- GINAC_ASSERT(bp!=0);
- return (*bp)[i];
+ size_t n = nops();
+ for (size_t i = 0; i < n; ++i)
+ op(i).traverse_postorder(v);
+
+ accept(v);
}
/** Return modifyable operand/member at position i. */
-ex & ex::let_op(int i)
+ex & ex::let_op(size_t i)
{
makewriteable();
- GINAC_ASSERT(bp!=0);
return bp->let_op(i);
}
+ex & ex::operator[](const ex & index)
+{
+ makewriteable();
+ return (*bp)[index];
+}
+
+ex & ex::operator[](size_t i)
+{
+ makewriteable();
+ return (*bp)[i];
+}
+
/** Left hand side of relational expression. */
-ex ex::lhs(void) const
+ex ex::lhs() const
{
- if (!is_ex_of_type(*this,relational))
+ if (!is_a<relational>(*this))
throw std::runtime_error("ex::lhs(): not a relation");
- return (*static_cast<relational *>(bp)).lhs();
+ return bp->op(0);
}
/** Right hand side of relational expression. */
-ex ex::rhs(void) const
+ex ex::rhs() const
{
- if (!is_ex_of_type(*this,relational))
+ if (!is_a<relational>(*this))
throw std::runtime_error("ex::rhs(): not a relation");
- return (*static_cast<relational *>(bp)).rhs();
+ return bp->op(1);
}
// private
* unlinking the object and creating an unshared copy of it. */
void ex::makewriteable()
{
- GINAC_ASSERT(bp!=0);
GINAC_ASSERT(bp->flags & status_flags::dynallocated);
- if (bp->refcount > 1) {
- basic * bp2 = bp->duplicate();
- ++bp2->refcount;
- bp2->setflag(status_flags::dynallocated);
- --bp->refcount;
- bp = bp2;
- }
- GINAC_ASSERT(bp->refcount==1);
+ bp.makewritable();
+ GINAC_ASSERT(bp->refcount == 1);
}
-/** Ctor from basic implementation.
+/** Helper function for the ex-from-basic constructor. This is where GiNaC's
+ * automatic evaluator and memory management are implemented.
* @see ex::ex(const basic &) */
-void ex::construct_from_basic(const basic & other)
+ptr<basic> ex::construct_from_basic(const basic & other)
{
if (!(other.flags & status_flags::evaluated)) {
- const ex & tmpex = other.eval(1); // evaluate only one (top) level
- bp = tmpex.bp;
- GINAC_ASSERT(bp->flags & status_flags::dynallocated);
- ++bp->refcount;
+
+ // The object is not yet evaluated, so call eval() to evaluate
+ // the top level. This will return either
+ // a) the original object with status_flags::evaluated set (when the
+ // eval() implementation calls hold())
+ // or
+ // b) a different expression.
+ //
+ // eval() returns an ex, not a basic&, so this will go through
+ // construct_from_basic() a second time. In case a) we end up in
+ // the "else" branch below. In case b) we end up here again and
+ // apply eval() once more. The recursion stops when eval() calls
+ // hold() or returns an object that already has its "evaluated"
+ // flag set, such as a symbol or a numeric.
+ const ex & tmpex = other.eval(1);
+
+ // Eventually, the eval() recursion goes through the "else" branch
+ // below, which assures that the object pointed to by tmpex.bp is
+ // allocated on the heap (either it was already on the heap or it
+ // is a heap-allocated duplicate of another object).
+ GINAC_ASSERT(tmpex.bp->flags & status_flags::dynallocated);
+
+ // If the original object is not referenced but heap-allocated,
+ // it means that eval() hit case b) above. The original object is
+ // no longer needed (it evaluated into something different), so we
+ // delete it (because nobody else will).
if ((other.refcount==0) && (other.flags & status_flags::dynallocated))
- delete &const_cast<basic &>(other);
+ delete &other; // yes, you can apply delete to a const pointer
+
+ // We can't return a basic& here because the tmpex is destroyed as
+ // soon as we leave the function, which would deallocate the
+ // evaluated object.
+ return tmpex.bp;
+
} else {
+
+ // The easy case: making an "ex" out of an evaluated object.
if (other.flags & status_flags::dynallocated) {
- // ok, it is already on the heap, so just copy bp:
- bp = &const_cast<basic &>(other);
+
+ // The object is already heap-allocated, so we can just make
+ // another reference to it.
+ return ptr<basic>(const_cast<basic &>(other));
+
} else {
- // create a duplicate on the heap:
- bp = other.duplicate();
+
+ // The object is not heap-allocated, so we create a duplicate
+ // on the heap.
+ basic *bp = other.duplicate();
bp->setflag(status_flags::dynallocated);
+ GINAC_ASSERT(bp->refcount == 0);
+ return bp;
}
- GINAC_ASSERT(bp!=0);
- ++bp->refcount;
}
- GINAC_ASSERT(bp!=0);
- GINAC_ASSERT(bp->flags & status_flags::dynallocated);
}
-void ex::construct_from_int(int i)
+basic & ex::construct_from_int(int i)
{
switch (i) { // prefer flyweights over new objects
case -12:
- bp = (basic*)_num_12_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num_12);
case -11:
- bp = (basic*)_num_11_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num_11);
case -10:
- bp = (basic*)_num_10_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num_10);
case -9:
- bp = (basic*)_num_9_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num_9);
case -8:
- bp = (basic*)_num_8_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num_8);
case -7:
- bp = (basic*)_num_7_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num_7);
case -6:
- bp = (basic*)_num_6_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num_6);
case -5:
- bp = (basic*)_num_5_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num_5);
case -4:
- bp = (basic*)_num_4_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num_4);
case -3:
- bp = (basic*)_num_3_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num_3);
case -2:
- bp = (basic*)_num_2_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num_2);
case -1:
- bp = (basic*)_num_1_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num_1);
case 0:
- bp = (basic*)_num0_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num0);
case 1:
- bp = (basic*)_num1_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num1);
case 2:
- bp = (basic*)_num2_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num2);
case 3:
- bp = (basic*)_num3_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num3);
case 4:
- bp = (basic*)_num4_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num4);
case 5:
- bp = (basic*)_num5_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num5);
case 6:
- bp = (basic*)_num6_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num6);
case 7:
- bp = (basic*)_num7_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num7);
case 8:
- bp = (basic*)_num8_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num8);
case 9:
- bp = (basic*)_num9_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num9);
case 10:
- bp = (basic*)_num10_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num10);
case 11:
- bp = (basic*)_num11_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num11);
case 12:
- bp = (basic*)_num12_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num12);
default:
- bp = new numeric(i);
+ basic *bp = new numeric(i);
bp->setflag(status_flags::dynallocated);
- ++bp->refcount;
- GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
- GINAC_ASSERT(bp->refcount==1);
+ GINAC_ASSERT(bp->refcount == 0);
+ return *bp;
}
}
-void ex::construct_from_uint(unsigned int i)
+basic & ex::construct_from_uint(unsigned int i)
{
switch (i) { // prefer flyweights over new objects
case 0:
- bp = (basic*)_num0_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num0);
case 1:
- bp = (basic*)_num1_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num1);
case 2:
- bp = (basic*)_num2_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num2);
case 3:
- bp = (basic*)_num3_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num3);
case 4:
- bp = (basic*)_num4_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num4);
case 5:
- bp = (basic*)_num5_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num5);
case 6:
- bp = (basic*)_num6_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num6);
case 7:
- bp = (basic*)_num7_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num7);
case 8:
- bp = (basic*)_num8_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num8);
case 9:
- bp = (basic*)_num9_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num9);
case 10:
- bp = (basic*)_num10_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num10);
case 11:
- bp = (basic*)_num11_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num11);
case 12:
- bp = (basic*)_num12_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num12);
default:
- bp = new numeric(i);
+ basic *bp = new numeric(i);
bp->setflag(status_flags::dynallocated);
- ++bp->refcount;
- GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
- GINAC_ASSERT(bp->refcount==1);
+ GINAC_ASSERT(bp->refcount == 0);
+ return *bp;
}
}
-void ex::construct_from_long(long i)
+basic & ex::construct_from_long(long i)
{
switch (i) { // prefer flyweights over new objects
case -12:
- bp = (basic*)_num_12_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num_12);
case -11:
- bp = (basic*)_num_11_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num_11);
case -10:
- bp = (basic*)_num_10_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num_10);
case -9:
- bp = (basic*)_num_9_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num_9);
case -8:
- bp = (basic*)_num_8_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num_8);
case -7:
- bp = (basic*)_num_7_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num_7);
case -6:
- bp = (basic*)_num_6_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num_6);
case -5:
- bp = (basic*)_num_5_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num_5);
case -4:
- bp = (basic*)_num_4_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num_4);
case -3:
- bp = (basic*)_num_3_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num_3);
case -2:
- bp = (basic*)_num_2_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num_2);
case -1:
- bp = (basic*)_num_1_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num_1);
case 0:
- bp = (basic*)_num0_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num0);
case 1:
- bp = (basic*)_num1_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num1);
case 2:
- bp = (basic*)_num2_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num2);
case 3:
- bp = (basic*)_num3_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num3);
case 4:
- bp = (basic*)_num4_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num4);
case 5:
- bp = (basic*)_num5_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num5);
case 6:
- bp = (basic*)_num6_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num6);
case 7:
- bp = (basic*)_num7_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num7);
case 8:
- bp = (basic*)_num8_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num8);
case 9:
- bp = (basic*)_num9_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num9);
case 10:
- bp = (basic*)_num10_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num10);
case 11:
- bp = (basic*)_num11_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num11);
case 12:
- bp = (basic*)_num12_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num12);
default:
- bp = new numeric(i);
+ basic *bp = new numeric(i);
bp->setflag(status_flags::dynallocated);
- ++bp->refcount;
- GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
- GINAC_ASSERT(bp->refcount==1);
+ GINAC_ASSERT(bp->refcount == 0);
+ return *bp;
}
}
-void ex::construct_from_ulong(unsigned long i)
+basic & ex::construct_from_ulong(unsigned long i)
{
switch (i) { // prefer flyweights over new objects
case 0:
- bp = (basic*)_num0_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num0);
case 1:
- bp = (basic*)_num1_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num1);
case 2:
- bp = (basic*)_num2_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num2);
case 3:
- bp = (basic*)_num3_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num3);
case 4:
- bp = (basic*)_num4_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num4);
case 5:
- bp = (basic*)_num5_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num5);
case 6:
- bp = (basic*)_num6_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num6);
case 7:
- bp = (basic*)_num7_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num7);
case 8:
- bp = (basic*)_num8_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num8);
case 9:
- bp = (basic*)_num9_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num9);
case 10:
- bp = (basic*)_num10_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num10);
case 11:
- bp = (basic*)_num11_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num11);
case 12:
- bp = (basic*)_num12_p;
- ++bp->refcount;
- break;
+ return const_cast<numeric &>(_num12);
default:
- bp = new numeric(i);
+ basic *bp = new numeric(i);
bp->setflag(status_flags::dynallocated);
- ++bp->refcount;
- GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
- GINAC_ASSERT(bp->refcount==1);
+ GINAC_ASSERT(bp->refcount == 0);
+ return *bp;
}
}
-void ex::construct_from_double(double d)
+basic & ex::construct_from_double(double d)
{
- bp = new numeric(d);
+ basic *bp = new numeric(d);
bp->setflag(status_flags::dynallocated);
- ++bp->refcount;
- GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
- GINAC_ASSERT(bp->refcount==1);
+ GINAC_ASSERT(bp->refcount == 0);
+ return *bp;
}
-void ex::construct_from_string_and_lst(const std::string &s, const ex &l)
+ptr<basic> ex::construct_from_string_and_lst(const std::string &s, const ex &l)
{
set_lexer_string(s);
set_lexer_symbols(l);
ginac_yyrestart(NULL);
if (ginac_yyparse())
throw (std::runtime_error(get_parser_error()));
- else {
- bp = parsed_ex.bp;
- GINAC_ASSERT(bp!=0);
- GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
- ++bp->refcount;
- }
+ else
+ return parsed_ex.bp;
}
//////////
#include <functional>
#include "basic.h"
-#include "operators.h"
+#include "ptr.h"
namespace GiNaC {
+
/** Helper class to initialize the library. There must be one static object
* of this class in every object file that makes use of our flyweights in
* order to guarantee proper initialization. Hence we put it into this
/** For construction of flyweights, etc. */
static library_init library_initializer;
-// Current versions of Cint don't link data declared extern within functions.
-// FIXME: Fix Cint and later remove this from here.
-#if defined(G__CINTVERSION)
-extern const class numeric *_num0_p;
-#endif
-
-class symbol;
-class lst;
class scalar_products;
template<class T> friend bool is_a(const ex &);
template<class T> friend bool is_exactly_a(const ex &);
-// member functions
-
- // default ctor, dtor, copy ctor, assignment operator and helpers
+ // default constructor, copy constructor and assignment operator
public:
ex();
- ~ex();
+#ifdef OBSCURE_CINT_HACK
ex(const ex & other);
ex & operator=(const ex & other);
- // other ctors
+#endif
+
+ // other constructors
public:
ex(const basic & other);
ex(int i);
/** Efficiently swap the contents of two expressions. */
void swap(ex & other)
{
- GINAC_ASSERT(bp!=0);
GINAC_ASSERT(bp->flags & status_flags::dynallocated);
- GINAC_ASSERT(other.bp!=0);
GINAC_ASSERT(other.bp->flags & status_flags::dynallocated);
-
- basic * tmpbp = bp;
- bp = other.bp;
- other.bp = tmpbp;
+ bp.swap(other.bp);
}
+ // evaluation
+ ex eval(int level = 0) const { return bp->eval(level); }
+ ex evalf(int level = 0) const { return bp->evalf(level); }
+ ex evalm() const { return bp->evalm(); }
+ ex eval_ncmul(const exvector & v) const { return bp->eval_ncmul(v); }
+
+ // printing
void print(const print_context & c, unsigned level = 0) const;
- void printtree(std::ostream & os) const;
- void dbgprint(void) const;
- void dbgprinttree(void) const;
+ void dbgprint() const;
+ void dbgprinttree() const;
+
+ // info
bool info(unsigned inf) const { return bp->info(inf); }
- unsigned nops() const { return bp->nops(); }
- ex expand(unsigned options=0) const;
+
+ // operand access
+ size_t nops() const { return bp->nops(); }
+ ex op(size_t i) const { return bp->op(i); }
+ ex operator[](const ex & index) const { return (*bp)[index]; }
+ ex operator[](size_t i) const { return (*bp)[i]; }
+ ex & let_op(size_t i);
+ ex & operator[](const ex & index);
+ ex & operator[](size_t i);
+ ex lhs() const;
+ ex rhs() const;
+
+ // pattern matching
bool has(const ex & pattern) const { return bp->has(pattern); }
+ bool find(const ex & pattern, lst & found) const;
+ bool match(const ex & pattern) const;
+ bool match(const ex & pattern, lst & repl_lst) const { return bp->match(pattern, repl_lst); }
+
+ // substitutions
+ ex subs(const lst & ls, const lst & lr, unsigned options = 0) const { return bp->subs(ls, lr, options); }
+ ex subs(const ex & e, unsigned options = 0) const { return bp->subs(e, options); }
+
+ // function mapping
ex map(map_function & f) const { return bp->map(f); }
ex map(ex (*f)(const ex & e)) const;
- bool find(const ex & pattern, lst & found) const;
+
+ // visitors and tree traversal
+ void accept(visitor & v) const { bp->accept(v); }
+ void traverse_preorder(visitor & v) const;
+ void traverse_postorder(visitor & v) const;
+ void traverse(visitor & v) const { traverse_preorder(v); }
+
+ // degree/coeff
int degree(const ex & s) const { return bp->degree(s); }
int ldegree(const ex & s) const { return bp->ldegree(s); }
ex coeff(const ex & s, int n = 1) const { return bp->coeff(s, n); }
ex lcoeff(const ex & s) const { return coeff(s, degree(s)); }
ex tcoeff(const ex & s) const { return coeff(s, ldegree(s)); }
- ex numer(void) const;
- ex denom(void) const;
- ex numer_denom(void) const;
+
+ // expand/collect
+ ex expand(unsigned options=0) const;
+ ex collect(const ex & s, bool distributed = false) const { return bp->collect(s, distributed); }
+
+ // differentiation and series expansion
+ ex diff(const symbol & s, unsigned nth = 1) const;
+ ex series(const ex & r, int order, unsigned options = 0) const;
+
+ // rational functions
+ ex normal(int level = 0) const;
+ ex to_rational(lst &repl_lst) const;
+ ex to_polynomial(lst &repl_lst) const;
+ ex numer() const;
+ ex denom() const;
+ ex numer_denom() const;
+
+ // polynomial algorithms
ex unit(const symbol &x) const;
ex content(const symbol &x) const;
- numeric integer_content(void) const;
+ numeric integer_content() const;
ex primpart(const symbol &x) const;
ex primpart(const symbol &x, const ex &cont) const;
- ex normal(int level = 0) const;
- ex to_rational(lst &repl_lst) const { return bp->to_rational(repl_lst); }
ex smod(const numeric &xi) const { return bp->smod(xi); }
- numeric max_coefficient(void) const;
- ex collect(const ex & s, bool distributed = false) const { return bp->collect(s, distributed); }
- ex eval(int level = 0) const { return bp->eval(level); }
- ex evalf(int level = 0) const { return bp->evalf(level); }
- ex evalm(void) const { return bp->evalm(); }
- ex diff(const symbol & s, unsigned nth = 1) const;
- ex series(const ex & r, int order, unsigned options = 0) const;
- bool match(const ex & pattern) const;
- bool match(const ex & pattern, lst & repl_lst) const { return bp->match(pattern, repl_lst); }
- ex subs(const lst & ls, const lst & lr, bool no_pattern = false) const { return bp->subs(ls, lr, no_pattern); }
- ex subs(const ex & e, bool no_pattern = false) const { return bp->subs(e, no_pattern); }
- exvector get_free_indices(void) const { return bp->get_free_indices(); }
- ex simplify_indexed(void) const;
+ numeric max_coefficient() const;
+
+ // indexed objects
+ exvector get_free_indices() const { return bp->get_free_indices(); }
+ ex simplify_indexed() const;
ex simplify_indexed(const scalar_products & sp) const;
- ex symmetrize(void) const;
- ex symmetrize(const lst & l) const;
- ex antisymmetrize(void) const;
- ex antisymmetrize(const lst & l) const;
- ex symmetrize_cyclic(void) const;
- ex symmetrize_cyclic(const lst & l) const;
- ex simplify_ncmul(const exvector & v) const { return bp->simplify_ncmul(v); }
- ex operator[](const ex & index) const;
- ex operator[](int i) const;
- ex op(int i) const { return bp->op(i); }
- ex & let_op(int i);
- ex lhs(void) const;
- ex rhs(void) const;
+
+ // comparison
int compare(const ex & other) const;
bool is_equal(const ex & other) const;
- bool is_zero(void) const { extern const ex _ex0; return is_equal(_ex0); }
+ bool is_zero() const { extern const ex _ex0; return is_equal(_ex0); }
- unsigned return_type(void) const { return bp->return_type(); }
- unsigned return_type_tinfo(void) const { return bp->return_type_tinfo(); }
- unsigned gethash(void) const { return bp->gethash(); }
+ // symmetry
+ ex symmetrize() const;
+ ex symmetrize(const lst & l) const;
+ ex antisymmetrize() const;
+ ex antisymmetrize(const lst & l) const;
+ ex symmetrize_cyclic() const;
+ ex symmetrize_cyclic(const lst & l) const;
+
+ // noncommutativity
+ unsigned return_type() const { return bp->return_type(); }
+ unsigned return_type_tinfo() const { return bp->return_type_tinfo(); }
+
+ unsigned gethash() const { return bp->gethash(); }
+
private:
- void construct_from_basic(const basic & other);
- void construct_from_int(int i);
- void construct_from_uint(unsigned int i);
- void construct_from_long(long i);
- void construct_from_ulong(unsigned long i);
- void construct_from_double(double d);
- void construct_from_string_and_lst(const std::string &s, const ex &l);
+ static ptr<basic> construct_from_basic(const basic & other);
+ static basic & construct_from_int(int i);
+ static basic & construct_from_uint(unsigned int i);
+ static basic & construct_from_long(long i);
+ static basic & construct_from_ulong(unsigned long i);
+ static basic & construct_from_double(double d);
+ static ptr<basic> construct_from_string_and_lst(const std::string &s, const ex &l);
void makewriteable();
#ifdef OBSCURE_CINT_HACK
public:
- static bool last_created_or_assigned_bp_can_be_converted_to_ex(void)
+ static bool last_created_or_assigned_bp_can_be_converted_to_ex()
{
if (last_created_or_assigned_bp==0) return false;
if ((last_created_or_assigned_bp->flags &
return true;
}
protected:
- void update_last_created_or_assigned_bp(void)
+ void update_last_created_or_assigned_bp()
{
- if (last_created_or_assigned_bp!=0) {
- if (--last_created_or_assigned_bp->refcount == 0) {
- delete last_created_or_assigned_bp;
- }
- }
last_created_or_assigned_bp = bp;
- ++last_created_or_assigned_bp->refcount;
last_created_or_assigned_exp = (long)(void *)(this);
}
#endif // def OBSCURE_CINT_HACK
// member variables
-public:
- basic *bp; ///< pointer to basic object managed by this, direct manipulation deprecated
+private:
+ ptr<basic> bp; ///< pointer to basic object managed by this
+
#ifdef OBSCURE_CINT_HACK
- static basic * last_created_or_assigned_bp;
+public:
+ static ptr<basic> last_created_or_assigned_bp;
static basic * dummy_bp;
static long last_created_or_assigned_exp;
#endif // def OBSCURE_CINT_HACK
// performance-critical inlined method implementations
+// This needs to be a basic* because we don't know that numeric is derived
+// from basic and we need a basic& for the ex default constructor
+extern const basic *_num0_bp;
+
inline
-ex::ex()
+ex::ex() : bp(*const_cast<basic *>(_num0_bp))
{
- extern const class numeric *_num0_p;
- bp = (basic*)_num0_p;
- GINAC_ASSERT(bp!=0);
GINAC_ASSERT(bp->flags & status_flags::dynallocated);
- ++bp->refcount;
#ifdef OBSCURE_CINT_HACK
update_last_created_or_assigned_bp();
#endif // def OBSCURE_CINT_HACK
}
-inline
-ex::~ex()
-{
- GINAC_ASSERT(bp!=0);
- GINAC_ASSERT(bp->flags & status_flags::dynallocated);
- if (--bp->refcount == 0)
- delete bp;
-}
-
+#ifdef OBSCURE_CINT_HACK
inline
ex::ex(const ex & other) : bp(other.bp)
{
- GINAC_ASSERT(bp!=0);
GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
- ++bp->refcount;
-#ifdef OBSCURE_CINT_HACK
update_last_created_or_assigned_bp();
-#endif // def OBSCURE_CINT_HACK
}
inline
ex & ex::operator=(const ex & other)
{
- GINAC_ASSERT(bp!=0);
GINAC_ASSERT(bp->flags & status_flags::dynallocated);
- GINAC_ASSERT(other.bp!=0);
GINAC_ASSERT(other.bp->flags & status_flags::dynallocated);
- // NB: must first increment other.bp->refcount, since other might be *this.
- ++other.bp->refcount;
- if (--bp->refcount==0)
- delete bp;
bp = other.bp;
-#ifdef OBSCURE_CINT_HACK
update_last_created_or_assigned_bp();
-#endif // def OBSCURE_CINT_HACK
return *this;
}
+#endif // def OBSCURE_CINT_HACK
inline
-ex::ex(const basic & other)
+ex::ex(const basic & other) : bp(construct_from_basic(other))
{
- construct_from_basic(other);
+ GINAC_ASSERT(bp->flags & status_flags::dynallocated);
#ifdef OBSCURE_CINT_HACK
update_last_created_or_assigned_bp();
#endif // def OBSCURE_CINT_HACK
}
inline
-ex::ex(int i)
+ex::ex(int i) : bp(construct_from_int(i))
{
- construct_from_int(i);
+ GINAC_ASSERT(bp->flags & status_flags::dynallocated);
#ifdef OBSCURE_CINT_HACK
update_last_created_or_assigned_bp();
#endif // def OBSCURE_CINT_HACK
}
inline
-ex::ex(unsigned int i)
+ex::ex(unsigned int i) : bp(construct_from_uint(i))
{
- construct_from_uint(i);
+ GINAC_ASSERT(bp->flags & status_flags::dynallocated);
#ifdef OBSCURE_CINT_HACK
update_last_created_or_assigned_bp();
#endif // def OBSCURE_CINT_HACK
}
inline
-ex::ex(long i)
+ex::ex(long i) : bp(construct_from_long(i))
{
- construct_from_long(i);
+ GINAC_ASSERT(bp->flags & status_flags::dynallocated);
#ifdef OBSCURE_CINT_HACK
update_last_created_or_assigned_bp();
#endif // def OBSCURE_CINT_HACK
}
inline
-ex::ex(unsigned long i)
+ex::ex(unsigned long i) : bp(construct_from_ulong(i))
{
- construct_from_ulong(i);
+ GINAC_ASSERT(bp->flags & status_flags::dynallocated);
#ifdef OBSCURE_CINT_HACK
update_last_created_or_assigned_bp();
#endif // def OBSCURE_CINT_HACK
}
inline
-ex::ex(double const d)
+ex::ex(double const d) : bp(construct_from_double(d))
{
- construct_from_double(d);
+ GINAC_ASSERT(bp->flags & status_flags::dynallocated);
#ifdef OBSCURE_CINT_HACK
update_last_created_or_assigned_bp();
#endif // def OBSCURE_CINT_HACK
}
inline
-ex::ex(const std::string &s, const ex &l)
+ex::ex(const std::string &s, const ex &l) : bp(construct_from_string_and_lst(s, l))
{
- construct_from_string_and_lst(s, l);
+ GINAC_ASSERT(bp->flags & status_flags::dynallocated);
#ifdef OBSCURE_CINT_HACK
update_last_created_or_assigned_bp();
#endif // def OBSCURE_CINT_HACK
inline
int ex::compare(const ex & other) const
{
- GINAC_ASSERT(bp!=0);
- GINAC_ASSERT(other.bp!=0);
- if (bp==other.bp) // trivial case: both expressions point to same basic
+ if (bp == other.bp) // trivial case: both expressions point to same basic
return 0;
return bp->compare(*other.bp);
}
inline
bool ex::is_equal(const ex & other) const
{
- GINAC_ASSERT(bp!=0);
- GINAC_ASSERT(other.bp!=0);
- if (bp==other.bp) // trivial case: both expressions point to same basic
+ if (bp == other.bp) // trivial case: both expressions point to same basic
return true;
return bp->is_equal(*other.bp);
}
}
// wrapper functions around member functions
-inline unsigned nops(const ex & thisex)
+inline size_t nops(const ex & thisex)
{ return thisex.nops(); }
inline ex expand(const ex & thisex, unsigned options = 0)
inline ex to_rational(const ex & thisex, lst & repl_lst)
{ return thisex.to_rational(repl_lst); }
+inline ex to_polynomial(const ex & thisex, lst & repl_lst)
+{ return thisex.to_polynomial(repl_lst); }
+
inline ex collect(const ex & thisex, const ex & s, bool distributed = false)
{ return thisex.collect(s, distributed); }
inline bool match(const ex & thisex, const ex & pattern, lst & repl_lst)
{ return thisex.match(pattern, repl_lst); }
-inline ex subs(const ex & thisex, const ex & e)
-{ return thisex.subs(e); }
+inline ex subs(const ex & thisex, const ex & e, unsigned options = 0)
+{ return thisex.subs(e, options); }
-inline ex subs(const ex & thisex, const lst & ls, const lst & lr)
-{ return thisex.subs(ls, lr); }
+inline ex subs(const ex & thisex, const lst & ls, const lst & lr, unsigned options = 0)
+{ return thisex.subs(ls, lr, options); }
inline ex simplify_indexed(const ex & thisex)
{ return thisex.simplify_indexed(); }
inline ex symmetrize_cyclic(const ex & thisex, const lst & l)
{ return thisex.symmetrize_cyclic(l); }
-inline ex op(const ex & thisex, int i)
+inline ex op(const ex & thisex, size_t i)
{ return thisex.op(i); }
inline ex lhs(const ex & thisex)
inline void swap(ex & e1, ex & e2)
{ e1.swap(e2); }
+
// This makes STL algorithms use the more efficient swap operation for ex objects
inline void iter_swap(std::vector<ex>::iterator i1, std::vector<ex>::iterator i2)
{ i1->swap(*i2); }
{
public:
expair() : rest(0), coeff(1) { }
- ~expair() { }
- expair(const expair & other) : rest(other.rest), coeff(other.coeff)
- {
- GINAC_ASSERT(is_exactly_a<numeric>(coeff));
- }
- const expair & operator=(const expair & other)
- {
- if (this != &other) {
- rest = other.rest;
- coeff = other.coeff;
- }
- return *this;
- }
-
+
/** Construct an expair from two ex. */
expair(const ex & r, const ex & c) : rest(r), coeff(c)
{
void print(std::ostream & os) const;
/** True if this is of the form (numeric,ex(1)). */
- bool is_canonical_numeric(void) const
+ bool is_canonical_numeric() const
{
GINAC_ASSERT(is_exactly_a<numeric>(coeff));
return (is_exactly_a<numeric>(rest) && (coeff.is_equal(1)));
#include "wildcard.h"
#include "print.h"
#include "archive.h"
+#include "operators.h"
#include "utils.h"
#if EXPAIRSEQ_USE_HASHTAB
namespace GiNaC {
-GINAC_IMPLEMENT_REGISTERED_CLASS_NO_CTORS(expairseq, basic)
+GINAC_IMPLEMENT_REGISTERED_CLASS(expairseq, basic)
//////////
// helper classes
};
//////////
-// default ctor, dtor, copy ctor, assignment operator and helpers
+// default constructor
//////////
// public
-expairseq::expairseq(const expairseq &other)
-{
- copy(other);
-}
-
-const expairseq &expairseq::operator=(const expairseq &other)
-{
- if (this != &other) {
- destroy(true);
- copy(other);
- }
- return *this;
-}
+expairseq::expairseq() : inherited(TINFO_expairseq)
+#if EXPAIRSEQ_USE_HASHTAB
+ , hashtabsize(0)
+#endif // EXPAIRSEQ_USE_HASHTAB
+{}
// protected
+#if 0
/** For use by copy ctor and assignment operator. */
void expairseq::copy(const expairseq &other)
{
- inherited::copy(other);
seq = other.seq;
overall_coeff = other.overall_coeff;
#if EXPAIRSEQ_USE_HASHTAB
}
#endif // EXPAIRSEQ_USE_HASHTAB
}
-
-DEFAULT_DESTROY(expairseq)
+#endif
//////////
-// other ctors
+// other constructors
//////////
expairseq::expairseq(const ex &lh, const ex &rh) : inherited(TINFO_expairseq)
// archiving
//////////
-expairseq::expairseq(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
+expairseq::expairseq(const archive_node &n, lst &sym_lst) : inherited(n, sym_lst)
#if EXPAIRSEQ_USE_HASHTAB
, hashtabsize(0)
#endif
{
-
for (unsigned int i=0; true; i++) {
-
- canonicalize();
- GINAC_ASSERT(is_canonical());
ex rest;
ex coeff;
if (n.find_ex("rest", rest, sym_lst, i) && n.find_ex("coeff", coeff, sym_lst, i))
else
break;
}
+
n.find_ex("overall_coeff", overall_coeff, sym_lst);
+
+ canonicalize();
+ GINAC_ASSERT(is_canonical());
}
void expairseq::archive(archive_node &n) const
// public
-basic *expairseq::duplicate() const
-{
- return new expairseq(*this);
-}
-
void expairseq::print(const print_context &c, unsigned level) const
{
- if (is_of_type(c, print_tree)) {
+ if (is_a<print_tree>(c)) {
unsigned delta_indent = static_cast<const print_tree &>(c).delta_indent;
<< std::hex << ", hash=0x" << hashvalue << ", flags=0x" << flags << std::dec
<< ", nops=" << nops()
<< std::endl;
- unsigned num = seq.size();
- for (unsigned i=0; i<num; ++i) {
+ size_t num = seq.size();
+ for (size_t i=0; i<num; ++i) {
seq[i].rest.print(c, level + delta_indent);
seq[i].coeff.print(c, level + delta_indent);
if (i != num - 1)
return inherited::info(inf);
}
-unsigned expairseq::nops() const
+size_t expairseq::nops() const
{
if (overall_coeff.is_equal(default_overall_coeff()))
return seq.size();
return seq.size()+1;
}
-ex expairseq::op(int i) const
+ex expairseq::op(size_t i) const
{
- if (unsigned(i)<seq.size())
+ if (i < seq.size())
return recombine_pair_to_ex(seq[i]);
GINAC_ASSERT(!overall_coeff.is_equal(default_overall_coeff()));
return overall_coeff;
}
-ex &expairseq::let_op(int i)
-{
- throw(std::logic_error("let_op not defined for expairseq and derived classes (add,mul,...)"));
-}
-
ex expairseq::map(map_function &f) const
{
epvector *v = new epvector;
// expression", like "*" above) is present
bool has_global_wildcard = false;
ex global_wildcard;
- for (unsigned int i=0; i<pattern.nops(); i++) {
- if (is_ex_exactly_of_type(pattern.op(i), wildcard)) {
+ for (size_t i=0; i<pattern.nops(); i++) {
+ if (is_exactly_a<wildcard>(pattern.op(i))) {
has_global_wildcard = true;
global_wildcard = pattern.op(i);
break;
// Chop into terms
exvector ops;
ops.reserve(nops());
- for (unsigned i=0; i<nops(); i++)
+ for (size_t i=0; i<nops(); i++)
ops.push_back(op(i));
// Now, for every term of the pattern, look for a matching term in
// the expression and remove the match
- for (unsigned i=0; i<pattern.nops(); i++) {
+ for (size_t i=0; i<pattern.nops(); i++) {
ex p = pattern.op(i);
if (has_global_wildcard && p.is_equal(global_wildcard))
continue;
// Assign all the remaining terms to the global wildcard (unless
// it has already been matched before, in which case the matches
// must be equal)
- unsigned num = ops.size();
+ size_t num = ops.size();
epvector *vp = new epvector();
vp->reserve(num);
- for (unsigned i=0; i<num; i++)
+ for (size_t i=0; i<num; i++)
vp->push_back(split_ex_to_pair(ops[i]));
ex rest = thisexpairseq(vp, default_overall_coeff());
- for (unsigned i=0; i<repl_lst.nops(); i++) {
- if (repl_lst.op(i).op(0).is_equal(global_wildcard))
- return rest.is_equal(repl_lst.op(i).op(1));
+ for (lst::const_iterator it = repl_lst.begin(); it != repl_lst.end(); ++it) {
+ if (it->op(0).is_equal(global_wildcard))
+ return rest.is_equal(it->op(1));
}
repl_lst.append(global_wildcard == rest);
return true;
return inherited::match(pattern, repl_lst);
}
-ex expairseq::subs(const lst &ls, const lst &lr, bool no_pattern) const
+ex expairseq::subs(const lst &ls, const lst &lr, unsigned options) const
{
- epvector *vp = subschildren(ls, lr, no_pattern);
+ epvector *vp = subschildren(ls, lr, options);
if (vp)
return ex_to<basic>(thisexpairseq(vp, overall_coeff));
+ else if ((options & subs_options::subs_algebraic) && is_exactly_a<mul>(*this))
+ return static_cast<const mul *>(this)->algebraic_subs_mul(ls, lr, options);
else
- return basic::subs(ls, lr, no_pattern);
+ return subs_one_level(ls, lr, options);
}
// protected
#endif // EXPAIRSEQ_USE_HASHTAB
}
-unsigned expairseq::return_type(void) const
+unsigned expairseq::return_type() const
{
return return_types::noncommutative_composite;
}
-unsigned expairseq::calchash(void) const
+unsigned expairseq::calchash() const
{
unsigned v = golden_ratio_hash(this->tinfo());
- epvector::const_iterator i = seq.begin(), end = seq.end();
+ epvector::const_iterator i = seq.begin();
+ const epvector::const_iterator end = seq.end();
while (i != end) {
-#if !EXPAIRSEQ_USE_HASHTAB
- v = rotate_left_31(v); // rotation would spoil commutativity
-#endif // EXPAIRSEQ_USE_HASHTAB
v ^= i->rest.gethash();
#if !EXPAIRSEQ_USE_HASHTAB
- v = rotate_left_31(v);
+ // rotation spoils commutativity!
+ v = rotate_left(v);
v ^= i->coeff.gethash();
-#endif // EXPAIRSEQ_USE_HASHTAB
+#endif // !EXPAIRSEQ_USE_HASHTAB
++i;
}
-
+
v ^= overall_coeff.gethash();
- v &= 0x7FFFFFFFU;
-
+
// store calculated hash value only if object is already evaluated
if (flags &status_flags::evaluated) {
setflag(status_flags::hash_calculated);
return false;
}
-ex expairseq::default_overall_coeff(void) const
+ex expairseq::default_overall_coeff() const
{
return _ex0;
}
hashtabsize = 0;
#endif // EXPAIRSEQ_USE_HASHTAB
- if (is_ex_exactly_of_type(lh,numeric)) {
- if (is_ex_exactly_of_type(rh,numeric)) {
+ if (is_exactly_a<numeric>(lh)) {
+ if (is_exactly_a<numeric>(rh)) {
combine_overall_coeff(lh);
combine_overall_coeff(rh);
} else {
seq.push_back(split_ex_to_pair(rh));
}
} else {
- if (is_ex_exactly_of_type(rh,numeric)) {
+ if (is_exactly_a<numeric>(rh)) {
combine_overall_coeff(rh);
seq.push_back(split_ex_to_pair(lh));
} else {
const ex &e)
{
combine_overall_coeff(s.overall_coeff);
- if (is_ex_exactly_of_type(e,numeric)) {
+ if (is_exactly_a<numeric>(e)) {
combine_overall_coeff(e);
seq = s.seq;
return;
++cit_s;
}
} else {
- if (is_ex_exactly_of_type(*cit,numeric))
+ if (is_exactly_a<numeric>(*cit))
combine_overall_coeff(*cit);
else
seq.push_back(split_ex_to_pair(*cit));
}
/** Brings this expairseq into a sorted (canonical) form. */
-void expairseq::canonicalize(void)
+void expairseq::canonicalize()
{
std::sort(seq.begin(), seq.end(), expair_rest_is_less());
}
/** Compact a presorted expairseq by combining all matching expairs to one
* each. On an add object, this is responsible for 2*x+3*x+y -> 5*x+y, for
* instance. */
-void expairseq::combine_same_terms_sorted_seq(void)
+void expairseq::combine_same_terms_sorted_seq()
{
if (seq.size()<2)
return;
size = nearest_power_of_2/hashtabfactor;
if (size<minhashtabsize)
return 0;
- GINAC_ASSERT(hashtabsize<=0x8000000U); // really max size due to 31 bit hashing
+
// hashtabsize must be a power of 2
GINAC_ASSERT((1U << log2(size))==size);
return size;
unsigned expairseq::calc_hashindex(const ex &e) const
{
// calculate hashindex
- unsigned hash = e.gethash();
unsigned hashindex;
- if (is_a_numeric_hash(hash)) {
+ if (is_a<numeric>(e)) {
hashindex = hashmask;
} else {
- hashindex = hash &hashmask;
+ hashindex = e.gethash() & hashmask;
// last hashtab entry is reserved for numerics
if (hashindex==hashmask) hashindex = 0;
}
- GINAC_ASSERT(hashindex>=0);
GINAC_ASSERT((hashindex<hashtabsize)||(hashtabsize==0));
return hashindex;
}
-void expairseq::shrink_hashtab(void)
+void expairseq::shrink_hashtab()
{
unsigned new_hashtabsize;
while (hashtabsize!=(new_hashtabsize=calc_hashtabsize(seq.size()))) {
epp current = seq.begin();
while (current!=first_numeric) {
- if (is_ex_exactly_of_type(current->rest,numeric)) {
+ if (is_exactly_a<numeric>(current->rest)) {
--first_numeric;
iter_swap(current,first_numeric);
} else {
// move terms with coeff 0 to end and remove them from hashtab
// check only those elements which have been touched
epp current = seq.begin();
- unsigned i = 0;
+ size_t i = 0;
while (current!=first_numeric) {
if (!touched[i]) {
++current;
/** True if one of the coeffs vanishes, otherwise false.
* This would be an invariant violation, so this should only be used for
* debugging purposes. */
-bool expairseq::has_coeff_0(void) const
+bool expairseq::has_coeff_0() const
{
epvector::const_iterator i = seq.begin(), end = seq.end();
while (i != end) {
}
}
-void expairseq::combine_same_terms(void)
+void expairseq::combine_same_terms()
{
// combine same terms, drop term with coeff 0, move numerics to end
epvector::iterator first_numeric = seq.end();
epvector::iterator last_non_zero = seq.end()-1;
- unsigned num = seq.size();
+ size_t num = seq.size();
std::vector<bool> touched(num);
unsigned number_of_zeroes = 0;
epvector::const_iterator it_last = it;
for (++it; it!=itend; it_last=it, ++it) {
if (!(it_last->is_less(*it) || it_last->is_equal(*it))) {
- if (!is_ex_exactly_of_type(it_last->rest,numeric) ||
- !is_ex_exactly_of_type(it->rest,numeric)) {
+ if (!is_exactly_a<numeric>(it_last->rest) ||
+ !is_exactly_a<numeric>(it->rest)) {
// double test makes it easier to set a breakpoint...
- if (!is_ex_exactly_of_type(it_last->rest,numeric) ||
- !is_ex_exactly_of_type(it->rest,numeric)) {
+ if (!is_exactly_a<numeric>(it_last->rest) ||
+ !is_exactly_a<numeric>(it->rest)) {
printpair(std::clog, *it_last, 0);
std::clog << ">";
printpair(std::clog, *it, 0);
* @see expairseq::subs()
* @return pointer to epvector containing pairs after application of subs,
* or NULL pointer if no members were changed. */
-epvector * expairseq::subschildren(const lst &ls, const lst &lr, bool no_pattern) const
+epvector * expairseq::subschildren(const lst &ls, const lst &lr, unsigned options) const
{
GINAC_ASSERT(ls.nops()==lr.nops());
// is a product or power. In this case we have to recombine the pairs
// because the numeric coefficients may be part of the search pattern.
bool complex_subs = false;
- for (unsigned i=0; i<ls.nops(); ++i)
- if (is_ex_exactly_of_type(ls.op(i), mul) || is_ex_exactly_of_type(ls.op(i), power)) {
+ for (lst::const_iterator it = ls.begin(); it != ls.end(); ++it) {
+ if (is_exactly_a<mul>(*it) || is_exactly_a<power>(*it)) {
complex_subs = true;
break;
}
+ }
if (complex_subs) {
while (cit != last) {
const ex &orig_ex = recombine_pair_to_ex(*cit);
- const ex &subsed_ex = orig_ex.subs(ls, lr, no_pattern);
+ const ex &subsed_ex = orig_ex.subs(ls, lr, options);
if (!are_ex_trivially_equal(orig_ex, subsed_ex)) {
// Something changed, copy seq, subs and return it
// Copy rest
while (cit != last) {
- s->push_back(split_ex_to_pair(recombine_pair_to_ex(*cit).subs(ls, lr, no_pattern)));
+ s->push_back(split_ex_to_pair(recombine_pair_to_ex(*cit).subs(ls, lr, options)));
++cit;
}
return s;
epvector::const_iterator cit = seq.begin(), last = seq.end();
while (cit != last) {
- const ex &subsed_ex = cit->rest.subs(ls, lr, no_pattern);
+ const ex &subsed_ex = cit->rest.subs(ls, lr, options);
if (!are_ex_trivially_equal(cit->rest, subsed_ex)) {
// Something changed, copy seq, subs and return it
// Copy rest
while (cit != last) {
- s->push_back(combine_ex_with_coeff_to_pair(cit->rest.subs(ls, lr, no_pattern),
+ s->push_back(combine_ex_with_coeff_to_pair(cit->rest.subs(ls, lr, options),
cit->coeff));
++cit;
}
* multiplication, which is the reason why there is this base class. */
class expairseq : public basic
{
- GINAC_DECLARE_REGISTERED_CLASS_NO_CTORS(expairseq, basic)
+ GINAC_DECLARE_REGISTERED_CLASS(expairseq, basic)
-// member functions
-
- // default ctor, dtor, copy ctor, assignment operator and helpers
-public:
- expairseq() : basic(TINFO_expairseq)
-#if EXPAIRSEQ_USE_HASHTAB
- , hashtabsize(0)
-#endif // EXPAIRSEQ_USE_HASHTAB
- { }
- ~expairseq() { destroy(false); }
- expairseq(const expairseq & other);
- const expairseq & operator=(const expairseq & other);
-protected:
- void copy(const expairseq & other);
- void destroy(bool call_parent);
- // other ctors
+ // other constructors
public:
expairseq(const ex & lh, const ex & rh);
expairseq(const exvector & v);
// functions overriding virtual functions from base classes
public:
- basic * duplicate() const;
void print(const print_context & c, unsigned level = 0) const;
- unsigned precedence(void) const {return 10;}
+ unsigned precedence() const {return 10;}
bool info(unsigned inf) const;
- unsigned nops() const;
- ex op(int i) const;
- ex & let_op(int i);
+ size_t nops() const;
+ ex op(size_t i) const;
ex map(map_function & f) const;
ex eval(int level=0) const;
ex to_rational(lst &repl_lst) const;
+ ex to_polynomial(lst &repl_lst) const;
bool match(const ex & pattern, lst & repl_lst) const;
- ex subs(const lst & ls, const lst & lr, bool no_pattern = false) const;
+ ex subs(const lst & ls, const lst & lr, unsigned options = 0) const;
protected:
- int compare_same_type(const basic & other) const;
bool is_equal_same_type(const basic & other) const;
- unsigned return_type(void) const;
- unsigned calchash(void) const;
+ unsigned return_type() const;
+ unsigned calchash() const;
ex expand(unsigned options=0) const;
// new virtual functions which can be overridden by derived classes
const ex & c) const;
virtual ex recombine_pair_to_ex(const expair & p) const;
virtual bool expair_needs_further_processing(epp it);
- virtual ex default_overall_coeff(void) const;
+ virtual ex default_overall_coeff() const;
virtual void combine_overall_coeff(const ex & c);
virtual void combine_overall_coeff(const ex & c1, const ex & c2);
virtual bool can_make_flat(const expair & p) const;
void construct_from_epvector(const epvector & v);
void make_flat(const exvector & v);
void make_flat(const epvector & v);
- void canonicalize(void);
- void combine_same_terms_sorted_seq(void);
+ void canonicalize();
+ void combine_same_terms_sorted_seq();
#if EXPAIRSEQ_USE_HASHTAB
- void combine_same_terms(void);
+ void combine_same_terms();
unsigned calc_hashtabsize(unsigned sz) const;
unsigned calc_hashindex(const ex & e) const;
- void shrink_hashtab(void);
+ void shrink_hashtab();
void remove_hashtab_entry(epvector::const_iterator element);
void move_hashtab_entry(epvector::const_iterator oldpos,
epvector::iterator newpos);
epvector::iterator & last_non_zero,
vector<bool> & touched,
unsigned & number_of_zeroes);
- bool has_coeff_0(void) const;
+ bool has_coeff_0() const;
void add_numerics_to_hashtab(epvector::iterator first_numeric,
epvector::const_iterator last_non_zero);
#endif // EXPAIRSEQ_USE_HASHTAB
bool is_canonical() const;
epvector * expandchildren(unsigned options) const;
epvector * evalchildren(int level) const;
- epvector * subschildren(const lst & ls, const lst & lr, bool no_pattern = false) const;
+ epvector * subschildren(const lst & ls, const lst & lr, unsigned options = 0) const;
// member variables
-/** @file exprseq_suppl.cpp
+/** @file exprseq.cpp
*
- * Supplement to exprseq.cpp, contains the parts which were not automatically
- * generated. */
+ * Implementation of GiNaC's exprseq. */
/*
* GiNaC Copyright (C) 1999-2003 Johannes Gutenberg University Mainz, Germany
*/
#include "exprseq.h"
-#include "ex.h"
namespace GiNaC {
-bool exprseq::info(unsigned inf) const
-{
- if (inf==info_flags::exprseq)
- return 1;
- return basic::info(inf);
-}
+GINAC_IMPLEMENT_REGISTERED_CLASS(exprseq, basic)
-ex & exprseq::let_op(int i)
+/** Specialization of container::info() for exprseq. */
+bool exprseq::info(unsigned inf) const
{
- GINAC_ASSERT(i>=0);
- GINAC_ASSERT(i<nops());
-
- return seq[i];
+ if (inf == info_flags::exprseq)
+ return true;
+ else
+ return inherited::info(inf);
}
} // namespace GiNaC
--- /dev/null
+/** @file exprseq.h
+ *
+ * Definition of GiNaC's exprseq. */
+
+/*
+ * GiNaC Copyright (C) 1999-2003 Johannes Gutenberg University Mainz, Germany
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __GINAC_EXPRSEQ_H__
+#define __GINAC_EXPRSEQ_H__
+
+#include <vector>
+
+#include "container.h"
+
+namespace GiNaC {
+
+typedef container<std::vector> exprseq;
+
+/** Specialization of container::get_tinfo() for exprseq. */
+inline unsigned exprseq::get_tinfo() { return TINFO_exprseq; }
+
+// defined in exprseq.cpp
+template<> bool exprseq::info(unsigned inf) const;
+
+/** Specialization of is_exactly_a<exprseq>(obj) for exprseq objects. */
+template<> inline bool is_exactly_a<exprseq>(const basic & obj)
+{
+ return obj.tinfo() == TINFO_exprseq;
+}
+
+} // namespace GiNaC
+
+#endif // ndef __GINAC_EXPRSEQ_H__
GINAC_IMPLEMENT_REGISTERED_CLASS(fail, basic)
//////////
-// default ctor, dtor, copy ctor, assignment operator and helpers
+// default constructor
//////////
-DEFAULT_CTORS(fail)
+DEFAULT_CTOR(fail)
//////////
// archiving
public:
void print(const print_context & c, unsigned level = 0) const;
protected:
- unsigned return_type(void) const { return return_types::noncommutative_composite; };
+ unsigned return_type() const { return return_types::noncommutative_composite; };
};
/** Specialization of is_exactly_a<fail>(obj) for fail objects. */
#include <iostream>
#include "fderivative.h"
+#include "operators.h"
#include "print.h"
#include "archive.h"
#include "utils.h"
GINAC_IMPLEMENT_REGISTERED_CLASS(fderivative, function)
//////////
-// default ctor, dtor, copy ctor, assignment operator and helpers
+// default constructor
//////////
fderivative::fderivative()
tinfo_key = TINFO_fderivative;
}
-void fderivative::copy(const fderivative & other)
-{
- inherited::copy(other);
- parameter_set = other.parameter_set;
-}
-
-DEFAULT_DESTROY(fderivative)
-
//////////
// other constructors
//////////
// archiving
//////////
-fderivative::fderivative(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
+fderivative::fderivative(const archive_node &n, lst &sym_lst) : inherited(n, sym_lst)
{
unsigned i = 0;
while (true) {
c.s << *i++ << ",";
c.s << *i << std::endl;
unsigned delta_indent = static_cast<const print_tree &>(c).delta_indent;
- for (unsigned i=0; i<seq.size(); ++i)
+ for (size_t i=0; i<seq.size(); ++i)
seq[i].print(c, level + delta_indent);
c.s << std::string(level + delta_indent, ' ') << "=====" << std::endl;
return basic::series(r, order, options);
}
-ex fderivative::thisexprseq(const exvector & v) const
+ex fderivative::thiscontainer(const exvector & v) const
{
return fderivative(serial, parameter_set, v);
}
-ex fderivative::thisexprseq(exvector * vp) const
+ex fderivative::thiscontainer(exvector * vp) const
{
return fderivative(serial, parameter_set, vp);
}
ex fderivative::derivative(const symbol & s) const
{
ex result;
- for (unsigned i=0; i!=seq.size(); i++) {
+ for (size_t i=0; i<seq.size(); i++) {
ex arg_diff = seq[i].diff(s);
if (!arg_diff.is_zero()) {
paramset ps = parameter_set;
ex eval(int level = 0) const;
ex evalf(int level = 0) const;
ex series(const relational & r, int order, unsigned options = 0) const;
- ex thisexprseq(const exvector & v) const;
- ex thisexprseq(exvector * vp) const;
+ ex thiscontainer(const exvector & v) const;
+ ex thiscontainer(exvector * vp) const;
protected:
ex derivative(const symbol & s) const;
bool is_equal_same_type(const basic & other) const;
namespace GiNaC {
+/** Flags to control the behavior of expand(). */
class expand_options {
public:
enum {
};
};
+/** Flags to control the behavior of subs(). */
+class subs_options {
+public:
+ enum {
+ subs_no_pattern = 0x0001,
+ subs_algebraic = 0x0002
+ };
+};
+
/** Flags to control series expansion. */
class series_options {
public:
enum {
+ /** Suppress branch cuts in series expansion. Branch cuts manifest
+ * themselves as step functions, if this option is not passed. If
+ * it is passed and expansion at a point on a cut is performed, then
+ * the analytic continuation of the function is expanded. */
suppress_branchcut = 0x0001
};
};
class determinant_algo {
public:
enum {
- automatic, ///< Let the system choose
- gauss, ///< Gauss elimiation
- divfree, ///< Division-free elimination
- laplace, ///< Laplace (or minor) elimination
- bareiss ///< Bareiss fraction-free elimination
+ /** Let the system choose. A heuristics is applied for automatic
+ * determination of a suitable algorithm. */
+ automatic,
+ /** Gauss elimination. If \f$m_{i,j}^{(0)}\f$ are the entries of the
+ * original matrix, then the matrix is transformed into triangular
+ * form by applying the rules
+ * \f[
+ * m_{i,j}^{(k+1)} = m_{i,j}^{(k)} - m_{i,k}^{(k)} m_{k,j}^{(k)} / m_{k,k}^{(k)}
+ * \f]
+ * The determinant is then just the product of diagonal elements.
+ * Choose this algorithm only for purely numerical matrices. */
+ gauss,
+ /** Division-free elimination. This is a modification of Gauss
+ * elimination where the division by the pivot element is not
+ * carried out. If \f$m_{i,j}^{(0)}\f$ are the entries of the
+ * original matrix, then the matrix is transformed into triangular
+ * form by applying the rules
+ * \f[
+ * m_{i,j}^{(k+1)} = m_{i,j}^{(k)} m_{k,k}^{(k)} - m_{i,k}^{(k)} m_{k,j}^{(k)}
+ * \f]
+ * The determinant can later be computed by inspecting the diagonal
+ * elements only. This algorithm is only there for the purpose of
+ * cross-checks. It is never fast. */
+ divfree,
+ /** Laplace elimination. This is plain recursive elimination along
+ * minors although multiple minors are avoided by the algorithm.
+ * Although the algorithm is exponential in complexity it is
+ * frequently the fastest one when the matrix is populated by
+ * complicated symbolic expressions. */
+ laplace,
+ /** Bareiss fraction-free elimination. This is a modification of
+ * Gauss elimination where the division by the pivot element is
+ * <EM>delayed</EM> until it can be carried out without computing
+ * GCDs. If \f$m_{i,j}^{(0)}\f$ are the entries of the original
+ * matrix, then the matrix is transformed into triangular form by
+ * applying the rules
+ * \f[
+ * m_{i,j}^{(k+1)} = (m_{i,j}^{(k)} m_{k,k}^{(k)} - m_{i,k}^{(k)} m_{k,j}^{(k)}) / m_{k-1,k-1}^{(k-1)}
+ * \f]
+ * (We have set \f$m_{-1,-1}^{(-1)}=1\f$ in order to avoid a case
+ * distinction in above formula.) It can be shown that nothing more
+ * than polynomial long division is needed for carrying out the
+ * division. The determinant can then be read of from the lower
+ * right entry. This algorithm is rarely fast for computing
+ * determinants. */
+ bareiss
};
};
class solve_algo {
public:
enum {
- automatic, ///< Let the system choose
- gauss, ///< Gauss elimiation
- divfree, ///< Division-free elimination
- bareiss ///< Bareiss fraction-free elimination
+ /** Let the system choose. A heuristics is applied for automatic
+ * determination of a suitable algorithm. */
+ automatic,
+ /** Gauss elimination. If \f$m_{i,j}^{(0)}\f$ are the entries of the
+ * original matrix, then the matrix is transformed into triangular
+ * form by applying the rules
+ * \f[
+ * m_{i,j}^{(k+1)} = m_{i,j}^{(k)} - m_{i,k}^{(k)} m_{k,j}^{(k)} / m_{k,k}^{(k)}
+ * \f]
+ * This algorithm is well-suited for numerical matrices but generally
+ * suffers from the expensive division (and computation of GCDs) at
+ * each step. */
+ gauss,
+ /** Division-free elimination. This is a modification of Gauss
+ * elimination where the division by the pivot element is not
+ * carried out. If \f$m_{i,j}^{(0)}\f$ are the entries of the
+ * original matrix, then the matrix is transformed into triangular
+ * form by applying the rules
+ * \f[
+ * m_{i,j}^{(k+1)} = m_{i,j}^{(k)} m_{k,k}^{(k)} - m_{i,k}^{(k)} m_{k,j}^{(k)}
+ * \f]
+ * This algorithm is only there for the purpose of cross-checks.
+ * It suffers from exponential intermediate expression swell. Use it
+ * only for small systems. */
+ divfree,
+ /** Bareiss fraction-free elimination. This is a modification of
+ * Gauss elimination where the division by the pivot element is
+ * <EM>delayed</EM> until it can be carried out without computing
+ * GCDs. If \f$m_{i,j}^{(0)}\f$ are the entries of the original
+ * matrix, then the matrix is transformed into triangular form by
+ * applying the rules
+ * \f[
+ * m_{i,j}^{(k+1)} = (m_{i,j}^{(k)} m_{k,k}^{(k)} - m_{i,k}^{(k)} m_{k,j}^{(k)}) / m_{k-1,k-1}^{(k-1)}
+ * \f]
+ * (We have set \f$m_{-1,-1}^{(-1)}=1\f$ in order to avoid a case
+ * distinction in above formula.) It can be shown that nothing more
+ * than polynomial long division is needed for carrying out the
+ * division. This is generally the fastest algorithm for solving
+ * linear systems. In contrast to division-free elimination it only
+ * has a linear expression swell. For two-dimensional systems, the
+ * two algorithms are equivalent, however. */
+ bareiss
};
};
$declare_function_macro = generate(
<<'END_OF_DECLARE_FUNCTION_MACRO','typename T${N}','const T${N} & p${N}','GiNaC::ex(p${N})');
#define DECLARE_FUNCTION_${N}P(NAME) \\
-extern const unsigned function_index_##NAME; \\
-template<${SEQ1}> \\
-inline const GiNaC::function NAME(${SEQ2}) { \\
- return GiNaC::function(function_index_##NAME, ${SEQ3}); \\
+class NAME##_SERIAL { public: static unsigned serial; }; \\
+template<${SEQ1}> const GiNaC::function NAME(${SEQ2}) { \\
+ return GiNaC::function(NAME##_SERIAL::serial, ${SEQ3}); \\
}
END_OF_DECLARE_FUNCTION_MACRO
// end of generated lines
#define REGISTER_FUNCTION(NAME,OPT) \\
-const unsigned function_index_##NAME= \\
+unsigned NAME##_SERIAL::serial = \\
GiNaC::function::register_new(GiNaC::function_options(#NAME).OPT);
namespace GiNaC {
typedef ex (* derivative_funcp_exvector)(const exvector &, unsigned);
typedef ex (* series_funcp_exvector)(const exvector &, const relational &, int, unsigned);
+
class function_options
{
friend class function;
function_options();
function_options(std::string const & n, std::string const & tn=std::string());
~function_options();
- void initialize(void);
+ void initialize();
function_options & set_name(std::string const & n, std::string const & tn=std::string());
function_options & latex_name(std::string const & tn);
// the following lines have been generated for max. ${maxargs} parameters
function_options & series_func(series_funcp_exvector s);
function_options & set_return_type(unsigned rt, unsigned rtt=0);
- function_options & do_not_evalf_params(void);
+ function_options & do_not_evalf_params();
function_options & remember(unsigned size, unsigned assoc_size=0,
unsigned strategy=remember_strategies::delete_never);
function_options & overloaded(unsigned o);
function_options & set_symmetry(const symmetry & s);
void test_and_set_nparams(unsigned n);
- std::string get_name(void) const { return name; }
- unsigned get_nparams(void) const { return nparams; }
- bool has_derivative(void) const { return derivative_f != NULL; }
+ std::string get_name() const { return name; }
+ unsigned get_nparams() const { return nparams; }
+ bool has_derivative() const { return derivative_f != NULL; }
protected:
std::string name;
ex symtree;
};
+
+/** Exception class thrown by classes which provide their own series expansion
+ * to signal that ordinary Taylor expansion is safe. */
+class do_taylor {};
+
+
/** The class function is used to implement builtin functions like sin, cos...
and user defined functions */
class function : public exprseq
// CINT has a linking problem
#ifndef __MAKECINT__
- friend void ginsh_get_ginac_functions(void);
+ friend void ginsh_get_ginac_functions();
#endif // def __MAKECINT__
friend class remember_table_entry;
// member functions
- // other ctors
+ // other constructors
public:
function(unsigned ser);
// the following lines have been generated for max. ${maxargs} parameters
// functions overriding virtual functions from base classes
public:
void print(const print_context & c, unsigned level = 0) const;
- unsigned precedence(void) const {return 70;}
+ unsigned precedence() const {return 70;}
ex expand(unsigned options=0) const;
ex eval(int level=0) const;
ex evalf(int level=0) const;
- unsigned calchash(void) const;
+ unsigned calchash() const;
ex series(const relational & r, int order, unsigned options = 0) const;
- ex thisexprseq(const exvector & v) const;
- ex thisexprseq(exvector * vp) const;
+ ex thiscontainer(const exvector & v) const;
+ ex thiscontainer(exvector * vp) const;
protected:
ex derivative(const symbol & s) const;
bool is_equal_same_type(const basic & other) const;
bool match_same_type(const basic & other) const;
- unsigned return_type(void) const;
- unsigned return_type_tinfo(void) const;
+ unsigned return_type() const;
+ unsigned return_type_tinfo() const;
// new virtual functions which can be overridden by derived classes
// none
// non-virtual functions in this class
protected:
ex pderivative(unsigned diff_param) const; // partial differentiation
- static std::vector<function_options> & registered_functions(void);
+ static std::vector<function_options> & registered_functions();
bool lookup_remember_table(ex & result) const;
void store_remember_table(ex const & result) const;
public:
static unsigned register_new(function_options const & opt);
static unsigned current_serial;
static unsigned find_function(const std::string &name, unsigned nparams);
- unsigned get_serial(void) const {return serial;}
- std::string get_name(void) const;
+ unsigned get_serial() const {return serial;}
+ std::string get_name() const;
// member variables
return obj.tinfo()==TINFO_function;
}
-#define is_ex_the_function(OBJ, FUNCNAME) \\
- (GiNaC::is_exactly_a<GiNaC::function>(OBJ) && GiNaC::ex_to<GiNaC::function>(OBJ).get_serial() == function_index_##FUNCNAME)
+template <typename T>
+inline bool is_the_function(const ex & x)
+{
+ return is_exactly_a<function>(x)
+ && ex_to<function>(x).get_serial() == T::serial;
+}
+
+// Check whether OBJ is the specified symbolic function.
+#define is_ex_the_function(OBJ, FUNCNAME) (GiNaC::is_the_function<FUNCNAME##_SERIAL>(OBJ))
} // namespace GiNaC
#include <list>
#include "function.h"
+#include "operators.h"
#include "fderivative.h"
#include "ex.h"
#include "lst.h"
// nothing to clean up at the moment
}
-void function_options::initialize(void)
+void function_options::initialize()
{
set_name("unnamed_function","\\\\mbox{unnamed}");
nparams = 0;
return *this;
}
-function_options & function_options::do_not_evalf_params(void)
+function_options & function_options::do_not_evalf_params()
{
evalf_params_first = false;
return *this;
// we do not throw an exception here because this code is
// usually executed before main(), so the exception could not
// caught anyhow
- std::cerr << "WARNING: number of parameters ("
+ std::cerr << "WARNING: " << name << "(): number of parameters ("
<< n << ") differs from number set before ("
<< nparams << ")" << std::endl;
}
GINAC_IMPLEMENT_REGISTERED_CLASS(function, exprseq)
//////////
-// default ctor, dtor, copy ctor, assignment operator and helpers
+// default constructor
//////////
// public
tinfo_key = TINFO_function;
}
-// protected
-
-void function::copy(const function & other)
-{
- inherited::copy(other);
- serial = other.serial;
-}
-
-void function::destroy(bool call_parent)
-{
- if (call_parent)
- inherited::destroy(call_parent);
-}
-
//////////
-// other ctors
+// other constructors
//////////
// public
//////////
/** Construct object from archive_node. */
-function::function(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
+function::function(const archive_node &n, lst &sym_lst) : inherited(n, sym_lst)
{
// Find serial number by function name
std::string s;
}
/** Unarchive the object. */
-ex function::unarchive(const archive_node &n, const lst &sym_lst)
+ex function::unarchive(const archive_node &n, lst &sym_lst)
{
return (new function(n, sym_lst))->setflag(status_flags::dynallocated);
}
{
GINAC_ASSERT(serial<registered_functions().size());
- if (is_of_type(c, print_tree)) {
+ if (is_a<print_tree>(c)) {
c.s << std::string(level, ' ') << class_name() << " "
<< registered_functions()[serial].name
<< ", nops=" << nops()
<< std::endl;
unsigned delta_indent = static_cast<const print_tree &>(c).delta_indent;
- for (unsigned i=0; i<seq.size(); ++i)
+ for (size_t i=0; i<seq.size(); ++i)
seq[i].print(c, level + delta_indent);
c.s << std::string(level + delta_indent, ' ') << "=====" << std::endl;
- } else if (is_of_type(c, print_csrc)) {
+ } else if (is_a<print_csrc>(c)) {
// Print function name in lowercase
std::string lname = registered_functions()[serial].name;
- unsigned num = lname.size();
- for (unsigned i=0; i<num; i++)
+ size_t num = lname.size();
+ for (size_t i=0; i<num; i++)
lname[i] = tolower(lname[i]);
c.s << lname << "(";
}
c.s << ")";
- } else if (is_of_type(c, print_latex)) {
+ } else if (is_a<print_latex>(c)) {
c.s << registered_functions()[serial].TeX_name;
printseq(c, '(', ',', ')', exprseq::precedence(), function::precedence());
} else {
// Something has changed while sorting arguments, more evaluations later
if (sig == 0)
return _ex0;
- return ex(sig) * thisexprseq(v);
+ return ex(sig) * thiscontainer(v);
}
}
throw(std::logic_error("function::evalf(): invalid nparams"));
}
-unsigned function::calchash(void) const
+unsigned function::calchash() const
{
unsigned v = golden_ratio_hash(golden_ratio_hash(tinfo()) ^ serial);
- for (unsigned i=0; i<nops(); i++) {
- v = rotate_left_31(v);
+ for (size_t i=0; i<nops(); i++) {
+ v = rotate_left(v);
v ^= this->op(i).gethash();
}
- v &= 0x7FFFFFFFU;
+
if (flags & status_flags::evaluated) {
setflag(status_flags::hash_calculated);
hashvalue = v;
return v;
}
-ex function::thisexprseq(const exvector & v) const
+ex function::thiscontainer(const exvector & v) const
{
return function(serial,v);
}
-ex function::thisexprseq(exvector * vp) const
+ex function::thiscontainer(exvector * vp) const
{
return function(serial,vp);
}
{
ex result;
- if (serial == function_index_Order) {
+ if (serial == Order_SERIAL::serial) {
// Order Term function only differentiates the argument
return Order(seq[0].diff(s));
} else {
// Chain rule
ex arg_diff;
- unsigned num = seq.size();
- for (unsigned i=0; i<num; i++) {
+ size_t num = seq.size();
+ for (size_t i=0; i<num; i++) {
arg_diff = seq[i].diff(s);
// We apply the chain rule only when it makes sense. This is not
// just for performance reasons but also to allow functions to
int function::compare_same_type(const basic & other) const
{
- GINAC_ASSERT(is_of_type(other, function));
+ GINAC_ASSERT(is_a<function>(other));
const function & o = static_cast<const function &>(other);
if (serial != o.serial)
bool function::is_equal_same_type(const basic & other) const
{
- GINAC_ASSERT(is_of_type(other, function));
+ GINAC_ASSERT(is_a<function>(other));
const function & o = static_cast<const function &>(other);
if (serial != o.serial)
bool function::match_same_type(const basic & other) const
{
- GINAC_ASSERT(is_of_type(other, function));
+ GINAC_ASSERT(is_a<function>(other));
const function & o = static_cast<const function &>(other);
return serial == o.serial;
}
-unsigned function::return_type(void) const
+unsigned function::return_type() const
{
const function_options &opt = registered_functions()[serial];
}
}
-unsigned function::return_type_tinfo(void) const
+unsigned function::return_type_tinfo() const
{
const function_options &opt = registered_functions()[serial];
throw(std::logic_error("function::pderivative(): no diff function defined"));
}
-std::vector<function_options> & function::registered_functions(void)
+std::vector<function_options> & function::registered_functions()
{
static std::vector<function_options> * rf = new std::vector<function_options>;
return *rf;
unsigned function::register_new(function_options const & opt)
{
- unsigned same_name = 0;
- for (unsigned i=0; i<registered_functions().size(); ++i) {
+ size_t same_name = 0;
+ for (size_t i=0; i<registered_functions().size(); ++i) {
if (registered_functions()[i].name==opt.name) {
++same_name;
}
}
/** Return the print name of the function. */
-std::string function::get_name(void) const
+std::string function::get_name() const
{
GINAC_ASSERT(serial<registered_functions().size());
return registered_functions()[serial].name;
#include "symbol.h"
#include "lst.h"
#include "relational.h"
+#include "operators.h"
#include "print.h"
#include "archive.h"
#include "utils.h"
GINAC_IMPLEMENT_REGISTERED_CLASS(spinidx, varidx)
//////////
-// default ctor, dtor, copy ctor, assignment operator and helpers
+// default constructor
//////////
idx::idx() : inherited(TINFO_idx) {}
tinfo_key = TINFO_spinidx;
}
-void idx::copy(const idx & other)
-{
- inherited::copy(other);
- value = other.value;
- dim = other.dim;
-}
-
-void varidx::copy(const varidx & other)
-{
- inherited::copy(other);
- covariant = other.covariant;
-}
-
-void spinidx::copy(const spinidx & other)
-{
- inherited::copy(other);
- dotted = other.dotted;
-}
-
-DEFAULT_DESTROY(idx)
-DEFAULT_DESTROY(varidx)
-DEFAULT_DESTROY(spinidx)
-
//////////
// other constructors
//////////
// archiving
//////////
-idx::idx(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
+idx::idx(const archive_node &n, lst &sym_lst) : inherited(n, sym_lst)
{
n.find_ex("value", value, sym_lst);
n.find_ex("dim", dim, sym_lst);
}
-varidx::varidx(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
+varidx::varidx(const archive_node &n, lst &sym_lst) : inherited(n, sym_lst)
{
n.find_bool("covariant", covariant);
}
-spinidx::spinidx(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
+spinidx::spinidx(const archive_node &n, lst &sym_lst) : inherited(n, sym_lst)
{
n.find_bool("dotted", dotted);
}
void idx::print(const print_context & c, unsigned level) const
{
- if (is_of_type(c, print_tree)) {
+ if (is_a<print_tree>(c)) {
c.s << std::string(level, ' ') << class_name()
<< std::hex << ", hash=0x" << hashvalue << ", flags=0x" << flags << std::dec
value.print(c);
if (need_parens)
c.s << ")";
+ if (c.options & print_options::print_index_dimensions) {
+ c.s << "[";
+ dim.print(c);
+ c.s << "]";
+ }
if (is_a<print_latex>(c))
c.s << "}";
}
void varidx::print(const print_context & c, unsigned level) const
{
- if (is_of_type(c, print_tree)) {
+ if (is_a<print_tree>(c)) {
c.s << std::string(level, ' ') << class_name()
<< std::hex << ", hash=0x" << hashvalue << ", flags=0x" << flags << std::dec
value.print(c);
if (need_parens)
c.s << ")";
+ if (c.options & print_options::print_index_dimensions) {
+ c.s << "[";
+ dim.print(c);
+ c.s << "]";
+ }
if (is_a<print_latex>(c))
c.s << "}";
}
void spinidx::print(const print_context & c, unsigned level) const
{
- if (is_of_type(c, print_tree)) {
+ if (is_a<print_tree>(c)) {
c.s << std::string(level, ' ') << class_name()
<< std::hex << ", hash=0x" << hashvalue << ", flags=0x" << flags << std::dec
} else {
- bool is_tex = is_of_type(c, print_latex);
+ bool is_tex = is_a<print_latex>(c);
if (is_tex) {
if (covariant)
c.s << "_{";
return inherited::info(inf);
}
-unsigned idx::nops() const
+size_t idx::nops() const
{
// don't count the dimension as that is not really a sub-expression
return 1;
}
-ex & idx::let_op(int i)
+ex idx::op(size_t i) const
{
GINAC_ASSERT(i == 0);
return value;
}
+ex idx::map(map_function & f) const
+{
+ idx *copy = duplicate();
+ copy->setflag(status_flags::dynallocated);
+ copy->clearflag(status_flags::hash_calculated);
+ copy->value = f(value);
+ return *copy;
+}
+
/** Returns order relation between two indices of the same type. The order
* must be such that dummy indices lie next to each other. */
int idx::compare_same_type(const basic & other) const
// Check variance last so dummy indices will end up next to each other
if (covariant != o.covariant)
return covariant ? -1 : 1;
+
return 0;
}
if (covariant != o.covariant)
return false;
+
return inherited::match_same_type(other);
}
return *this;
}
-ex idx::subs(const lst & ls, const lst & lr, bool no_pattern) const
+ex idx::subs(const lst & ls, const lst & lr, unsigned options) const
{
GINAC_ASSERT(ls.nops() == lr.nops());
// First look for index substitutions
- for (unsigned i=0; i<ls.nops(); i++) {
- if (is_equal(ex_to<basic>(ls.op(i)))) {
+ lst::const_iterator its, itr;
+ for (its = ls.begin(), itr = lr.begin(); its != ls.end(); ++its, ++itr) {
+ if (is_equal(ex_to<basic>(*its))) {
// Substitution index->index
- if (is_a<idx>(lr.op(i)))
- return lr.op(i);
+ if (is_a<idx>(*itr))
+ return *itr;
// Otherwise substitute value
- idx *i_copy = static_cast<idx *>(duplicate());
- i_copy->value = lr.op(i);
+ idx *i_copy = duplicate();
+ i_copy->value = *itr;
i_copy->clearflag(status_flags::hash_calculated);
return i_copy->setflag(status_flags::dynallocated);
}
}
// None, substitute objects in value (not in dimension)
- const ex &subsed_value = value.subs(ls, lr, no_pattern);
+ const ex &subsed_value = value.subs(ls, lr, options);
if (are_ex_trivially_equal(value, subsed_value))
return *this;
- idx *i_copy = static_cast<idx *>(duplicate());
+ idx *i_copy = duplicate();
i_copy->value = subsed_value;
i_copy->clearflag(status_flags::hash_calculated);
return i_copy->setflag(status_flags::dynallocated);
{
const idx &o = static_cast<const idx &>(other);
- // Only pure symbols form dummy pairs, numeric indices and expressions
- // like "2n+1" don't
+ // Only pure symbols form dummy pairs, "2n+1" doesn't
if (!is_a<symbol>(value))
return false;
ex idx::replace_dim(const ex & new_dim) const
{
- idx *i_copy = static_cast<idx *>(duplicate());
+ idx *i_copy = duplicate();
i_copy->dim = new_dim;
i_copy->clearflag(status_flags::hash_calculated);
return i_copy->setflag(status_flags::dynallocated);
return GiNaC::minimal_dim(dim, other.dim);
}
-ex varidx::toggle_variance(void) const
+ex varidx::toggle_variance() const
{
- varidx *i_copy = static_cast<varidx *>(duplicate());
+ varidx *i_copy = duplicate();
i_copy->covariant = !i_copy->covariant;
i_copy->clearflag(status_flags::hash_calculated);
return i_copy->setflag(status_flags::dynallocated);
}
-ex spinidx::toggle_dot(void) const
+ex spinidx::toggle_dot() const
{
- spinidx *i_copy = static_cast<spinidx *>(duplicate());
+ spinidx *i_copy = duplicate();
i_copy->dotted = !i_copy->dotted;
i_copy->clearflag(status_flags::hash_calculated);
return i_copy->setflag(status_flags::dynallocated);
}
-ex spinidx::toggle_variance_dot(void) const
+ex spinidx::toggle_variance_dot() const
{
- spinidx *i_copy = static_cast<spinidx *>(duplicate());
+ spinidx *i_copy = duplicate();
i_copy->covariant = !i_copy->covariant;
i_copy->dotted = !i_copy->dotted;
i_copy->clearflag(status_flags::hash_calculated);
public:
void print(const print_context & c, unsigned level = 0) const;
bool info(unsigned inf) const;
- unsigned nops() const;
- ex & let_op(int i);
+ size_t nops() const;
+ ex op(size_t i) const;
+ ex map(map_function & f) const;
ex evalf(int level = 0) const;
- ex subs(const lst & ls, const lst & lr, bool no_pattern = false) const;
+ ex subs(const lst & ls, const lst & lr, unsigned options = 0) const;
protected:
ex derivative(const symbol & s) const;
// non-virtual functions in this class
public:
/** Get value of index. */
- ex get_value(void) const {return value;}
+ ex get_value() const {return value;}
/** Check whether the index is numeric. */
- bool is_numeric(void) const {return is_exactly_a<numeric>(value);}
+ bool is_numeric() const {return is_exactly_a<numeric>(value);}
/** Check whether the index is symbolic. */
- bool is_symbolic(void) const {return !is_exactly_a<numeric>(value);}
+ bool is_symbolic() const {return !is_exactly_a<numeric>(value);}
/** Get dimension of index space. */
- ex get_dim(void) const {return dim;}
+ ex get_dim() const {return dim;}
/** Check whether the dimension is numeric. */
- bool is_dim_numeric(void) const {return is_exactly_a<numeric>(dim);}
+ bool is_dim_numeric() const {return is_exactly_a<numeric>(dim);}
/** Check whether the dimension is symbolic. */
- bool is_dim_symbolic(void) const {return !is_exactly_a<numeric>(dim);}
+ bool is_dim_symbolic() const {return !is_exactly_a<numeric>(dim);}
/** Make a new index with the same value but a different dimension. */
ex replace_dim(const ex & new_dim) const;
// non-virtual functions in this class
public:
/** Check whether the index is covariant. */
- bool is_covariant(void) const {return covariant;}
+ bool is_covariant() const {return covariant;}
/** Check whether the index is contravariant (not covariant). */
- bool is_contravariant(void) const {return !covariant;}
+ bool is_contravariant() const {return !covariant;}
/** Make a new index with the same value but the opposite variance. */
- ex toggle_variance(void) const;
+ ex toggle_variance() const;
// member variables
protected:
// non-virtual functions in this class
public:
/** Check whether the index is dotted. */
- bool is_dotted(void) const {return dotted;}
+ bool is_dotted() const {return dotted;}
/** Check whether the index is not dotted. */
- bool is_undotted(void) const {return !dotted;}
+ bool is_undotted() const {return !dotted;}
/** Make a new index with the same value and variance but the opposite
* dottedness. */
- ex toggle_dot(void) const;
+ ex toggle_dot() const;
/** Make a new index with the same value but opposite variance and
* dottedness. */
- ex toggle_variance_dot(void) const;
+ ex toggle_variance_dot() const;
// member variables
protected:
}
/** Count the number of dummy index pairs in an index vector. */
-inline unsigned count_dummy_indices(const exvector & v)
+inline size_t count_dummy_indices(const exvector & v)
{
exvector free_indices, dummy_indices;
find_free_and_dummy(v.begin(), v.end(), free_indices, dummy_indices);
}
/** Count the number of dummy index pairs in an index vector. */
-inline unsigned count_free_indices(const exvector & v)
+inline size_t count_free_indices(const exvector & v)
{
exvector free_indices, dummy_indices;
find_free_and_dummy(v.begin(), v.end(), free_indices, dummy_indices);
#include "power.h"
#include "relational.h"
#include "symmetry.h"
+#include "operators.h"
#include "lst.h"
#include "print.h"
#include "archive.h"
GINAC_IMPLEMENT_REGISTERED_CLASS(indexed, exprseq)
//////////
-// default ctor, dtor, copy ctor, assignment operator and helpers
+// default constructor
//////////
indexed::indexed() : symtree(sy_none())
tinfo_key = TINFO_indexed;
}
-void indexed::copy(const indexed & other)
-{
- inherited::copy(other);
- symtree = other.symtree;
-}
-
-DEFAULT_DESTROY(indexed)
-
//////////
// other constructors
//////////
// archiving
//////////
-indexed::indexed(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
+indexed::indexed(const archive_node &n, lst &sym_lst) : inherited(n, sym_lst)
{
if (!n.find_ex("symmetry", symtree, sym_lst)) {
// GiNaC versions <= 0.9.0 had an unsigned "symmetry" property
return _ex0;
// If the base object is a product, pull out the numeric factor
- if (is_ex_exactly_of_type(base, mul) && is_ex_exactly_of_type(base.op(base.nops() - 1), numeric)) {
+ if (is_exactly_a<mul>(base) && is_exactly_a<numeric>(base.op(base.nops() - 1))) {
exvector v(seq);
ex f = ex_to<numeric>(base.op(base.nops() - 1));
v[0] = seq[0] / f;
- return f * thisexprseq(v);
+ return f * thiscontainer(v);
}
// Canonicalize indices according to the symmetry properties
// Something has changed while sorting indices, more evaluations later
if (sig == 0)
return _ex0;
- return ex(sig) * thisexprseq(v);
+ return ex(sig) * thiscontainer(v);
}
}
return ex_to<basic>(base).eval_indexed(*this);
}
-ex indexed::thisexprseq(const exvector & v) const
+ex indexed::thiscontainer(const exvector & v) const
{
return indexed(ex_to<symmetry>(symtree), v);
}
-ex indexed::thisexprseq(exvector * vp) const
+ex indexed::thiscontainer(exvector * vp) const
{
return indexed(ex_to<symmetry>(symtree), vp);
}
{
GINAC_ASSERT(seq.size() > 0);
- if ((options & expand_options::expand_indexed) && is_ex_exactly_of_type(seq[0], add)) {
+ if ((options & expand_options::expand_indexed) && is_exactly_a<add>(seq[0])) {
// expand_indexed expands (a+b).i -> a.i + b.i
const ex & base = seq[0];
ex sum = _ex0;
- for (unsigned i=0; i<base.nops(); i++) {
+ for (size_t i=0; i<base.nops(); i++) {
exvector s = seq;
s[0] = base.op(i);
- sum += thisexprseq(s).expand();
+ sum += thiscontainer(s).expand();
}
return sum;
bool covariant = true;
while (it != itend) {
- bool cur_covariant = (is_ex_of_type(*it, varidx) ? ex_to<varidx>(*it).is_covariant() : true);
+ bool cur_covariant = (is_a<varidx>(*it) ? ex_to<varidx>(*it).is_covariant() : true);
if (first || cur_covariant != covariant) { // Variance changed
// The empty {} prevents indices from ending up on top of each other
if (!first)
/** Check whether all indices are of class idx and validate the symmetry
* tree. This function is used internally to make sure that all constructed
* indexed objects really carry indices and not some other classes. */
-void indexed::validate(void) const
+void indexed::validate() const
{
GINAC_ASSERT(seq.size() > 0);
exvector::const_iterator it = seq.begin() + 1, itend = seq.end();
while (it != itend) {
- if (!is_ex_of_type(*it, idx))
+ if (!is_a<idx>(*it))
throw(std::invalid_argument("indices of indexed object must be of type idx"));
it++;
}
if (!symtree.is_zero()) {
- if (!is_ex_exactly_of_type(symtree, symmetry))
+ if (!is_exactly_a<symmetry>(symtree))
throw(std::invalid_argument("symmetry of indexed object must be of type symmetry"));
const_cast<symmetry &>(ex_to<symmetry>(symtree)).validate(seq.size() - 1);
}
return equal(v1.begin(), v1.end(), v2.begin(), idx_is_equal_ignore_dim());
}
-exvector indexed::get_indices(void) const
+exvector indexed::get_indices() const
{
GINAC_ASSERT(seq.size() >= 1);
return exvector(seq.begin() + 1, seq.end());
}
-exvector indexed::get_dummy_indices(void) const
+exvector indexed::get_dummy_indices() const
{
exvector free_indices, dummy_indices;
find_free_and_dummy(seq.begin() + 1, seq.end(), free_indices, dummy_indices);
return false;
}
-exvector indexed::get_free_indices(void) const
+exvector indexed::get_free_indices() const
{
exvector free_indices, dummy_indices;
find_free_and_dummy(seq.begin() + 1, seq.end(), free_indices, dummy_indices);
return free_indices;
}
-exvector add::get_free_indices(void) const
+exvector add::get_free_indices() const
{
exvector free_indices;
- for (unsigned i=0; i<nops(); i++) {
+ for (size_t i=0; i<nops(); i++) {
if (i == 0)
free_indices = op(i).get_free_indices();
else {
return free_indices;
}
-exvector mul::get_free_indices(void) const
+exvector mul::get_free_indices() const
{
// Concatenate free indices of all factors
exvector un;
- for (unsigned i=0; i<nops(); i++) {
+ for (size_t i=0; i<nops(); i++) {
exvector free_indices_of_factor = op(i).get_free_indices();
un.insert(un.end(), free_indices_of_factor.begin(), free_indices_of_factor.end());
}
return free_indices;
}
-exvector ncmul::get_free_indices(void) const
+exvector ncmul::get_free_indices() const
{
// Concatenate free indices of all factors
exvector un;
- for (unsigned i=0; i<nops(); i++) {
+ for (size_t i=0; i<nops(); i++) {
exvector free_indices_of_factor = op(i).get_free_indices();
un.insert(un.end(), free_indices_of_factor.begin(), free_indices_of_factor.end());
}
return free_indices;
}
-exvector power::get_free_indices(void) const
+exvector power::get_free_indices() const
{
// Return free indices of basis
return basis.get_free_indices();
* by the function */
static ex rename_dummy_indices(const ex & e, exvector & global_dummy_indices, exvector & local_dummy_indices)
{
- unsigned global_size = global_dummy_indices.size(),
- local_size = local_dummy_indices.size();
+ size_t global_size = global_dummy_indices.size(),
+ local_size = local_dummy_indices.size();
// Any local dummy indices at all?
if (local_size == 0)
// More local indices than we encountered before, add the new ones
// to the global set
- int old_global_size = global_size;
+ size_t old_global_size = global_size;
int remaining = local_size - global_size;
exvector::const_iterator it = local_dummy_indices.begin(), itend = local_dummy_indices.end();
while (it != itend && remaining > 0) {
}
GINAC_ASSERT(local_size <= global_size);
- // Construct lists of index symbols
- exlist local_syms, global_syms;
- for (unsigned i=0; i<local_size; i++)
+ // Construct vectors of index symbols
+ exvector local_syms, global_syms;
+ local_syms.reserve(local_size);
+ global_syms.reserve(local_size);
+ for (size_t i=0; i<local_size; i++)
local_syms.push_back(local_dummy_indices[i].op(0));
shaker_sort(local_syms.begin(), local_syms.end(), ex_is_less(), ex_swap());
- for (unsigned i=0; i<local_size; i++) // don't use more global symbols than necessary
+ for (size_t i=0; i<local_size; i++) // don't use more global symbols than necessary
global_syms.push_back(global_dummy_indices[i].op(0));
shaker_sort(global_syms.begin(), global_syms.end(), ex_is_less(), ex_swap());
// Remove common indices
- exlist local_uniq, global_uniq;
- set_difference(local_syms.begin(), local_syms.end(), global_syms.begin(), global_syms.end(), std::back_insert_iterator<exlist>(local_uniq), ex_is_less());
- set_difference(global_syms.begin(), global_syms.end(), local_syms.begin(), local_syms.end(), std::back_insert_iterator<exlist>(global_uniq), ex_is_less());
+ exvector local_uniq, global_uniq;
+ set_difference(local_syms.begin(), local_syms.end(), global_syms.begin(), global_syms.end(), std::back_insert_iterator<exvector>(local_uniq), ex_is_less());
+ set_difference(global_syms.begin(), global_syms.end(), local_syms.begin(), local_syms.end(), std::back_insert_iterator<exvector>(global_uniq), ex_is_less());
// Replace remaining non-common local index symbols by global ones
if (local_uniq.empty())
else {
while (global_uniq.size() > local_uniq.size())
global_uniq.pop_back();
- return e.subs(lst(local_uniq), lst(global_uniq));
+ return e.subs(lst(local_uniq.begin(), local_uniq.end()), lst(global_uniq.begin(), global_uniq.end()));
}
}
{
// Remember whether the product was commutative or noncommutative
// (because we chop it into factors and need to reassemble later)
- bool non_commutative = is_ex_exactly_of_type(e, ncmul);
+ bool non_commutative = is_exactly_a<ncmul>(e);
// Collect factors in an exvector, store squares twice
exvector v;
v.reserve(e.nops() * 2);
- if (is_ex_exactly_of_type(e, power)) {
+ if (is_exactly_a<power>(e)) {
// We only get called for simple squares, split a^2 -> a*a
GINAC_ASSERT(e.op(1).is_equal(_ex2));
v.push_back(e.op(0));
v.push_back(e.op(0));
} else {
- for (unsigned i=0; i<e.nops(); i++) {
+ for (size_t i=0; i<e.nops(); i++) {
ex f = e.op(i);
- if (is_ex_exactly_of_type(f, power) && f.op(1).is_equal(_ex2)) {
+ if (is_exactly_a<power>(f) && f.op(1).is_equal(_ex2)) {
v.push_back(f.op(0));
v.push_back(f.op(0));
- } else if (is_ex_exactly_of_type(f, ncmul)) {
+ } else if (is_exactly_a<ncmul>(f)) {
// Noncommutative factor found, split it as well
non_commutative = true; // everything becomes noncommutative, ncmul will sort out the commutative factors later
- for (unsigned j=0; j<f.nops(); j++)
+ for (size_t j=0; j<f.nops(); j++)
v.push_back(f.op(j));
} else
v.push_back(f);
for (it1 = v.begin(); it1 != next_to_last; it1++) {
try_again:
- if (!is_ex_of_type(*it1, indexed))
+ if (!is_a<indexed>(*it1))
continue;
bool first_noncommutative = (it1->return_type() != return_types::commutative);
exvector::iterator it2;
for (it2 = it1 + 1; it2 != itend; it2++) {
- if (!is_ex_of_type(*it2, indexed))
+ if (!is_a<indexed>(*it2))
continue;
bool second_noncommutative = (it2->return_type() != return_types::commutative);
// Check whether the two factors share dummy indices
exvector free, dummy;
find_free_and_dummy(un, free, dummy);
- unsigned num_dummies = dummy.size();
+ size_t num_dummies = dummy.size();
if (num_dummies == 0)
continue;
// At least one dummy index, is it a defined scalar product?
bool contracted = false;
if (free.empty()) {
- if (sp.is_defined(*it1, *it2)) {
- *it1 = sp.evaluate(*it1, *it2);
+
+ // Find minimal dimension of all indices of both factors
+ exvector::const_iterator dit = ex_to<indexed>(*it1).seq.begin() + 1, ditend = ex_to<indexed>(*it1).seq.end();
+ ex dim = ex_to<idx>(*dit).get_dim();
+ ++dit;
+ for (; dit != ditend; ++dit) {
+ dim = minimal_dim(dim, ex_to<idx>(*dit).get_dim());
+ }
+ dit = ex_to<indexed>(*it2).seq.begin() + 1;
+ ditend = ex_to<indexed>(*it2).seq.end();
+ for (; dit != ditend; ++dit) {
+ dim = minimal_dim(dim, ex_to<idx>(*dit).get_dim());
+ }
+
+ // User-defined scalar product?
+ if (sp.is_defined(*it1, *it2, dim)) {
+
+ // Yes, substitute it
+ *it1 = sp.evaluate(*it1, *it2, dim);
*it2 = _ex1;
goto contraction_done;
}
if (contracted) {
contraction_done:
if (first_noncommutative || second_noncommutative
- || is_ex_exactly_of_type(*it1, add) || is_ex_exactly_of_type(*it2, add)
- || is_ex_exactly_of_type(*it1, mul) || is_ex_exactly_of_type(*it2, mul)
- || is_ex_exactly_of_type(*it1, ncmul) || is_ex_exactly_of_type(*it2, ncmul)) {
+ || is_exactly_a<add>(*it1) || is_exactly_a<add>(*it2)
+ || is_exactly_a<mul>(*it1) || is_exactly_a<mul>(*it2)
+ || is_exactly_a<ncmul>(*it1) || is_exactly_a<ncmul>(*it2)) {
// One of the factors became a sum or product:
// re-expand expression and run again
// Non-commutative products are always re-expanded to give
- // simplify_ncmul() the chance to re-order and canonicalize
+ // eval_ncmul() the chance to re-order and canonicalize
// the product
ex r = (non_commutative ? ex(ncmul(v, true)) : ex(mul(v)));
return simplify_indexed(r, free_indices, dummy_indices, sp);
exvector un, individual_dummy_indices;
for (it1 = v.begin(), itend = v.end(); it1 != itend; ++it1) {
exvector free_indices_of_factor;
- if (is_ex_of_type(*it1, indexed)) {
+ if (is_a<indexed>(*it1)) {
exvector dummy_indices_of_factor;
find_free_and_dummy(ex_to<indexed>(*it1).seq.begin() + 1, ex_to<indexed>(*it1).seq.end(), free_indices_of_factor, dummy_indices_of_factor);
individual_dummy_indices.insert(individual_dummy_indices.end(), dummy_indices_of_factor.begin(), dummy_indices_of_factor.end());
// Iterate over all indexed objects in the product
for (it1 = v.begin(), itend = v.end(); it1 != itend; ++it1) {
- if (!is_ex_of_type(*it1, indexed))
+ if (!is_a<indexed>(*it1))
continue;
if (reposition_dummy_indices(*it1, variant_dummy_indices, moved_indices))
// indices, so if the symmetrization vanishes, the whole expression is
// zero. This detects things like eps.i.j.k * p.j * p.k = 0.
if (local_dummy_indices.size() >= 2) {
- lst dummy_syms;
- for (exvector::size_type i=0; i<local_dummy_indices.size(); i++)
- dummy_syms.append(local_dummy_indices[i].op(0));
- if (r.symmetrize(dummy_syms).is_zero()) {
+ exvector dummy_syms;
+ dummy_syms.reserve(local_dummy_indices.size());
+ for (exvector::const_iterator it = local_dummy_indices.begin(); it != local_dummy_indices.end(); ++it)
+ dummy_syms.push_back(it->op(0));
+ if (symmetrize(r, dummy_syms).is_zero()) {
free_indices.clear();
return _ex0;
}
r = rename_dummy_indices(r, dummy_indices, local_dummy_indices);
// Product of indexed object with a scalar?
- if (is_ex_exactly_of_type(r, mul) && r.nops() == 2
- && is_ex_exactly_of_type(r.op(1), numeric) && is_ex_of_type(r.op(0), indexed))
+ if (is_exactly_a<mul>(r) && r.nops() == 2
+ && is_exactly_a<numeric>(r.op(1)) && is_a<indexed>(r.op(0)))
return ex_to<basic>(r.op(0).op(0)).scalar_mul_indexed(r.op(0), ex_to<numeric>(r.op(1)));
else
return r;
public:
symminfo() : num(0) {}
- symminfo(const ex & symmterm_, const ex & orig_, unsigned num_) : orig(orig_), num(num_)
+ symminfo(const ex & symmterm_, const ex & orig_, size_t num_) : orig(orig_), num(num_)
{
if (is_exactly_a<mul>(symmterm_) && is_exactly_a<numeric>(symmterm_.op(symmterm_.nops()-1))) {
coeff = symmterm_.op(symmterm_.nops()-1);
ex symmterm; /**< symmetrized term */
ex coeff; /**< coefficient of symmetrized term */
ex orig; /**< original term */
- unsigned num; /**< how many symmetrized terms resulted from the original term */
+ size_t num; /**< how many symmetrized terms resulted from the original term */
};
class symminfo_is_less_by_symmterm {
// Simplification of single indexed object: just find the free indices
// and perform dummy index renaming/repositioning
- if (is_ex_of_type(e_expanded, indexed)) {
+ if (is_a<indexed>(e_expanded)) {
// Find the dummy indices
const indexed &i = ex_to<indexed>(e_expanded);
// Simplification of sum = sum of simplifications, check consistency of
// free indices in each term
- if (is_ex_exactly_of_type(e_expanded, add)) {
+ if (is_exactly_a<add>(e_expanded)) {
bool first = true;
ex sum;
free_indices.clear();
- for (unsigned i=0; i<e_expanded.nops(); i++) {
+ for (size_t i=0; i<e_expanded.nops(); i++) {
exvector free_indices_of_term;
ex term = simplify_indexed(e_expanded.op(i), free_indices_of_term, dummy_indices, sp);
if (!term.is_zero()) {
s << exprseq(free_indices) << " vs. " << exprseq(free_indices_of_term);
throw (std::runtime_error(s.str()));
}
- if (is_ex_of_type(sum, indexed) && is_ex_of_type(term, indexed))
+ if (is_a<indexed>(sum) && is_a<indexed>(term))
sum = ex_to<basic>(sum.op(0)).add_indexed(sum, term);
else
sum += term;
}
// More than one term and more than one dummy index?
- int num_terms_orig = (is_exactly_a<add>(sum) ? sum.nops() : 1);
+ size_t num_terms_orig = (is_exactly_a<add>(sum) ? sum.nops() : 1);
if (num_terms_orig < 2 || dummy_indices.size() < 2)
return sum;
- // Yes, construct list of all dummy index symbols
- lst dummy_syms;
- for (exvector::size_type i=0; i<dummy_indices.size(); i++)
- dummy_syms.append(dummy_indices[i].op(0));
+ // Yes, construct vector of all dummy index symbols
+ exvector dummy_syms;
+ dummy_syms.reserve(dummy_indices.size());
+ for (exvector::const_iterator it = dummy_indices.begin(); it != dummy_indices.end(); ++it)
+ dummy_syms.push_back(it->op(0));
// Chop the sum into terms and symmetrize each one over the dummy
// indices
std::vector<terminfo> terms;
- for (unsigned i=0; i<sum.nops(); i++) {
+ for (size_t i=0; i<sum.nops(); i++) {
const ex & term = sum.op(i);
- ex term_symm = term.symmetrize(dummy_syms);
+ ex term_symm = symmetrize(term, dummy_syms);
if (term_symm.is_zero())
continue;
terms.push_back(terminfo(term, term_symm));
// Combine equal symmetrized terms
std::vector<terminfo> terms_pass2;
for (std::vector<terminfo>::const_iterator i=terms.begin(); i!=terms.end(); ) {
- unsigned num = 1;
+ size_t num = 1;
std::vector<terminfo>::const_iterator j = i + 1;
while (j != terms.end() && j->symm == i->symm) {
num++;
std::vector<symminfo> sy;
for (std::vector<terminfo>::const_iterator i=terms_pass2.begin(); i!=terms_pass2.end(); ++i) {
if (is_exactly_a<add>(i->symm)) {
- unsigned num = i->symm.nops();
- for (unsigned j=0; j<num; j++)
+ size_t num = i->symm.nops();
+ for (size_t j=0; j<num; j++)
sy.push_back(symminfo(i->symm.op(j), i->orig, num));
} else
sy.push_back(symminfo(i->symm, i->orig, 1));
for (std::vector<symminfo>::const_iterator i=sy_pass2.begin(); i!=sy_pass2.end(); ) {
// How many symmetrized terms of this original term are left?
- unsigned num = 1;
+ size_t num = 1;
std::vector<symminfo>::const_iterator j = i + 1;
while (j != sy_pass2.end() && j->orig == i->orig) {
num++;
}
// Simplification of products
- if (is_ex_exactly_of_type(e_expanded, mul)
- || is_ex_exactly_of_type(e_expanded, ncmul)
- || (is_ex_exactly_of_type(e_expanded, power) && is_ex_of_type(e_expanded.op(0), indexed) && e_expanded.op(1).is_equal(_ex2)))
+ if (is_exactly_a<mul>(e_expanded)
+ || is_exactly_a<ncmul>(e_expanded)
+ || (is_exactly_a<power>(e_expanded) && is_a<indexed>(e_expanded.op(0)) && e_expanded.op(1).is_equal(_ex2)))
return simplify_indexed_product(e_expanded, free_indices, dummy_indices, sp);
// Cannot do anything
* the free indices in sums are consistent.
*
* @return simplified expression */
-ex ex::simplify_indexed(void) const
+ex ex::simplify_indexed() const
{
exvector free_indices, dummy_indices;
scalar_products sp;
}
/** Symmetrize expression over its free indices. */
-ex ex::symmetrize(void) const
+ex ex::symmetrize() const
{
return GiNaC::symmetrize(*this, get_free_indices());
}
/** Antisymmetrize expression over its free indices. */
-ex ex::antisymmetrize(void) const
+ex ex::antisymmetrize() const
{
return GiNaC::antisymmetrize(*this, get_free_indices());
}
/** Symmetrize expression by cyclic permutation over its free indices. */
-ex ex::symmetrize_cyclic(void) const
+ex ex::symmetrize_cyclic() const
{
return GiNaC::symmetrize_cyclic(*this, get_free_indices());
}
// helper classes
//////////
+spmapkey::spmapkey(const ex & v1_, const ex & v2_, const ex & dim_) : dim(dim_)
+{
+ // If indexed, extract base objects
+ ex s1 = is_a<indexed>(v1_) ? v1_.op(0) : v1_;
+ ex s2 = is_a<indexed>(v2_) ? v2_.op(0) : v2_;
+
+ // Enforce canonical order in pair
+ if (s1.compare(s2) > 0) {
+ v1 = s2;
+ v2 = s1;
+ } else {
+ v1 = s1;
+ v2 = s2;
+ }
+}
+
+bool spmapkey::operator==(const spmapkey &other) const
+{
+ if (!v1.is_equal(other.v1))
+ return false;
+ if (!v2.is_equal(other.v2))
+ return false;
+ if (is_a<wildcard>(dim) || is_a<wildcard>(other.dim))
+ return true;
+ else
+ return dim.is_equal(other.dim);
+}
+
+bool spmapkey::operator<(const spmapkey &other) const
+{
+ int cmp = v1.compare(other.v1);
+ if (cmp)
+ return cmp < 0;
+ cmp = v2.compare(other.v2);
+ if (cmp)
+ return cmp < 0;
+
+ // Objects are equal, now check dimensions
+ if (is_a<wildcard>(dim) || is_a<wildcard>(other.dim))
+ return false;
+ else
+ return dim.compare(other.dim) < 0;
+}
+
+void spmapkey::debugprint() const
+{
+ std::cerr << "(" << v1 << "," << v2 << "," << dim << ")";
+}
+
void scalar_products::add(const ex & v1, const ex & v2, const ex & sp)
{
- spm[make_key(v1, v2)] = sp;
+ spm[spmapkey(v1, v2)] = sp;
}
-void scalar_products::add_vectors(const lst & l)
+void scalar_products::add(const ex & v1, const ex & v2, const ex & dim, const ex & sp)
+{
+ spm[spmapkey(v1, v2, dim)] = sp;
+}
+
+void scalar_products::add_vectors(const lst & l, const ex & dim)
{
// Add all possible pairs of products
- unsigned num = l.nops();
- for (unsigned i=0; i<num; i++) {
- ex a = l.op(i);
- for (unsigned j=0; j<num; j++) {
- ex b = l.op(j);
- add(a, b, a*b);
- }
- }
+ for (lst::const_iterator it1 = l.begin(); it1 != l.end(); ++it1)
+ for (lst::const_iterator it2 = l.begin(); it2 != l.end(); ++it2)
+ add(*it1, *it2, *it1 * *it2);
}
-void scalar_products::clear(void)
+void scalar_products::clear()
{
spm.clear();
}
/** Check whether scalar product pair is defined. */
-bool scalar_products::is_defined(const ex & v1, const ex & v2) const
+bool scalar_products::is_defined(const ex & v1, const ex & v2, const ex & dim) const
{
- return spm.find(make_key(v1, v2)) != spm.end();
+ return spm.find(spmapkey(v1, v2, dim)) != spm.end();
}
/** Return value of defined scalar product pair. */
-ex scalar_products::evaluate(const ex & v1, const ex & v2) const
+ex scalar_products::evaluate(const ex & v1, const ex & v2, const ex & dim) const
{
- return spm.find(make_key(v1, v2))->second;
+ return spm.find(spmapkey(v1, v2, dim))->second;
}
-void scalar_products::debugprint(void) const
+void scalar_products::debugprint() const
{
std::cerr << "map size=" << spm.size() << std::endl;
spmap::const_iterator i = spm.begin(), end = spm.end();
while (i != end) {
const spmapkey & k = i->first;
- std::cerr << "item key=(" << k.first << "," << k.second;
- std::cerr << "), value=" << i->second << std::endl;
+ std::cerr << "item key=";
+ k.debugprint();
+ std::cerr << ", value=" << i->second << std::endl;
++i;
}
}
-/** Make key from object pair. */
-spmapkey scalar_products::make_key(const ex & v1, const ex & v2)
-{
- // If indexed, extract base objects
- ex s1 = is_ex_of_type(v1, indexed) ? v1.op(0) : v1;
- ex s2 = is_ex_of_type(v2, indexed) ? v2.op(0) : v2;
-
- // Enforce canonical order in pair
- if (s1.compare(s2) > 0)
- return spmapkey(s2, s1);
- else
- return spmapkey(s1, s2);
-}
-
} // namespace GiNaC
#include <map>
#include "exprseq.h"
+#include "wildcard.h"
namespace GiNaC {
// functions overriding virtual functions from base classes
public:
void print(const print_context & c, unsigned level = 0) const;
- unsigned precedence(void) const {return 55;}
+ unsigned precedence() const {return 55;}
bool info(unsigned inf) const;
ex eval(int level = 0) const;
- exvector get_free_indices(void) const;
+ exvector get_free_indices() const;
protected:
ex derivative(const symbol & s) const;
- ex thisexprseq(const exvector & v) const;
- ex thisexprseq(exvector * vp) const;
- unsigned return_type(void) const { return return_types::commutative; }
+ ex thiscontainer(const exvector & v) const;
+ ex thiscontainer(exvector * vp) const;
+ unsigned return_type() const { return return_types::commutative; }
ex expand(unsigned options = 0) const;
// new virtual functions which can be overridden by derived classes
bool all_index_values_are(unsigned inf) const;
/** Return a vector containing the object's indices. */
- exvector get_indices(void) const;
+ exvector get_indices() const;
/** Return a vector containing the dummy indices of the object, if any. */
- exvector get_dummy_indices(void) const;
+ exvector get_dummy_indices() const;
/** Return a vector containing the dummy indices in the contraction with
* another indexed object. */
bool has_dummy_index_for(const ex & i) const;
/** Return symmetry properties. */
- ex get_symmetry(void) const {return symtree;}
+ ex get_symmetry() const {return symtree;}
protected:
void printindices(const print_context & c, unsigned level) const;
- void validate(void) const;
+ void validate() const;
// member variables
protected:
};
-typedef std::pair<ex, ex> spmapkey;
+class spmapkey {
+public:
+ spmapkey() : dim(wild()) {}
+ spmapkey(const ex & v1, const ex & v2, const ex & dim = wild());
+
+ bool operator==(const spmapkey &other) const;
+ bool operator<(const spmapkey &other) const;
-struct spmapkey_is_less {
- bool operator() (const spmapkey &p, const spmapkey &q) const
- {
- int cmp = p.first.compare(q.first);
- return ((cmp<0) || (!(cmp>0) && p.second.compare(q.second)<0));
- }
+ void debugprint() const;
+
+protected:
+ ex v1, v2, dim;
};
-typedef std::map<spmapkey, ex, spmapkey_is_less> spmap;
+typedef std::map<spmapkey, ex> spmap;
/** Helper class for storing information about known scalar products which
* are to be automatically replaced by simplify_indexed().
/** Register scalar product pair and its value. */
void add(const ex & v1, const ex & v2, const ex & sp);
+ /** Register scalar product pair and its value for a specific space dimension. */
+ void add(const ex & v1, const ex & v2, const ex & dim, const ex & sp);
+
/** Register list of vectors. This adds all possible pairs of products
* a.i * b.i with the value a*b (note that this is not a scalar vector
* product but an ordinary product of scalars). */
- void add_vectors(const lst & l);
+ void add_vectors(const lst & l, const ex & dim = wild());
/** Clear all registered scalar products. */
- void clear(void);
-
- bool is_defined(const ex & v1, const ex & v2) const;
- ex evaluate(const ex & v1, const ex & v2) const;
- void debugprint(void) const;
+ void clear();
-private:
- static spmapkey make_key(const ex & v1, const ex & v2);
+ bool is_defined(const ex & v1, const ex & v2, const ex & dim) const;
+ ex evaluate(const ex & v1, const ex & v2, const ex & dim) const;
+ void debugprint() const;
+protected:
spmap spm; /*< Map from defined scalar product pairs to their values */
};
#include "matrix.h"
#include "mul.h"
#include "power.h"
+#include "operators.h"
#include "relational.h"
#include "pseries.h"
#include "symbol.h"
static ex abs_eval(const ex & arg)
{
- if (is_ex_exactly_of_type(arg, numeric))
+ if (is_exactly_a<numeric>(arg))
return abs(ex_to<numeric>(arg));
else
return abs(arg).hold();
static ex csgn_eval(const ex & arg)
{
- if (is_ex_exactly_of_type(arg, numeric))
+ if (is_exactly_a<numeric>(arg))
return csgn(ex_to<numeric>(arg));
- else if (is_ex_exactly_of_type(arg, mul) &&
- is_ex_of_type(arg.op(arg.nops()-1),numeric)) {
+ else if (is_exactly_a<mul>(arg) &&
+ is_exactly_a<numeric>(arg.op(arg.nops()-1))) {
numeric oc = ex_to<numeric>(arg.op(arg.nops()-1));
if (oc.is_real()) {
if (oc > 0)
seq.push_back(expair(Li2(x_pt), _ex0));
// compute the intermediate terms:
ex replarg = series(Li2(x), s==foo, order);
- for (unsigned i=1; i<replarg.nops()-1; ++i)
+ for (size_t i=1; i<replarg.nops()-1; ++i)
seq.push_back(expair((replarg.op(i)/power(s-foo,i)).series(foo==point,1,options).op(0).subs(foo==s),i));
// append an order term:
seq.push_back(expair(Order(_ex1), replarg.nops()-1));
static ex factorial_eval(const ex & x)
{
- if (is_ex_exactly_of_type(x, numeric))
+ if (is_exactly_a<numeric>(x))
return factorial(ex_to<numeric>(x));
else
return factorial(x).hold();
static ex binomial_eval(const ex & x, const ex &y)
{
- if (is_ex_exactly_of_type(x, numeric) && is_ex_exactly_of_type(y, numeric))
+ if (is_exactly_a<numeric>(x) && is_exactly_a<numeric>(y))
return binomial(ex_to<numeric>(x), ex_to<numeric>(y));
else
return binomial(x, y).hold();
static ex Order_eval(const ex & x)
{
- if (is_ex_exactly_of_type(x, numeric)) {
+ if (is_exactly_a<numeric>(x)) {
// O(c) -> O(1) or 0
if (!x.is_zero())
return Order(_ex1).hold();
else
return _ex0;
- } else if (is_ex_exactly_of_type(x, mul)) {
+ } else if (is_exactly_a<mul>(x)) {
const mul &m = ex_to<mul>(x);
// O(c*expr) -> O(expr)
- if (is_ex_exactly_of_type(m.op(m.nops() - 1), numeric))
+ if (is_exactly_a<numeric>(m.op(m.nops() - 1)))
return Order(x / m.op(m.nops() - 1)).hold();
}
return Order(x).hold();
if (!eqns.info(info_flags::list)) {
throw(std::invalid_argument("lsolve(): 1st argument must be a list"));
}
- for (unsigned i=0; i<eqns.nops(); i++) {
+ for (size_t i=0; i<eqns.nops(); i++) {
if (!eqns.op(i).info(info_flags::relation_equal)) {
throw(std::invalid_argument("lsolve(): 1st argument must be a list of equations"));
}
if (!symbols.info(info_flags::list)) {
throw(std::invalid_argument("lsolve(): 2nd argument must be a list"));
}
- for (unsigned i=0; i<symbols.nops(); i++) {
+ for (size_t i=0; i<symbols.nops(); i++) {
if (!symbols.op(i).info(info_flags::symbol)) {
throw(std::invalid_argument("lsolve(): 2nd argument must be a list of symbols"));
}
matrix rhs(eqns.nops(),1);
matrix vars(symbols.nops(),1);
- for (unsigned r=0; r<eqns.nops(); r++) {
+ for (size_t r=0; r<eqns.nops(); r++) {
const ex eq = eqns.op(r).op(0)-eqns.op(r).op(1); // lhs-rhs==0
ex linpart = eq;
- for (unsigned c=0; c<symbols.nops(); c++) {
+ for (size_t c=0; c<symbols.nops(); c++) {
const ex co = eq.coeff(ex_to<symbol>(symbols.op(c)),1);
linpart -= co*symbols.op(c);
sys(r,c) = co;
}
// test if system is linear and fill vars matrix
- for (unsigned i=0; i<symbols.nops(); i++) {
+ for (size_t i=0; i<symbols.nops(); i++) {
vars(i,0) = symbols.op(i);
if (sys.has(symbols.op(i)))
throw(std::logic_error("lsolve: system is not linear"));
// return list of equations of the form lst(var1==sol1,var2==sol2,...)
lst sollist;
- for (unsigned i=0; i<symbols.nops(); i++)
+ for (size_t i=0; i<symbols.nops(); i++)
sollist.append(symbols.op(i)==solution(i,0));
return sollist;
/* Force inclusion of functions from inifcns_gamma and inifcns_zeta
* for static lib (so ginsh will see them). */
-unsigned force_include_tgamma = function_index_tgamma;
-unsigned force_include_zeta1 = function_index_zeta1;
+unsigned force_include_tgamma = tgamma_SERIAL::serial;
+unsigned force_include_zeta1 = zeta1_SERIAL::serial;
} // namespace GiNaC
// overloading at work: we cannot use the macros here
/** Riemann's Zeta-function. */
-extern const unsigned function_index_zeta1;
+class zeta1_SERIAL { public: static unsigned serial; };
template<typename T1>
inline function zeta(const T1 & p1) {
- return function(function_index_zeta1, ex(p1));
+ return function(zeta1_SERIAL::serial, ex(p1));
}
/** Derivatives of Riemann's Zeta-function. */
-extern const unsigned function_index_zeta2;
+class zeta2_SERIAL { public: static unsigned serial; };
template<typename T1, typename T2>
inline function zeta(const T1 & p1, const T2 & p2) {
- return function(function_index_zeta2, ex(p1), ex(p2));
+ return function(zeta2_SERIAL::serial, ex(p1), ex(p2));
+}
+class zeta_SERIAL;
+template<> inline bool is_the_function<class zeta_SERIAL>(const ex & x)
+{
+ return is_the_function<zeta1_SERIAL>(x) || is_the_function<zeta2_SERIAL>(x);
}
/** Gamma-function. */
// overloading at work: we cannot use the macros here
/** Psi-function (aka digamma-function). */
-extern const unsigned function_index_psi1;
+class psi1_SERIAL { public: static unsigned serial; };
template<typename T1>
inline function psi(const T1 & p1) {
- return function(function_index_psi1, ex(p1));
+ return function(psi1_SERIAL::serial, ex(p1));
}
/** Derivatives of Psi-function (aka polygamma-functions). */
-extern const unsigned function_index_psi2;
+class psi2_SERIAL { public: static unsigned serial; };
template<typename T1, typename T2>
inline function psi(const T1 & p1, const T2 & p2) {
- return function(function_index_psi2, ex(p1), ex(p2));
+ return function(psi2_SERIAL::serial, ex(p1), ex(p2));
+}
+class psi_SERIAL;
+template<> inline bool is_the_function<class psi_SERIAL>(const ex & x)
+{
+ return is_the_function<psi1_SERIAL>(x) || is_the_function<psi2_SERIAL>(x);
}
/** Factorial function. */
/** Order term function (for truncated power series). */
DECLARE_FUNCTION_1P(Order)
-ex lsolve(const ex &eqns, const ex &symbols, unsigned options = determinant_algo::automatic);
+ex lsolve(const ex &eqns, const ex &symbols, unsigned options = solve_algo::automatic);
/** Check whether a function is the Order (O(n)) function. */
inline bool is_order_function(const ex & e)
#include "numeric.h"
#include "power.h"
#include "relational.h"
+#include "operators.h"
#include "symbol.h"
#include "symmetry.h"
#include "utils.h"
static ex beta_eval(const ex & x, const ex & y)
{
+ if (x.is_equal(_ex1))
+ return 1/y;
+ if (y.is_equal(_ex1))
+ return 1/x;
if (x.info(info_flags::numeric) && y.info(info_flags::numeric)) {
// treat all problematic x and y that may not be passed into tgamma,
// because they would throw there although beta(x,y) is well-defined
return (psi(arg+m+_ex1)-recur).series(rel, order, options);
}
-const unsigned function_index_psi1 =
+unsigned psi1_SERIAL::serial =
function::register_new(function_options("psi").
eval_func(psi1_eval).
evalf_func(psi1_evalf).
return (psi(n, arg+m+_ex1)-recur).series(rel, order, options);
}
-const unsigned function_index_psi2 =
+unsigned psi2_SERIAL::serial =
function::register_new(function_options("psi").
eval_func(psi2_eval).
evalf_func(psi2_evalf).
#include "constant.h"
#include "numeric.h"
#include "power.h"
+#include "operators.h"
#include "relational.h"
#include "symbol.h"
#include "pseries.h"
return power(x, _ex_1);
}
-// This is a strange workaround for a compiliation problem with the try statement
-// below. With -O1 the exception is not caucht properly as of GCC-2.95.2, at
-// least on i386. Version 2.95.4 seems to have fixed this silly problem, though.
-// Funnily, with a simple extern declaration here it mysteriously works again.
-#if defined(__GNUC__) && (__GNUC__==2)
-extern "C" int putchar(int);
-#endif
-
static ex log_series(const ex &arg,
const relational &rel,
int order,
#include "numeric.h"
#include "power.h"
#include "symbol.h"
+#include "operators.h"
#include "utils.h"
namespace GiNaC {
return zeta(_ex1, x);
}
-const unsigned function_index_zeta1 =
+unsigned zeta1_SERIAL::serial =
function::register_new(function_options("zeta").
eval_func(zeta1_eval).
evalf_func(zeta1_evalf).
return zeta(n+1,x);
}
-const unsigned function_index_zeta2 =
+unsigned zeta2_SERIAL::serial =
function::register_new(function_options("zeta").
eval_func(zeta2_eval).
derivative_func(zeta2_deriv).
extern bool is_lexer_symbol_predefined(const ex &s);
/** The expression parser function (used internally). */
-extern int ginac_yyparse();
+extern int ginac_yyparse(void);
/** The expression returned by the parser (used internally). */
extern ex parsed_ex;
%{
#include <stdexcept>
-#include "input_lexer.h"
#include "ex.h"
+#include "input_lexer.h"
#include "relational.h"
+#include "operators.h"
#include "symbol.h"
#include "lst.h"
#include "power.h"
-/** @file lst_suppl.cpp
+/** @file lst.cpp
*
- * Supplement to lst.cpp, contains the parts which were not automatically
- * generated. */
+ * Implementation of GiNaC's lst. */
/*
* GiNaC Copyright (C) 1999-2003 Johannes Gutenberg University Mainz, Germany
namespace GiNaC {
+GINAC_IMPLEMENT_REGISTERED_CLASS(lst, basic)
+
+/** Specialization of container::info() for lst. */
bool lst::info(unsigned inf) const
{
- if (inf==info_flags::list) return true;
- return basic::info(inf);
+ if (inf == info_flags::list)
+ return true;
+ else
+ return inherited::info(inf);
}
} // namespace GiNaC
--- /dev/null
+/** @file lst.h
+ *
+ * Definition of GiNaC's lst. */
+
+/*
+ * GiNaC Copyright (C) 1999-2003 Johannes Gutenberg University Mainz, Germany
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __GINAC_LST_H__
+#define __GINAC_LST_H__
+
+#include <list>
+
+#include "container.h"
+
+namespace GiNaC {
+
+typedef container<std::list> lst;
+
+/** Specialization of container::get_tinfo() for lst. */
+inline unsigned lst::get_tinfo() { return TINFO_lst; }
+
+/** Specialization of container::get_open_delim() for lst. */
+inline char lst::get_open_delim() { return '{'; }
+
+/** Specialization of container::get_close_delim() for lst. */
+inline char lst::get_close_delim() { return '}'; }
+
+// defined in lst.cpp
+template<> bool lst::info(unsigned inf) const;
+
+/** Specialization of is_exactly_a<lst>(obj) for lst objects. */
+template<> inline bool is_exactly_a<lst>(const basic & obj)
+{
+ return obj.tinfo() == TINFO_lst;
+}
+
+} // namespace GiNaC
+
+#endif // ndef __GINAC_LST_H__
#include "lst.h"
#include "idx.h"
#include "indexed.h"
+#include "add.h"
#include "power.h"
#include "symbol.h"
+#include "operators.h"
#include "normal.h"
#include "print.h"
#include "archive.h"
GINAC_IMPLEMENT_REGISTERED_CLASS(matrix, basic)
//////////
-// default ctor, dtor, copy ctor, assignment operator and helpers:
+// default constructor
//////////
/** Default ctor. Initializes to 1 x 1-dimensional zero-matrix. */
m.push_back(_ex0);
}
-void matrix::copy(const matrix & other)
-{
- inherited::copy(other);
- row = other.row;
- col = other.col;
- m = other.m; // STL's vector copying invoked here
-}
-
-DEFAULT_DESTROY(matrix)
-
//////////
-// other ctors
+// other constructors
//////////
// public
{
m.resize(r*c, _ex0);
- for (unsigned i=0; i<l.nops(); i++) {
- unsigned x = i % c;
- unsigned y = i / c;
+ size_t i = 0;
+ for (lst::const_iterator it = l.begin(); it != l.end(); ++it, ++i) {
+ size_t x = i % c;
+ size_t y = i / c;
if (y >= r)
break; // matrix smaller than list: throw away excessive elements
- m[y*c+x] = l.op(i);
+ m[y*c+x] = *it;
}
}
// archiving
//////////
-matrix::matrix(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
+matrix::matrix(const archive_node &n, lst &sym_lst) : inherited(n, sym_lst)
{
if (!(n.find_unsigned("row", row)) || !(n.find_unsigned("col", col)))
throw (std::runtime_error("unknown matrix dimensions in archive"));
}
/** nops is defined to be rows x columns. */
-unsigned matrix::nops() const
+size_t matrix::nops() const
{
- return row*col;
+ return static_cast<size_t>(row) * static_cast<size_t>(col);
}
/** returns matrix entry at position (i/col, i%col). */
-ex matrix::op(int i) const
+ex matrix::op(size_t i) const
{
+ GINAC_ASSERT(i<nops());
+
return m[i];
}
-/** returns matrix entry at position (i/col, i%col). */
-ex & matrix::let_op(int i)
+/** returns writable matrix entry at position (i/col, i%col). */
+ex & matrix::let_op(size_t i)
{
- GINAC_ASSERT(i>=0);
GINAC_ASSERT(i<nops());
+ ensure_if_modifiable();
return m[i];
}
status_flags::evaluated);
}
-ex matrix::subs(const lst & ls, const lst & lr, bool no_pattern) const
-{
+ex matrix::subs(const lst & ls, const lst & lr, unsigned options) const
+{
exvector m2(row * col);
for (unsigned r=0; r<row; ++r)
for (unsigned c=0; c<col; ++c)
- m2[r*col+c] = m[r*col+c].subs(ls, lr, no_pattern);
+ m2[r*col+c] = m[r*col+c].subs(ls, lr, options);
- return matrix(row, col, m2).basic::subs(ls, lr, no_pattern);
+ return matrix(row, col, m2).subs_one_level(ls, lr, options);
}
// protected
GINAC_ASSERT(self.nops() == 2 || self.nops() == 3);
// Only add two matrices
- if (is_ex_of_type(other.op(0), matrix)) {
+ if (is_a<matrix>(other.op(0))) {
GINAC_ASSERT(other.nops() == 2 || other.nops() == 3);
const matrix &self_matrix = ex_to<matrix>(self.op(0));
GINAC_ASSERT(is_a<matrix>(self->op(0)));
// Only contract with other matrices
- if (!is_ex_of_type(other->op(0), matrix))
+ if (!is_a<matrix>(other->op(0)))
return false;
GINAC_ASSERT(other->nops() == 2 || other->nops() == 3);
if (col!=row)
throw (std::logic_error("matrix::pow(): matrix not square"));
- if (is_ex_exactly_of_type(expn, numeric)) {
+ if (is_exactly_a<numeric>(expn)) {
// Integer cases are computed by successive multiplication, using the
// obvious shortcut of storing temporaries, like A^4 == (A*A)*(A*A).
if (expn.info(info_flags::integer)) {
/** Transposed of an m x n matrix, producing a new n x m matrix object that
* represents the transposed. */
-matrix matrix::transpose(void) const
+matrix matrix::transpose() const
{
exvector trans(this->cols()*this->rows());
*
* @return the sum of diagonal elements
* @exception logic_error (matrix not square) */
-ex matrix::trace(void) const
+ex matrix::trace() const
{
if (row != col)
throw (std::logic_error("matrix::trace(): matrix not square"));
// trapped and we use Leverrier's algorithm which goes as row^3 for
// every coefficient. The expensive part is the matrix multiplication.
if (numeric_flag) {
+
matrix B(*this);
ex c = B.trace();
ex poly = power(lambda,row)-c*power(lambda,row-1);
for (unsigned j=0; j<row; ++j)
B.m[j*col+j] -= c;
B = this->mul(B);
- c = B.trace()/ex(i+1);
+ c = B.trace() / ex(i+1);
poly -= c*power(lambda,row-i-1);
}
if (row%2)
return -poly;
else
return poly;
- }
+
+ } else {
- matrix M(*this);
- for (unsigned r=0; r<col; ++r)
- M.m[r*col+r] -= lambda;
+ matrix M(*this);
+ for (unsigned r=0; r<col; ++r)
+ M.m[r*col+r] -= lambda;
- return M.determinant().collect(lambda);
+ return M.determinant().collect(lambda);
+ }
}
* @return the inverted matrix
* @exception logic_error (matrix not square)
* @exception runtime_error (singular matrix) */
-matrix matrix::inverse(void) const
+matrix matrix::inverse() const
{
if (row != col)
throw (std::logic_error("matrix::inverse(): matrix not square"));
*
* @return the determinant as a new expression (in expanded form)
* @see matrix::determinant() */
-ex matrix::determinant_minor(void) const
+ex matrix::determinant_minor() const
{
// for small matrices the algorithm does not make any sense:
const unsigned n = this->cols();
//
// Bareiss (fraction-free) elimination in addition divides that element
// by m[k-1](k-1,k-1) for k>1, where it can be shown by means of the
- // Sylvester determinant that this really divides m[k+1](r,c).
+ // Sylvester identity that this really divides m[k+1](r,c).
//
// We also allow rational functions where the original prove still holds.
// However, we must care for numerator and denominator separately and
ex lst_to_matrix(const lst & l)
{
+ lst::const_iterator itr, itc;
+
// Find number of rows and columns
- unsigned rows = l.nops(), cols = 0, i, j;
- for (i=0; i<rows; i++)
- if (l.op(i).nops() > cols)
- cols = l.op(i).nops();
+ size_t rows = l.nops(), cols = 0;
+ for (itr = l.begin(); itr != l.end(); ++itr) {
+ if (!is_a<lst>(*itr))
+ throw (std::invalid_argument("lst_to_matrix: argument must be a list of lists"));
+ if (itr->nops() > cols)
+ cols = itr->nops();
+ }
// Allocate and fill matrix
matrix &M = *new matrix(rows, cols);
M.setflag(status_flags::dynallocated);
- for (i=0; i<rows; i++)
- for (j=0; j<cols; j++)
- if (l.op(i).nops() > j)
- M(i, j) = l.op(i).op(j);
- else
- M(i, j) = _ex0;
+
+ unsigned i;
+ for (itr = l.begin(), i = 0; itr != l.end(); ++itr, ++i) {
+ unsigned j;
+ for (itc = ex_to<lst>(*itr).begin(), j = 0; itc != ex_to<lst>(*itr).end(); ++itc, ++j)
+ M(i, j) = *itc;
+ }
+
return M;
}
ex diag_matrix(const lst & l)
{
- unsigned dim = l.nops();
+ lst::const_iterator it;
+ size_t dim = l.nops();
+
+ // Allocate and fill matrix
+ matrix &M = *new matrix(dim, dim);
+ M.setflag(status_flags::dynallocated);
- matrix &m = *new matrix(dim, dim);
- m.setflag(status_flags::dynallocated);
- for (unsigned i=0; i<dim; i++)
- m(i, i) = l.op(i);
+ unsigned i;
+ for (it = l.begin(), i = 0; it != l.end(); ++it, ++i)
+ M(i, i) = *it;
- return m;
+ return M;
}
ex unit_matrix(unsigned r, unsigned c)
{
GINAC_DECLARE_REGISTERED_CLASS(matrix, basic)
- // other ctors
+ // other constructors
public:
matrix(unsigned r, unsigned c);
matrix(unsigned r, unsigned c, const exvector & m2);
// functions overriding virtual functions from base classes
public:
void print(const print_context & c, unsigned level = 0) const;
- unsigned nops() const;
- ex op(int i) const;
- ex & let_op(int i);
+ size_t nops() const;
+ ex op(size_t i) const;
+ ex & let_op(size_t i);
ex eval(int level=0) const;
- ex evalm(void) const {return *this;}
- ex subs(const lst & ls, const lst & lr, bool no_pattern = false) const;
+ ex evalm() const {return *this;}
+ ex subs(const lst & ls, const lst & lr, unsigned options = 0) const;
ex eval_indexed(const basic & i) const;
ex add_indexed(const ex & self, const ex & other) const;
ex scalar_mul_indexed(const ex & self, const numeric & other) const;
protected:
bool match_same_type(const basic & other) const;
- unsigned return_type(void) const { return return_types::noncommutative; };
+ unsigned return_type() const { return return_types::noncommutative; };
// non-virtual functions in this class
public:
- unsigned rows(void) const /// Get number of rows.
+ unsigned rows() const /// Get number of rows.
{ return row; }
- unsigned cols(void) const /// Get number of columns.
+ unsigned cols() const /// Get number of columns.
{ return col; }
matrix add(const matrix & other) const;
matrix sub(const matrix & other) const;
const ex & operator() (unsigned ro, unsigned co) const;
ex & operator() (unsigned ro, unsigned co);
matrix & set(unsigned ro, unsigned co, const ex & value) { (*this)(ro, co) = value; return *this; }
- matrix transpose(void) const;
+ matrix transpose() const;
ex determinant(unsigned algo = determinant_algo::automatic) const;
- ex trace(void) const;
+ ex trace() const;
ex charpoly(const symbol & lambda) const;
- matrix inverse(void) const;
+ matrix inverse() const;
matrix solve(const matrix & vars, const matrix & rhs,
unsigned algo = solve_algo::automatic) const;
protected:
- ex determinant_minor(void) const;
+ ex determinant_minor() const;
int gauss_elimination(const bool det = false);
int division_free_elimination(const bool det = false);
int fraction_free_elimination(const bool det = false);
// wrapper functions around member functions
-inline unsigned nops(const matrix & m)
+inline size_t nops(const matrix & m)
{ return m.nops(); }
inline ex expand(const matrix & m, unsigned options = 0)
#include <iostream>
#include <vector>
#include <stdexcept>
+#include <limits>
#include "mul.h"
#include "add.h"
#include "power.h"
+#include "operators.h"
#include "matrix.h"
+#include "lst.h"
#include "archive.h"
#include "utils.h"
GINAC_IMPLEMENT_REGISTERED_CLASS(mul, expairseq)
//////////
-// default ctor, dtor, copy ctor, assignment operator and helpers
+// default constructor
//////////
mul::mul()
tinfo_key = TINFO_mul;
}
-DEFAULT_COPY(mul)
-DEFAULT_DESTROY(mul)
-
//////////
-// other ctors
+// other constructors
//////////
// public
//////////
// public
-
void mul::print(const print_context & c, unsigned level) const
{
if (is_a<print_tree>(c)) {
if (it->coeff.is_equal(_ex1) || it->coeff.is_equal(_ex_1))
it->rest.print(c, precedence());
else if (it->coeff.info(info_flags::negint))
- // Outer parens around ex needed for broken gcc-2.95 parser:
+ // Outer parens around ex needed for broken GCC parser:
(ex(power(it->rest, -ex_to<numeric>(it->coeff)))).print(c, level);
else
- // Outer parens around ex needed for broken gcc-2.95 parser:
+ // Outer parens around ex needed for broken GCC parser:
(ex(power(it->rest, ex_to<numeric>(it->coeff)))).print(c, level);
if (needclosingparenthesis)
} else if (is_a<print_python_repr>(c)) {
c.s << class_name() << '(';
op(0).print(c);
- for (unsigned i=1; i<nops(); ++i) {
+ for (size_t i=1; i<nops(); ++i) {
c.s << ',';
op(i).print(c);
}
}
// First print the overall numeric coefficient
- numeric coeff = ex_to<numeric>(overall_coeff);
+ const numeric &coeff = ex_to<numeric>(overall_coeff);
if (coeff.csgn() == -1)
c.s << '-';
if (!coeff.is_equal(_num1) &&
GINAC_ASSERT((!is_exactly_a<mul>(i->rest)) ||
(!(ex_to<numeric>(i->coeff).is_integer())));
GINAC_ASSERT(!(i->is_canonical_numeric()));
- if (is_ex_exactly_of_type(recombine_pair_to_ex(*i), numeric))
+ if (is_exactly_a<numeric>(recombine_pair_to_ex(*i)))
print(print_tree(std::cerr));
GINAC_ASSERT(!is_exactly_a<numeric>(recombine_pair_to_ex(*i)));
/* for paranoia */
// *(x;1) -> x
return recombine_pair_to_ex(*(seq.begin()));
} else if ((seq_size==1) &&
- is_ex_exactly_of_type((*seq.begin()).rest,add) &&
+ is_exactly_a<add>((*seq.begin()).rest) &&
ex_to<numeric>((*seq.begin()).coeff).is_equal(_num1)) {
// *(+(x,y,...);c) -> +(*(x,c),*(y,c),...) (c numeric(), no powers of +())
const add & addref = ex_to<add>((*seq.begin()).rest);
return mul(s, overall_coeff.evalf(level));
}
-ex mul::evalm(void) const
+ex mul::evalm() const
{
// numeric*matrix
if (seq.size() == 1 && seq[0].coeff.is_equal(_ex1)
- && is_ex_of_type(seq[0].rest, matrix))
+ && is_a<matrix>(seq[0].rest))
return ex_to<matrix>(seq[0].rest).mul(ex_to<numeric>(overall_coeff));
// Evaluate children first, look whether there are any matrices at all
while (i != end) {
const ex &m = recombine_pair_to_ex(*i).evalm();
s->push_back(split_ex_to_pair(m));
- if (is_ex_of_type(m, matrix)) {
+ if (is_a<matrix>(m)) {
have_matrix = true;
the_matrix = s->end() - 1;
}
return (new mul(s, overall_coeff))->setflag(status_flags::dynallocated);
}
-ex mul::simplify_ncmul(const exvector & v) const
+ex mul::eval_ncmul(const exvector & v) const
{
if (seq.empty())
- return inherited::simplify_ncmul(v);
+ return inherited::eval_ncmul(v);
- // Find first noncommutative element and call its simplify_ncmul()
+ // Find first noncommutative element and call its eval_ncmul()
epvector::const_iterator i = seq.begin(), end = seq.end();
while (i != end) {
if (i->rest.return_type() == return_types::noncommutative)
- return i->rest.simplify_ncmul(v);
+ return i->rest.eval_ncmul(v);
++i;
}
- return inherited::simplify_ncmul(v);
+ return inherited::eval_ncmul(v);
+}
+
+bool tryfactsubs(const ex & origfactor, const ex & patternfactor, int & nummatches, lst & repls)
+{
+ ex origbase;
+ int origexponent;
+ int origexpsign;
+
+ if (is_exactly_a<power>(origfactor) && origfactor.op(1).info(info_flags::integer)) {
+ origbase = origfactor.op(0);
+ int expon = ex_to<numeric>(origfactor.op(1)).to_int();
+ origexponent = expon > 0 ? expon : -expon;
+ origexpsign = expon > 0 ? 1 : -1;
+ } else {
+ origbase = origfactor;
+ origexponent = 1;
+ origexpsign = 1;
+ }
+
+ ex patternbase;
+ int patternexponent;
+ int patternexpsign;
+
+ if (is_exactly_a<power>(patternfactor) && patternfactor.op(1).info(info_flags::integer)) {
+ patternbase = patternfactor.op(0);
+ int expon = ex_to<numeric>(patternfactor.op(1)).to_int();
+ patternexponent = expon > 0 ? expon : -expon;
+ patternexpsign = expon > 0 ? 1 : -1;
+ } else {
+ patternbase = patternfactor;
+ patternexponent = 1;
+ patternexpsign = 1;
+ }
+
+ lst saverepls = repls;
+ if (origexponent < patternexponent || origexpsign != patternexpsign || !origbase.match(patternbase,saverepls))
+ return false;
+ repls = saverepls;
+
+ int newnummatches = origexponent / patternexponent;
+ if (newnummatches < nummatches)
+ nummatches = newnummatches;
+ return true;
+}
+
+ex mul::algebraic_subs_mul(const lst & ls, const lst & lr, unsigned options) const
+{
+ std::vector<bool> subsed(seq.size(), false);
+ exvector subsresult(seq.size());
+
+ lst::const_iterator its, itr;
+ for (its = ls.begin(), itr = lr.begin(); its != ls.end(); ++its, ++itr) {
+
+ if (is_exactly_a<mul>(*its)) {
+
+ int nummatches = std::numeric_limits<int>::max();
+ std::vector<bool> currsubsed(seq.size(), false);
+ bool succeed = true;
+ lst repls;
+
+ for (size_t j=0; j<its->nops(); j++) {
+ bool found=false;
+ for (size_t k=0; k<nops(); k++) {
+ if (currsubsed[k] || subsed[k])
+ continue;
+ if (tryfactsubs(op(k), its->op(j), nummatches, repls)) {
+ currsubsed[k] = true;
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ succeed = false;
+ break;
+ }
+ }
+ if (!succeed)
+ continue;
+
+ bool foundfirstsubsedfactor = false;
+ for (size_t j=0; j<subsed.size(); j++) {
+ if (currsubsed[j]) {
+ if (foundfirstsubsedfactor)
+ subsresult[j] = op(j);
+ else {
+ foundfirstsubsedfactor = true;
+ subsresult[j] = op(j) * power(itr->subs(ex(repls), subs_options::subs_no_pattern) / its->subs(ex(repls), subs_options::subs_no_pattern), nummatches);
+ }
+ subsed[j] = true;
+ }
+ }
+
+ } else {
+
+ int nummatches = std::numeric_limits<int>::max();
+ lst repls;
+
+ for (size_t j=0; j<this->nops(); j++) {
+ if (!subsed[j] && tryfactsubs(op(j), *its, nummatches, repls)) {
+ subsed[j] = true;
+ subsresult[j] = op(j) * power(itr->subs(ex(repls), subs_options::subs_no_pattern) / its->subs(ex(repls), subs_options::subs_no_pattern), nummatches);
+ }
+ }
+ }
+ }
+
+ bool subsfound = false;
+ for (size_t i=0; i<subsed.size(); i++) {
+ if (subsed[i]) {
+ subsfound = true;
+ break;
+ }
+ }
+ if (!subsfound)
+ return subs_one_level(ls, lr, options | subs_options::subs_algebraic);
+
+ exvector ev; ev.reserve(nops());
+ for (size_t i=0; i<nops(); i++) {
+ if (subsed[i])
+ ev.push_back(subsresult[i]);
+ else
+ ev.push_back(op(i));
+ }
+
+ return (new mul(ev))->setflag(status_flags::dynallocated);
}
// protected
* @see ex::diff */
ex mul::derivative(const symbol & s) const
{
- unsigned num = seq.size();
+ size_t num = seq.size();
exvector addseq;
addseq.reserve(num);
return inherited::compare_same_type(other);
}
-bool mul::is_equal_same_type(const basic & other) const
-{
- return inherited::is_equal_same_type(other);
-}
-
-unsigned mul::return_type(void) const
+unsigned mul::return_type() const
{
if (seq.empty()) {
// mul without factors: should not happen, but commutes
return all_commutative ? return_types::commutative : return_types::noncommutative;
}
-unsigned mul::return_type_tinfo(void) const
+unsigned mul::return_type_tinfo() const
{
if (seq.empty())
return tinfo_key; // mul without factors: should not happen
expair mul::split_ex_to_pair(const ex & e) const
{
- if (is_ex_exactly_of_type(e,power)) {
+ if (is_exactly_a<power>(e)) {
const power & powerref = ex_to<power>(e);
- if (is_ex_exactly_of_type(powerref.exponent,numeric))
+ if (is_exactly_a<numeric>(powerref.exponent))
return expair(powerref.basis,powerref.exponent);
}
return expair(e,_ex1);
{
// to avoid duplication of power simplification rules,
// we create a temporary power object
- // otherwise it would be hard to correctly simplify
+ // otherwise it would be hard to correctly evaluate
// expression like (4^(1/3))^(3/2)
- if (are_ex_trivially_equal(c,_ex1))
+ if (c.is_equal(_ex1))
return split_ex_to_pair(e);
-
+
return split_ex_to_pair(power(e,c));
}
{
// to avoid duplication of power simplification rules,
// we create a temporary power object
- // otherwise it would be hard to correctly simplify
+ // otherwise it would be hard to correctly evaluate
// expression like (4^(1/3))^(3/2)
- if (are_ex_trivially_equal(c,_ex1))
+ if (c.is_equal(_ex1))
return p;
-
+
return split_ex_to_pair(power(recombine_pair_to_ex(p),c));
}
if (ex_to<numeric>(p.coeff).is_equal(_num1))
return p.rest;
else
- return power(p.rest,p.coeff);
+ return (new power(p.rest,p.coeff))->setflag(status_flags::dynallocated);
}
bool mul::expair_needs_further_processing(epp it)
{
- if (is_ex_exactly_of_type((*it).rest,mul) &&
- ex_to<numeric>((*it).coeff).is_integer()) {
+ if (is_exactly_a<mul>(it->rest) &&
+ ex_to<numeric>(it->coeff).is_integer()) {
// combined pair is product with integer power -> expand it
*it = split_ex_to_pair(recombine_pair_to_ex(*it));
return true;
}
- if (is_ex_exactly_of_type((*it).rest,numeric)) {
- expair ep=split_ex_to_pair(recombine_pair_to_ex(*it));
+ if (is_exactly_a<numeric>(it->rest)) {
+ expair ep = split_ex_to_pair(recombine_pair_to_ex(*it));
if (!ep.is_equal(*it)) {
// combined pair is a numeric power which can be simplified
*it = ep;
return true;
}
- if (ex_to<numeric>((*it).coeff).is_equal(_num1)) {
+ if (it->coeff.is_equal(_ex1)) {
// combined pair has coeff 1 and must be moved to the end
return true;
}
return false;
}
-ex mul::default_overall_coeff(void) const
+ex mul::default_overall_coeff() const
{
return _ex1;
}
non_adds.reserve(expanded_seq.size());
epvector::const_iterator cit = expanded_seq.begin(), last = expanded_seq.end();
while (cit != last) {
- if (is_ex_exactly_of_type(cit->rest, add) &&
+ if (is_exactly_a<add>(cit->rest) &&
(cit->coeff.is_equal(_ex1))) {
++number_of_adds;
- if (is_ex_exactly_of_type(last_expanded, add)) {
-#if 0
- // Expand a product of two sums, simple and robust version.
- const add & add1 = ex_to<add>(last_expanded);
- const add & add2 = ex_to<add>(cit->rest);
- const int n1 = add1.nops();
- const int n2 = add2.nops();
- ex tmp_accu;
- exvector distrseq;
- distrseq.reserve(n2);
- for (int i1=0; i1<n1; ++i1) {
- distrseq.clear();
- // cache the first operand (for efficiency):
- const ex op1 = add1.op(i1);
- for (int i2=0; i2<n2; ++i2)
- distrseq.push_back(op1 * add2.op(i2));
- tmp_accu += (new add(distrseq))->
- setflag(status_flags::dynallocated);
- }
- last_expanded = tmp_accu;
-#else
+ if (is_exactly_a<add>(last_expanded)) {
+
// Expand a product of two sums, aggressive version.
// Caring for the overall coefficients in separate loops can
// sometimes give a performance gain of up to 15%!
// Don't push_back expairs which might have a rest that evaluates to a numeric,
// since that would violate an invariant of expairseq:
const ex rest = (new mul(i1->rest, i2->rest))->setflag(status_flags::dynallocated);
- if (is_ex_exactly_of_type(rest, numeric))
+ if (is_exactly_a<numeric>(rest))
oc += ex_to<numeric>(rest).mul(ex_to<numeric>(i1->coeff).mul(ex_to<numeric>(i2->coeff)));
else
distrseq.push_back(expair(rest, ex_to<numeric>(i1->coeff).mul_dyn(ex_to<numeric>(i2->coeff))));
tmp_accu += (new add(distrseq, oc))->setflag(status_flags::dynallocated);
}
last_expanded = tmp_accu;
-#endif
+
} else {
non_adds.push_back(split_ex_to_pair(last_expanded));
last_expanded = cit->rest;
// Now the only remaining thing to do is to multiply the factors which
// were not sums into the "last_expanded" sum
- if (is_ex_exactly_of_type(last_expanded, add)) {
+ if (is_exactly_a<add>(last_expanded)) {
const add & finaladd = ex_to<add>(last_expanded);
exvector distrseq;
- int n = finaladd.nops();
+ size_t n = finaladd.nops();
distrseq.reserve(n);
- for (int i=0; i<n; ++i) {
+ for (size_t i=0; i<n; ++i) {
epvector factors = non_adds;
factors.push_back(split_ex_to_pair(finaladd.op(i)));
distrseq.push_back((new mul(factors, overall_coeff))->
friend class ncmul;
friend class power;
- // other ctors
+ // other constructors
public:
mul(const ex & lh, const ex & rh);
mul(const exvector & v);
// functions overriding virtual functions from base classes
public:
void print(const print_context & c, unsigned level = 0) const;
- unsigned precedence(void) const {return 50;}
+ unsigned precedence() const {return 50;}
bool info(unsigned inf) const;
int degree(const ex & s) const;
int ldegree(const ex & s) const;
ex coeff(const ex & s, int n = 1) const;
ex eval(int level=0) const;
ex evalf(int level=0) const;
- ex evalm(void) const;
+ ex evalm() const;
ex series(const relational & s, int order, unsigned options = 0) const;
ex normal(lst &sym_lst, lst &repl_lst, int level = 0) const;
- numeric integer_content(void) const;
+ numeric integer_content() const;
ex smod(const numeric &xi) const;
- numeric max_coefficient(void) const;
- exvector get_free_indices(void) const;
- ex simplify_ncmul(const exvector & v) const;
+ numeric max_coefficient() const;
+ exvector get_free_indices() const;
protected:
ex derivative(const symbol & s) const;
- bool is_equal_same_type(const basic & other) const;
- unsigned return_type(void) const;
- unsigned return_type_tinfo(void) const;
+ ex eval_ncmul(const exvector & v) const;
+ unsigned return_type() const;
+ unsigned return_type_tinfo() const;
ex thisexpairseq(const epvector & v, const ex & oc) const;
ex thisexpairseq(epvector * vp, const ex & oc) const;
expair split_ex_to_pair(const ex & e) const;
expair combine_pair_with_coeff_to_pair(const expair & p, const ex & c) const;
ex recombine_pair_to_ex(const expair & p) const;
bool expair_needs_further_processing(epp it);
- ex default_overall_coeff(void) const;
+ ex default_overall_coeff() const;
void combine_overall_coeff(const ex & c);
void combine_overall_coeff(const ex & c1, const ex & c2);
bool can_make_flat(const expair & p) const;
// none
// non-virtual functions in this class
+public:
+ ex algebraic_subs_mul(const lst & ls, const lst & lr, unsigned options) const;
protected:
epvector * expandchildren(unsigned options) const;
};
GINAC_IMPLEMENT_REGISTERED_CLASS(ncmul, exprseq)
//////////
-// default ctor, dtor, copy ctor, assignment operator and helpers
+// default constructor
//////////
ncmul::ncmul()
tinfo_key = TINFO_ncmul;
}
-DEFAULT_COPY(ncmul)
-DEFAULT_DESTROY(ncmul)
-
//////////
// other constructors
//////////
intvector positions_of_adds(expanded_seq.size());
intvector number_of_add_operands(expanded_seq.size());
- int number_of_adds = 0;
- int number_of_expanded_terms = 1;
+ size_t number_of_adds = 0;
+ size_t number_of_expanded_terms = 1;
- unsigned current_position = 0;
+ size_t current_position = 0;
exvector::const_iterator last = expanded_seq.end();
for (exvector::const_iterator cit=expanded_seq.begin(); cit!=last; ++cit) {
if (is_exactly_a<add>(*cit)) {
positions_of_adds[number_of_adds] = current_position;
- unsigned num_ops = cit->nops();
+ size_t num_ops = cit->nops();
number_of_add_operands[number_of_adds] = num_ops;
number_of_expanded_terms *= num_ops;
number_of_adds++;
while (true) {
exvector term = expanded_seq;
- for (int i=0; i<number_of_adds; i++)
+ for (size_t i=0; i<number_of_adds; i++)
term[positions_of_adds[i]] = expanded_seq[positions_of_adds[i]].op(k[i]);
distrseq.push_back((new ncmul(term, true))->
setflag(status_flags::dynallocated | (options == 0 ? status_flags::expanded : 0)));
return _ex0;
}
-unsigned ncmul::count_factors(const ex & e) const
+size_t ncmul::count_factors(const ex & e) const
{
- if ((is_ex_exactly_of_type(e,mul)&&(e.return_type()!=return_types::commutative))||
- (is_ex_exactly_of_type(e,ncmul))) {
- unsigned factors=0;
- for (unsigned i=0; i<e.nops(); i++)
+ if ((is_exactly_a<mul>(e)&&(e.return_type()!=return_types::commutative))||
+ (is_exactly_a<ncmul>(e))) {
+ size_t factors=0;
+ for (size_t i=0; i<e.nops(); i++)
factors += count_factors(e.op(i));
return factors;
void ncmul::append_factors(exvector & v, const ex & e) const
{
- if ((is_ex_exactly_of_type(e,mul)&&(e.return_type()!=return_types::commutative))||
- (is_ex_exactly_of_type(e,ncmul))) {
- for (unsigned i=0; i<e.nops(); i++)
- append_factors(v,e.op(i));
+ if ((is_exactly_a<mul>(e)&&(e.return_type()!=return_types::commutative))||
+ (is_exactly_a<ncmul>(e))) {
+ for (size_t i=0; i<e.nops(); i++)
+ append_factors(v, e.op(i));
} else
v.push_back(e);
}
* - ncmul() -> 1
* - ncmul(...,c1,...,c2,...) -> *(c1,c2,ncmul(...)) (pull out commutative elements)
* - ncmul(x1,y1,x2,y2) -> *(ncmul(x1,x2),ncmul(y1,y2)) (collect elements of same type)
- * - ncmul(x1,x2,x3,...) -> x::simplify_ncmul(x1,x2,x3,...)
+ * - ncmul(x1,x2,x3,...) -> x::eval_ncmul(x1,x2,x3,...)
*
* @param level cut-off in recursive evaluation */
ex ncmul::eval(int level) const
// ncmul(...,*(x1,x2),...,ncmul(x3,x4),...) ->
// ncmul(...,x1,x2,...,x3,x4,...) (associativity)
- unsigned factors = 0;
+ size_t factors = 0;
exvector::const_iterator cit = evaledseq.begin(), citend = evaledseq.end();
while (cit != citend)
factors += count_factors(*cit++);
// determine return types
unsignedvector rettypes;
rettypes.reserve(assocseq.size());
- unsigned i = 0;
- unsigned count_commutative=0;
- unsigned count_noncommutative=0;
- unsigned count_noncommutative_composite=0;
+ size_t i = 0;
+ size_t count_commutative=0;
+ size_t count_noncommutative=0;
+ size_t count_noncommutative_composite=0;
cit = assocseq.begin(); citend = assocseq.end();
while (cit != citend) {
switch (rettypes[i] = cit->return_type()) {
commutativeseq.reserve(count_commutative+1);
exvector noncommutativeseq;
noncommutativeseq.reserve(assocseq.size()-count_commutative);
- unsigned num = assocseq.size();
- for (unsigned i=0; i<num; ++i) {
+ size_t num = assocseq.size();
+ for (size_t i=0; i<num; ++i) {
if (rettypes[i]==return_types::commutative)
commutativeseq.push_back(assocseq[i]);
else
// elements in assocseq
GINAC_ASSERT(count_commutative==0);
- unsigned assoc_num = assocseq.size();
+ size_t assoc_num = assocseq.size();
exvectorvector evv;
unsignedvector rttinfos;
evv.reserve(assoc_num);
cit = assocseq.begin(), citend = assocseq.end();
while (cit != citend) {
unsigned ti = cit->return_type_tinfo();
- unsigned rtt_num = rttinfos.size();
+ size_t rtt_num = rttinfos.size();
// search type in vector of known types
for (i=0; i<rtt_num; ++i) {
if (ti == rttinfos[i]) {
++cit;
}
- unsigned evv_num = evv.size();
+ size_t evv_num = evv.size();
#ifdef DO_GINAC_ASSERT
GINAC_ASSERT(evv_num == rttinfos.size());
GINAC_ASSERT(evv_num > 0);
- unsigned s=0;
+ size_t s=0;
for (i=0; i<evv_num; ++i)
s += evv[i].size();
GINAC_ASSERT(s == assoc_num);
// if all elements are of same type, simplify the string
if (evv_num == 1)
- return evv[0][0].simplify_ncmul(evv[0]);
+ return evv[0][0].eval_ncmul(evv[0]);
exvector splitseq;
splitseq.reserve(evv_num);
status_flags::evaluated);
}
-ex ncmul::evalm(void) const
+ex ncmul::evalm() const
{
// Evaluate children first
exvector *s = new exvector;
// If there are only matrices, simply multiply them
it = s->begin(); itend = s->end();
- if (is_ex_of_type(*it, matrix)) {
+ if (is_a<matrix>(*it)) {
matrix prod(ex_to<matrix>(*it));
it++;
while (it != itend) {
- if (!is_ex_of_type(*it, matrix))
+ if (!is_a<matrix>(*it))
goto no_matrix;
prod = prod.mul(ex_to<matrix>(*it));
it++;
return (new ncmul(s))->setflag(status_flags::dynallocated);
}
-ex ncmul::thisexprseq(const exvector & v) const
+ex ncmul::thiscontainer(const exvector & v) const
{
return (new ncmul(v))->setflag(status_flags::dynallocated);
}
-ex ncmul::thisexprseq(exvector * vp) const
+ex ncmul::thiscontainer(exvector * vp) const
{
return (new ncmul(vp))->setflag(status_flags::dynallocated);
}
* @see ex::diff */
ex ncmul::derivative(const symbol & s) const
{
- unsigned num = seq.size();
+ size_t num = seq.size();
exvector addseq;
addseq.reserve(num);
// D(a*b*c) = D(a)*b*c + a*D(b)*c + a*b*D(c)
exvector ncmulseq = seq;
- for (unsigned i=0; i<num; ++i) {
+ for (size_t i=0; i<num; ++i) {
ex e = seq[i].diff(s);
e.swap(ncmulseq[i]);
addseq.push_back((new ncmul(ncmulseq))->setflag(status_flags::dynallocated));
return inherited::compare_same_type(other);
}
-unsigned ncmul::return_type(void) const
+unsigned ncmul::return_type() const
{
if (seq.empty())
return return_types::commutative;
return all_commutative ? return_types::commutative : return_types::noncommutative;
}
-unsigned ncmul::return_type_tinfo(void) const
+unsigned ncmul::return_type_tinfo() const
{
if (seq.empty())
return tinfo_key;
return s;
}
-const exvector & ncmul::get_factors(void) const
+const exvector & ncmul::get_factors() const
{
return seq;
}
// friend functions
//////////
-ex nonsimplified_ncmul(const exvector & v)
+ex reeval_ncmul(const exvector & v)
{
return (new ncmul(v))->setflag(status_flags::dynallocated);
}
-ex simplified_ncmul(const exvector & v)
+ex hold_ncmul(const exvector & v)
{
if (v.empty())
return _ex1;
GINAC_DECLARE_REGISTERED_CLASS(ncmul, exprseq)
friend class power;
- friend ex nonsimplified_ncmul(const exvector & v);
- friend ex simplified_ncmul(const exvector & v);
+ friend ex reeval_ncmul(const exvector & v);
+ friend ex hold_ncmul(const exvector & v);
// member functions
// functions overriding virtual functions from base classes
public:
void print(const print_context & c, unsigned level = 0) const;
- unsigned precedence(void) const {return 50;}
+ unsigned precedence() const {return 50;}
bool info(unsigned inf) const;
int degree(const ex & s) const;
int ldegree(const ex & s) const;
ex expand(unsigned options=0) const;
ex coeff(const ex & s, int n=1) const;
ex eval(int level=0) const;
- ex evalm(void) const;
- exvector get_free_indices(void) const;
- ex thisexprseq(const exvector & v) const;
- ex thisexprseq(exvector * vp) const;
+ ex evalm() const;
+ exvector get_free_indices() const;
+ ex thiscontainer(const exvector & v) const;
+ ex thiscontainer(exvector * vp) const;
+
protected:
ex derivative(const symbol & s) const;
- unsigned return_type(void) const;
- unsigned return_type_tinfo(void) const;
+ unsigned return_type() const;
+ unsigned return_type_tinfo() const;
// new virtual functions which can be overridden by derived classes
// none
// non-virtual functions in this class
protected:
- unsigned count_factors(const ex & e) const;
+ size_t count_factors(const ex & e) const;
void append_factors(exvector & v, const ex & e) const;
exvector expandchildren(unsigned options) const;
public:
- const exvector & get_factors(void) const;
+ const exvector & get_factors() const;
};
// friend funtions
-ex nonsimplified_ncmul(const exvector & v);
-ex simplified_ncmul(const exvector & v);
+ex reeval_ncmul(const exvector & v);
+ex hold_ncmul(const exvector & v);
// utility functions
#include "numeric.h"
#include "power.h"
#include "relational.h"
+#include "operators.h"
#include "matrix.h"
#include "pseries.h"
#include "symbol.h"
x = &ex_to<symbol>(e);
return true;
} else if (is_exactly_a<add>(e) || is_exactly_a<mul>(e)) {
- for (unsigned i=0; i<e.nops(); i++)
+ for (size_t i=0; i<e.nops(); i++)
if (get_first_symbol(e.op(i), x))
return true;
} else if (is_exactly_a<power>(e)) {
int max_deg;
/** Maximum number of terms of leading coefficient of symbol in both polynomials */
- int max_lcnops;
+ size_t max_lcnops;
/** Commparison operator for sorting */
bool operator<(const sym_desc &x) const
if (is_a<symbol>(e)) {
add_symbol(&ex_to<symbol>(e), v);
} else if (is_exactly_a<add>(e) || is_exactly_a<mul>(e)) {
- for (unsigned i=0; i<e.nops(); i++)
+ for (size_t i=0; i<e.nops(); i++)
collect_symbols(e.op(i), v);
} else if (is_exactly_a<power>(e)) {
collect_symbols(e.op(0), v);
++it;
}
std::sort(v.begin(), v.end());
+
#if 0
std::clog << "Symbols:\n";
it = v.begin(); itend = v.end();
return lcm(ex_to<numeric>(e).denom(), l);
else if (is_exactly_a<add>(e)) {
numeric c = _num1;
- for (unsigned i=0; i<e.nops(); i++)
+ for (size_t i=0; i<e.nops(); i++)
c = lcmcoeff(e.op(i), c);
return lcm(c, l);
} else if (is_exactly_a<mul>(e)) {
numeric c = _num1;
- for (unsigned i=0; i<e.nops(); i++)
+ for (size_t i=0; i<e.nops(); i++)
c *= lcmcoeff(e.op(i), _num1);
return lcm(c, l);
} else if (is_exactly_a<power>(e)) {
static ex multiply_lcm(const ex &e, const numeric &lcm)
{
if (is_exactly_a<mul>(e)) {
- unsigned num = e.nops();
+ size_t num = e.nops();
exvector v; v.reserve(num + 1);
numeric lcm_accum = _num1;
- for (unsigned i=0; i<e.nops(); i++) {
+ for (size_t i=0; i<num; i++) {
numeric op_lcm = lcmcoeff(e.op(i), _num1);
v.push_back(multiply_lcm(e.op(i), op_lcm));
lcm_accum *= op_lcm;
v.push_back(lcm / lcm_accum);
return (new mul(v))->setflag(status_flags::dynallocated);
} else if (is_exactly_a<add>(e)) {
- unsigned num = e.nops();
+ size_t num = e.nops();
exvector v; v.reserve(num);
- for (unsigned i=0; i<num; i++)
+ for (size_t i=0; i<num; i++)
v.push_back(multiply_lcm(e.op(i), lcm));
return (new add(v))->setflag(status_flags::dynallocated);
} else if (is_exactly_a<power>(e)) {
*
* @param e expanded polynomial
* @return integer content */
-numeric ex::integer_content(void) const
+numeric ex::integer_content() const
{
- GINAC_ASSERT(bp!=0);
return bp->integer_content();
}
-numeric basic::integer_content(void) const
+numeric basic::integer_content() const
{
return _num1;
}
-numeric numeric::integer_content(void) const
+numeric numeric::integer_content() const
{
return abs(*this);
}
-numeric add::integer_content(void) const
+numeric add::integer_content() const
{
epvector::const_iterator it = seq.begin();
epvector::const_iterator itend = seq.end();
return c;
}
-numeric mul::integer_content(void) const
+numeric mul::integer_content() const
{
#ifdef DO_GINAC_ASSERT
epvector::const_iterator it = seq.begin();
* GCD of multivariate polynomials
*/
-/** Compute GCD of polynomials in Q[X] using the Euclidean algorithm (not
- * really suited for multivariate GCDs). This function is only provided for
- * testing purposes.
- *
- * @param a first multivariate polynomial
- * @param b second multivariate polynomial
- * @param x pointer to symbol (main variable) in which to compute the GCD in
- * @return the GCD as a new expression
- * @see gcd */
-
-static ex eu_gcd(const ex &a, const ex &b, const symbol *x)
-{
-//std::clog << "eu_gcd(" << a << "," << b << ")\n";
-
- // Sort c and d so that c has higher degree
- ex c, d;
- int adeg = a.degree(*x), bdeg = b.degree(*x);
- if (adeg >= bdeg) {
- c = a;
- d = b;
- } else {
- c = b;
- d = a;
- }
-
- // Normalize in Q[x]
- c = c / c.lcoeff(*x);
- d = d / d.lcoeff(*x);
-
- // Euclidean algorithm
- ex r;
- for (;;) {
-//std::clog << " d = " << d << endl;
- r = rem(c, d, *x, false);
- if (r.is_zero())
- return d / d.lcoeff(*x);
- c = d;
- d = r;
- }
-}
-
-
-/** Compute GCD of multivariate polynomials using the Euclidean PRS algorithm
- * with pseudo-remainders ("World's Worst GCD Algorithm", staying in Z[X]).
- * This function is only provided for testing purposes.
- *
- * @param a first multivariate polynomial
- * @param b second multivariate polynomial
- * @param x pointer to symbol (main variable) in which to compute the GCD in
- * @return the GCD as a new expression
- * @see gcd */
-
-static ex euprem_gcd(const ex &a, const ex &b, const symbol *x)
-{
-//std::clog << "euprem_gcd(" << a << "," << b << ")\n";
-
- // Sort c and d so that c has higher degree
- ex c, d;
- int adeg = a.degree(*x), bdeg = b.degree(*x);
- if (adeg >= bdeg) {
- c = a;
- d = b;
- } else {
- c = b;
- d = a;
- }
-
- // Calculate GCD of contents
- ex gamma = gcd(c.content(*x), d.content(*x), NULL, NULL, false);
-
- // Euclidean algorithm with pseudo-remainders
- ex r;
- for (;;) {
-//std::clog << " d = " << d << endl;
- r = prem(c, d, *x, false);
- if (r.is_zero())
- return d.primpart(*x) * gamma;
- c = d;
- d = r;
- }
-}
-
-
-/** Compute GCD of multivariate polynomials using the primitive Euclidean
- * PRS algorithm (complete content removal at each step). This function is
- * only provided for testing purposes.
- *
- * @param a first multivariate polynomial
- * @param b second multivariate polynomial
- * @param x pointer to symbol (main variable) in which to compute the GCD in
- * @return the GCD as a new expression
- * @see gcd */
-
-static ex peu_gcd(const ex &a, const ex &b, const symbol *x)
-{
-//std::clog << "peu_gcd(" << a << "," << b << ")\n";
-
- // Sort c and d so that c has higher degree
- ex c, d;
- int adeg = a.degree(*x), bdeg = b.degree(*x);
- int ddeg;
- if (adeg >= bdeg) {
- c = a;
- d = b;
- ddeg = bdeg;
- } else {
- c = b;
- d = a;
- ddeg = adeg;
- }
-
- // Remove content from c and d, to be attached to GCD later
- ex cont_c = c.content(*x);
- ex cont_d = d.content(*x);
- ex gamma = gcd(cont_c, cont_d, NULL, NULL, false);
- if (ddeg == 0)
- return gamma;
- c = c.primpart(*x, cont_c);
- d = d.primpart(*x, cont_d);
-
- // Euclidean algorithm with content removal
- ex r;
- for (;;) {
-//std::clog << " d = " << d << endl;
- r = prem(c, d, *x, false);
- if (r.is_zero())
- return gamma * d;
- c = d;
- d = r.primpart(*x);
- }
-}
-
-
-/** Compute GCD of multivariate polynomials using the reduced PRS algorithm.
- * This function is only provided for testing purposes.
- *
- * @param a first multivariate polynomial
- * @param b second multivariate polynomial
- * @param x pointer to symbol (main variable) in which to compute the GCD in
- * @return the GCD as a new expression
- * @see gcd */
-
-static ex red_gcd(const ex &a, const ex &b, const symbol *x)
-{
-//std::clog << "red_gcd(" << a << "," << b << ")\n";
-
- // Sort c and d so that c has higher degree
- ex c, d;
- int adeg = a.degree(*x), bdeg = b.degree(*x);
- int cdeg, ddeg;
- if (adeg >= bdeg) {
- c = a;
- d = b;
- cdeg = adeg;
- ddeg = bdeg;
- } else {
- c = b;
- d = a;
- cdeg = bdeg;
- ddeg = adeg;
- }
-
- // Remove content from c and d, to be attached to GCD later
- ex cont_c = c.content(*x);
- ex cont_d = d.content(*x);
- ex gamma = gcd(cont_c, cont_d, NULL, NULL, false);
- if (ddeg == 0)
- return gamma;
- c = c.primpart(*x, cont_c);
- d = d.primpart(*x, cont_d);
-
- // First element of divisor sequence
- ex r, ri = _ex1;
- int delta = cdeg - ddeg;
-
- for (;;) {
- // Calculate polynomial pseudo-remainder
-//std::clog << " d = " << d << endl;
- r = prem(c, d, *x, false);
- if (r.is_zero())
- return gamma * d.primpart(*x);
- c = d;
- cdeg = ddeg;
-
- if (!divide(r, pow(ri, delta), d, false))
- throw(std::runtime_error("invalid expression in red_gcd(), division failed"));
- ddeg = d.degree(*x);
- if (ddeg == 0) {
- if (is_exactly_a<numeric>(r))
- return gamma;
- else
- return gamma * r.primpart(*x);
- }
-
- ri = c.expand().lcoeff(*x);
- delta = cdeg - ddeg;
- }
-}
-
-
/** Compute GCD of multivariate polynomials using the subresultant PRS
* algorithm. This function is used internally by gcd().
*
static ex sr_gcd(const ex &a, const ex &b, sym_desc_vec::const_iterator var)
{
-//std::clog << "sr_gcd(" << a << "," << b << ")\n";
#if STATISTICS
sr_gcd_called++;
#endif
return gamma;
c = c.primpart(x, cont_c);
d = d.primpart(x, cont_d);
-//std::clog << " content " << gamma << " removed, continuing with sr_gcd(" << c << "," << d << ")\n";
// First element of subresultant sequence
ex r = _ex0, ri = _ex1, psi = _ex1;
int delta = cdeg - ddeg;
for (;;) {
+
// Calculate polynomial pseudo-remainder
-//std::clog << " start of loop, psi = " << psi << ", calculating pseudo-remainder...\n";
-//std::clog << " d = " << d << endl;
r = prem(c, d, x, false);
if (r.is_zero())
return gamma * d.primpart(x);
+
c = d;
cdeg = ddeg;
-//std::clog << " dividing...\n";
if (!divide_in_z(r, ri * pow(psi, delta), d, var))
throw(std::runtime_error("invalid expression in sr_gcd(), division failed"));
ddeg = d.degree(x);
}
// Next element of subresultant sequence
-//std::clog << " calculating next subresultant...\n";
ri = c.expand().lcoeff(x);
if (delta == 1)
psi = ri;
* @param e expanded multivariate polynomial
* @return maximum coefficient
* @see heur_gcd */
-numeric ex::max_coefficient(void) const
+numeric ex::max_coefficient() const
{
- GINAC_ASSERT(bp!=0);
return bp->max_coefficient();
}
/** Implementation ex::max_coefficient().
* @see heur_gcd */
-numeric basic::max_coefficient(void) const
+numeric basic::max_coefficient() const
{
return _num1;
}
-numeric numeric::max_coefficient(void) const
+numeric numeric::max_coefficient() const
{
return abs(*this);
}
-numeric add::max_coefficient(void) const
+numeric add::max_coefficient() const
{
epvector::const_iterator it = seq.begin();
epvector::const_iterator itend = seq.end();
return cur_max;
}
-numeric mul::max_coefficient(void) const
+numeric mul::max_coefficient() const
{
#ifdef DO_GINAC_ASSERT
epvector::const_iterator it = seq.begin();
* @exception gcdheu_failed() */
static ex heur_gcd(const ex &a, const ex &b, ex *ca, ex *cb, sym_desc_vec::const_iterator var)
{
-//std::clog << "heur_gcd(" << a << "," << b << ")\n";
#if STATISTICS
heur_gcd_called++;
#endif
// 6 tries maximum
for (int t=0; t<6; t++) {
if (xi.int_length() * maxdeg > 100000) {
-//std::clog << "giving up heur_gcd, xi.int_length = " << xi.int_length() << ", maxdeg = " << maxdeg << std::endl;
throw gcdheu_failed();
}
else
return g;
}
-#if 0
- cp = interpolate(cp, xi, x);
- if (divide_in_z(cp, p, g, var)) {
- if (divide_in_z(g, q, cb ? *cb : dummy, var)) {
- g *= gc;
- if (ca)
- *ca = cp;
- ex lc = g.lcoeff(x);
- if (is_exactly_a<numeric>(lc) && ex_to<numeric>(lc).is_negative())
- return -g;
- else
- return g;
- }
- }
- cq = interpolate(cq, xi, x);
- if (divide_in_z(cq, q, g, var)) {
- if (divide_in_z(g, p, ca ? *ca : dummy, var)) {
- g *= gc;
- if (cb)
- *cb = cq;
- ex lc = g.lcoeff(x);
- if (is_exactly_a<numeric>(lc) && ex_to<numeric>(lc).is_negative())
- return -g;
- else
- return g;
- }
- }
-#endif
}
// Next evaluation point
* @return the GCD as a new expression */
ex gcd(const ex &a, const ex &b, ex *ca, ex *cb, bool check_args)
{
-//std::clog << "gcd(" << a << "," << b << ")\n";
#if STATISTICS
gcd_called++;
#endif
if (is_exactly_a<mul>(b) && b.nops() > a.nops())
goto factored_b;
factored_a:
- unsigned num = a.nops();
+ size_t num = a.nops();
exvector g; g.reserve(num);
exvector acc_ca; acc_ca.reserve(num);
ex part_b = b;
- for (unsigned i=0; i<num; i++) {
+ for (size_t i=0; i<num; i++) {
ex part_ca, part_cb;
g.push_back(gcd(a.op(i), part_b, &part_ca, &part_cb, check_args));
acc_ca.push_back(part_ca);
if (is_exactly_a<mul>(a) && a.nops() > b.nops())
goto factored_a;
factored_b:
- unsigned num = b.nops();
+ size_t num = b.nops();
exvector g; g.reserve(num);
exvector acc_cb; acc_cb.reserve(num);
ex part_a = a;
- for (unsigned i=0; i<num; i++) {
+ for (size_t i=0; i<num; i++) {
ex part_ca, part_cb;
g.push_back(gcd(part_a, b.op(i), &part_ca, &part_cb, check_args));
acc_cb.push_back(part_cb);
int min_ldeg = std::min(ldeg_a,ldeg_b);
if (min_ldeg > 0) {
ex common = power(x, min_ldeg);
-//std::clog << "trivial common factor " << common << std::endl;
return gcd((aex / common).expand(), (bex / common).expand(), ca, cb, false) * common;
}
// Try to eliminate variables
if (var->deg_a == 0) {
-//std::clog << "eliminating variable " << x << " from b" << std::endl;
ex c = bex.content(x);
ex g = gcd(aex, c, ca, cb, false);
if (cb)
*cb *= bex.unit(x) * bex.primpart(x, c);
return g;
} else if (var->deg_b == 0) {
-//std::clog << "eliminating variable " << x << " from a" << std::endl;
ex c = aex.content(x);
ex g = gcd(c, bex, ca, cb, false);
if (ca)
return g;
}
- ex g;
-#if 1
// Try heuristic algorithm first, fall back to PRS if that failed
+ ex g;
try {
g = heur_gcd(aex, bex, ca, cb, var);
} catch (gcdheu_failed) {
g = fail();
}
if (is_exactly_a<fail>(g)) {
-//std::clog << "heuristics failed" << std::endl;
#if STATISTICS
heur_gcd_failed++;
#endif
-#endif
-// g = heur_gcd(aex, bex, ca, cb, var);
-// g = eu_gcd(aex, bex, &x);
-// g = euprem_gcd(aex, bex, &x);
-// g = peu_gcd(aex, bex, &x);
-// g = red_gcd(aex, bex, &x);
g = sr_gcd(aex, bex, var);
if (g.is_equal(_ex1)) {
// Keep cofactors factored if possible
if (cb)
divide(bex, g, *cb, false);
}
-#if 1
} else {
if (g.is_equal(_ex1)) {
// Keep cofactors factored if possible
*cb = b;
}
}
-#endif
+
return g;
}
}
// Find the symbol to factor in at this stage
- if (!is_ex_of_type(args.op(0), symbol))
+ if (!is_a<symbol>(args.op(0)))
throw (std::runtime_error("sqrfree(): invalid factorization variable"));
const symbol &x = ex_to<symbol>(args.op(0));
// Factorize denominator and compute cofactors
exvector yun = sqrfree_yun(denom, x);
//clog << "yun factors: " << exprseq(yun) << endl;
- unsigned num_yun = yun.size();
+ size_t num_yun = yun.size();
exvector factor; factor.reserve(num_yun);
exvector cofac; cofac.reserve(num_yun);
- for (unsigned i=0; i<num_yun; i++) {
+ for (size_t i=0; i<num_yun; i++) {
if (!yun[i].is_equal(_ex1)) {
- for (unsigned j=0; j<=i; j++) {
+ for (size_t j=0; j<=i; j++) {
factor.push_back(pow(yun[i], j+1));
ex prod = _ex1;
- for (unsigned k=0; k<num_yun; k++) {
+ for (size_t k=0; k<num_yun; k++) {
if (k == i)
prod *= pow(yun[k], i-j);
else
}
}
}
- unsigned num_factors = factor.size();
+ size_t num_factors = factor.size();
//clog << "factors : " << exprseq(factor) << endl;
//clog << "cofactors: " << exprseq(cofac) << endl;
matrix sys(max_denom_deg + 1, num_factors);
matrix rhs(max_denom_deg + 1, 1);
for (int i=0; i<=max_denom_deg; i++) {
- for (unsigned j=0; j<num_factors; j++)
+ for (size_t j=0; j<num_factors; j++)
sys(i, j) = cofac[j].coeff(x, i);
rhs(i, 0) = red_numer.coeff(x, i);
}
// Solve resulting linear system
matrix vars(num_factors, 1);
- for (unsigned i=0; i<num_factors; i++)
+ for (size_t i=0; i<num_factors; i++)
vars(i, 0) = symbol();
matrix sol = sys.solve(vars, rhs);
// Sum up decomposed fractions
ex sum = 0;
- for (unsigned i=0; i<num_factors; i++)
+ for (size_t i=0; i<num_factors; i++)
sum += sol(i, 0) / factor[i];
return red_poly + sum;
static ex replace_with_symbol(const ex &e, lst &sym_lst, lst &repl_lst)
{
// Expression already in repl_lst? Then return the assigned symbol
- for (unsigned i=0; i<repl_lst.nops(); i++)
- if (repl_lst.op(i).is_equal(e))
- return sym_lst.op(i);
+ lst::const_iterator its, itr;
+ for (its = sym_lst.begin(), itr = repl_lst.begin(); itr != repl_lst.end(); ++its, ++itr)
+ if (itr->is_equal(e))
+ return *its;
// Otherwise create new symbol and add to list, taking care that the
// replacement expression doesn't contain symbols from the sym_lst
/** Create a symbol for replacing the expression "e" (or return a previously
* assigned symbol). An expression of the form "symbol == expression" is added
* to repl_lst and the symbol is returned.
- * @see basic::to_rational */
+ * @see basic::to_rational
+ * @see basic::to_polynomial */
static ex replace_with_symbol(const ex &e, lst &repl_lst)
{
// Expression already in repl_lst? Then return the assigned symbol
- for (unsigned i=0; i<repl_lst.nops(); i++)
- if (repl_lst.op(i).op(1).is_equal(e))
- return repl_lst.op(i).op(0);
+ for (lst::const_iterator it = repl_lst.begin(); it != repl_lst.end(); ++it)
+ if (it->op(1).is_equal(e))
+ return it->op(0);
// Otherwise create new symbol and add to list, taking care that the
// replacement expression doesn't contain symbols from the sym_lst
*
* @see ex::normal
* @return numerator */
-ex ex::numer(void) const
+ex ex::numer() const
{
lst sym_lst, repl_lst;
*
* @see ex::normal
* @return denominator */
-ex ex::denom(void) const
+ex ex::denom() const
{
lst sym_lst, repl_lst;
*
* @see ex::normal
* @return a list [numerator, denominator] */
-ex ex::numer_denom(void) const
+ex ex::numer_denom() const
{
lst sym_lst, repl_lst;
/** Rationalization of non-rational functions.
- * This function converts a general expression to a rational polynomial
+ * This function converts a general expression to a rational function
* by replacing all non-rational subexpressions (like non-rational numbers,
* non-integer powers or functions like sin(), cos() etc.) to temporary
* symbols. This makes it possible to use functions like gcd() and divide()
*
* @param repl_lst collects a list of all temporary symbols and their replacements
* @return rationalized expression */
+ex ex::to_rational(lst &repl_lst) const
+{
+ return bp->to_rational(repl_lst);
+}
+
+ex ex::to_polynomial(lst &repl_lst) const
+{
+ return bp->to_polynomial(repl_lst);
+}
+
+
+/** Default implementation of ex::to_rational(). This replaces the object with
+ * a temporary symbol. */
ex basic::to_rational(lst &repl_lst) const
{
return replace_with_symbol(*this, repl_lst);
}
+ex basic::to_polynomial(lst &repl_lst) const
+{
+ return replace_with_symbol(*this, repl_lst);
+}
+
/** Implementation of ex::to_rational() for symbols. This returns the
* unmodified symbol. */
return *this;
}
+/** Implementation of ex::to_polynomial() for symbols. This returns the
+ * unmodified symbol. */
+ex symbol::to_polynomial(lst &repl_lst) const
+{
+ return *this;
+}
+
/** Implementation of ex::to_rational() for a numeric. It splits complex
* numbers into re+I*im and replaces I and non-rational real numbers with a
return *this;
}
+/** Implementation of ex::to_polynomial() for a numeric. It splits complex
+ * numbers into re+I*im and replaces I and non-integer real numbers with a
+ * temporary symbol. */
+ex numeric::to_polynomial(lst &repl_lst) const
+{
+ if (is_real()) {
+ if (!is_integer())
+ return replace_with_symbol(*this, repl_lst);
+ } else { // complex
+ numeric re = real();
+ numeric im = imag();
+ ex re_ex = re.is_integer() ? re : replace_with_symbol(re, repl_lst);
+ ex im_ex = im.is_integer() ? im : replace_with_symbol(im, repl_lst);
+ return re_ex + im_ex * replace_with_symbol(I, repl_lst);
+ }
+ return *this;
+}
+
/** Implementation of ex::to_rational() for powers. It replaces non-integer
* powers by temporary symbols. */
return replace_with_symbol(*this, repl_lst);
}
+/** Implementation of ex::to_polynomial() for powers. It replaces non-posint
+ * powers by temporary symbols. */
+ex power::to_polynomial(lst &repl_lst) const
+{
+ if (exponent.info(info_flags::posint))
+ return power(basis.to_rational(repl_lst), exponent);
+ else
+ return replace_with_symbol(*this, repl_lst);
+}
+
/** Implementation of ex::to_rational() for expairseqs. */
ex expairseq::to_rational(lst &repl_lst) const
return thisexpairseq(s, default_overall_coeff());
}
+/** Implementation of ex::to_polynomial() for expairseqs. */
+ex expairseq::to_polynomial(lst &repl_lst) const
+{
+ epvector s;
+ s.reserve(seq.size());
+ epvector::const_iterator i = seq.begin(), end = seq.end();
+ while (i != end) {
+ s.push_back(split_ex_to_pair(recombine_pair_to_ex(*i).to_polynomial(repl_lst)));
+ ++i;
+ }
+ ex oc = overall_coeff.to_polynomial(repl_lst);
+ if (oc.info(info_flags::numeric))
+ return thisexpairseq(s, overall_coeff);
+ else
+ s.push_back(combine_ex_with_coeff_to_pair(oc, _ex1));
+ return thisexpairseq(s, default_overall_coeff());
+}
+
/** Remove the common factor in the terms of a sum 'e' by calculating the GCD,
* and multiply it into the expression 'factor' (which needs to be initialized
{
if (is_exactly_a<add>(e)) {
- unsigned num = e.nops();
+ size_t num = e.nops();
exvector terms; terms.reserve(num);
ex gc;
// Find the common GCD
- for (unsigned i=0; i<num; i++) {
- ex x = e.op(i).to_rational(repl);
+ for (size_t i=0; i<num; i++) {
+ ex x = e.op(i).to_polynomial(repl);
if (is_exactly_a<add>(x) || is_exactly_a<mul>(x)) {
ex f = 1;
factor *= gc;
// Now divide all terms by the GCD
- for (unsigned i=0; i<num; i++) {
+ for (size_t i=0; i<num; i++) {
ex x;
// Try to avoid divide() because it expands the polynomial
ex &t = terms[i];
if (is_exactly_a<mul>(t)) {
- for (unsigned j=0; j<t.nops(); j++) {
+ for (size_t j=0; j<t.nops(); j++) {
if (t.op(j).is_equal(gc)) {
exvector v; v.reserve(t.nops());
- for (unsigned k=0; k<t.nops(); k++) {
+ for (size_t k=0; k<t.nops(); k++) {
if (k == j)
v.push_back(_ex1);
else
} else if (is_exactly_a<mul>(e)) {
- unsigned num = e.nops();
+ size_t num = e.nops();
exvector v; v.reserve(num);
- for (unsigned i=0; i<num; i++)
+ for (size_t i=0; i<num; i++)
v.push_back(find_common_factor(e.op(i), factor, repl));
return (new mul(v))->setflag(status_flags::dynallocated);
} else if (is_exactly_a<power>(e)) {
- ex x = e.to_rational(repl);
- if (is_exactly_a<power>(x) && x.op(1).info(info_flags::negative))
- return replace_with_symbol(x, repl);
- else
- return x;
+ return e.to_polynomial(repl);
} else
return e;
#include <stdexcept>
#include <string>
#include <sstream>
+#include <limits>
#include "numeric.h"
#include "ex.h"
#include "print.h"
+#include "operators.h"
#include "archive.h"
#include "tostring.h"
#include "utils.h"
GINAC_IMPLEMENT_REGISTERED_CLASS(numeric, basic)
//////////
-// default ctor, dtor, copy ctor, assignment operator and helpers
+// default constructor
//////////
/** default ctor. Numerically it initializes to an integer zero. */
setflag(status_flags::evaluated | status_flags::expanded);
}
-void numeric::copy(const numeric &other)
-{
- inherited::copy(other);
- value = other.value;
-}
-
-DEFAULT_DESTROY(numeric)
-
//////////
-// other ctors
+// other constructors
//////////
// public
// archiving
//////////
-numeric::numeric(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
+numeric::numeric(const archive_node &n, lst &sym_lst) : inherited(n, sym_lst)
{
cln::cl_N ctorval = 0;
// Set precision
if (is_a<print_csrc_double>(c))
- c.s.precision(16);
+ c.s.precision(std::numeric_limits<double>::digits10 + 1);
else
- c.s.precision(7);
+ c.s.precision(std::numeric_limits<float>::digits10 + 1);
if (this->is_real()) {
* sign as a multiplicative factor. */
bool numeric::has(const ex &other) const
{
- if (!is_ex_exactly_of_type(other, numeric))
+ if (!is_exactly_a<numeric>(other))
return false;
const numeric &o = ex_to<numeric>(other);
if (this->is_equal(o) || this->is_equal(-o))
}
-unsigned numeric::calchash(void) const
+unsigned numeric::calchash() const
{
- // Use CLN's hashcode. Warning: It depends only on the number's value, not
- // its type or precision (i.e. a true equivalence relation on numbers). As
- // a consequence, 3 and 3.0 share the same hashvalue.
+ // Base computation of hashvalue on CLN's hashcode. Note: That depends
+ // only on the number's value, not its type or precision (i.e. a true
+ // equivalence relation on numbers). As a consequence, 3 and 3.0 share
+ // the same hashvalue. That shouldn't really matter, though.
setflag(status_flags::hash_calculated);
- return (hashvalue = cln::equal_hashcode(cln::the<cln::cl_N>(value)) | 0x80000000U);
+ hashvalue = golden_ratio_hash(cln::equal_hashcode(cln::the<cln::cl_N>(value)));
+ return hashvalue;
}
* a numeric object. */
const numeric numeric::add(const numeric &other) const
{
- // Efficiency shortcut: trap the neutral element by pointer.
- if (this==_num0_p)
- return other;
- else if (&other==_num0_p)
- return *this;
-
return numeric(cln::the<cln::cl_N>(value)+cln::the<cln::cl_N>(other.value));
}
* result as a numeric object. */
const numeric numeric::mul(const numeric &other) const
{
- // Efficiency shortcut: trap the neutral element by pointer.
- if (this==_num1_p)
- return other;
- else if (&other==_num1_p)
- return *this;
-
return numeric(cln::the<cln::cl_N>(value)*cln::the<cln::cl_N>(other.value));
}
* returns result as a numeric object. */
const numeric numeric::power(const numeric &other) const
{
- // Efficiency shortcut: trap the neutral exponent by pointer.
- if (&other==_num1_p)
+ // Shortcut for efficiency and numeric stability (as in 1.0 exponent):
+ // trap the neutral exponent.
+ if (&other==_num1_p || cln::equal(cln::the<cln::cl_N>(other.value),cln::the<cln::cl_N>(_num1.value)))
return *this;
if (cln::zerop(cln::the<cln::cl_N>(value))) {
}
+
+/** Numerical addition method. Adds argument to *this and returns result as
+ * a numeric object on the heap. Use internally only for direct wrapping into
+ * an ex object, where the result would end up on the heap anyways. */
const numeric &numeric::add_dyn(const numeric &other) const
{
- // Efficiency shortcut: trap the neutral element by pointer.
+ // Efficiency shortcut: trap the neutral element by pointer. This hack
+ // is supposed to keep the number of distinct numeric objects low.
if (this==_num0_p)
return other;
else if (&other==_num0_p)
return *this;
return static_cast<const numeric &>((new numeric(cln::the<cln::cl_N>(value)+cln::the<cln::cl_N>(other.value)))->
- setflag(status_flags::dynallocated));
+ setflag(status_flags::dynallocated));
}
+/** Numerical subtraction method. Subtracts argument from *this and returns
+ * result as a numeric object on the heap. Use internally only for direct
+ * wrapping into an ex object, where the result would end up on the heap
+ * anyways. */
const numeric &numeric::sub_dyn(const numeric &other) const
{
+ // Efficiency shortcut: trap the neutral exponent (first by pointer). This
+ // hack is supposed to keep the number of distinct numeric objects low.
+ if (&other==_num0_p || cln::zerop(cln::the<cln::cl_N>(other.value)))
+ return *this;
+
return static_cast<const numeric &>((new numeric(cln::the<cln::cl_N>(value)-cln::the<cln::cl_N>(other.value)))->
- setflag(status_flags::dynallocated));
+ setflag(status_flags::dynallocated));
}
+/** Numerical multiplication method. Multiplies *this and argument and returns
+ * result as a numeric object on the heap. Use internally only for direct
+ * wrapping into an ex object, where the result would end up on the heap
+ * anyways. */
const numeric &numeric::mul_dyn(const numeric &other) const
{
- // Efficiency shortcut: trap the neutral element by pointer.
+ // Efficiency shortcut: trap the neutral element by pointer. This hack
+ // is supposed to keep the number of distinct numeric objects low.
if (this==_num1_p)
return other;
else if (&other==_num1_p)
return *this;
return static_cast<const numeric &>((new numeric(cln::the<cln::cl_N>(value)*cln::the<cln::cl_N>(other.value)))->
- setflag(status_flags::dynallocated));
+ setflag(status_flags::dynallocated));
}
+/** Numerical division method. Divides *this by argument and returns result as
+ * a numeric object on the heap. Use internally only for direct wrapping
+ * into an ex object, where the result would end up on the heap
+ * anyways.
+ *
+ * @exception overflow_error (division by zero) */
const numeric &numeric::div_dyn(const numeric &other) const
{
+ // Efficiency shortcut: trap the neutral element by pointer. This hack
+ // is supposed to keep the number of distinct numeric objects low.
+ if (&other==_num1_p)
+ return *this;
if (cln::zerop(cln::the<cln::cl_N>(other.value)))
throw std::overflow_error("division by zero");
return static_cast<const numeric &>((new numeric(cln::the<cln::cl_N>(value)/cln::the<cln::cl_N>(other.value)))->
- setflag(status_flags::dynallocated));
+ setflag(status_flags::dynallocated));
}
+/** Numerical exponentiation. Raises *this to the power given as argument and
+ * returns result as a numeric object on the heap. Use internally only for
+ * direct wrapping into an ex object, where the result would end up on the
+ * heap anyways. */
const numeric &numeric::power_dyn(const numeric &other) const
{
- // Efficiency shortcut: trap the neutral exponent by pointer.
- if (&other==_num1_p)
+ // Efficiency shortcut: trap the neutral exponent (first try by pointer, then
+ // try harder, since calls to cln::expt() below may return amazing results for
+ // floating point exponent 1.0).
+ if (&other==_num1_p || cln::equal(cln::the<cln::cl_N>(other.value),cln::the<cln::cl_N>(_num1.value)))
return *this;
if (cln::zerop(cln::the<cln::cl_N>(value))) {
/** Inverse of a number. */
-const numeric numeric::inverse(void) const
+const numeric numeric::inverse() const
{
if (cln::zerop(cln::the<cln::cl_N>(value)))
throw std::overflow_error("numeric::inverse(): division by zero");
* csgn(x)==-1 for Re(x)<0 or Re(x)=0 and Im(x)<0.
*
* @see numeric::compare(const numeric &other) */
-int numeric::csgn(void) const
+int numeric::csgn() const
{
if (cln::zerop(cln::the<cln::cl_N>(value)))
return 0;
* to be compatible with our method csgn.
*
* @return csgn(*this-other)
- * @see numeric::csgn(void) */
+ * @see numeric::csgn() */
int numeric::compare(const numeric &other) const
{
// Comparing two real numbers?
/** True if object is zero. */
-bool numeric::is_zero(void) const
+bool numeric::is_zero() const
{
return cln::zerop(cln::the<cln::cl_N>(value));
}
/** True if object is not complex and greater than zero. */
-bool numeric::is_positive(void) const
+bool numeric::is_positive() const
{
- if (this->is_real())
+ if (cln::instanceof(value, cln::cl_R_ring)) // real?
return cln::plusp(cln::the<cln::cl_R>(value));
return false;
}
/** True if object is not complex and less than zero. */
-bool numeric::is_negative(void) const
+bool numeric::is_negative() const
{
- if (this->is_real())
+ if (cln::instanceof(value, cln::cl_R_ring)) // real?
return cln::minusp(cln::the<cln::cl_R>(value));
return false;
}
/** True if object is a non-complex integer. */
-bool numeric::is_integer(void) const
+bool numeric::is_integer() const
{
return cln::instanceof(value, cln::cl_I_ring);
}
/** True if object is an exact integer greater than zero. */
-bool numeric::is_pos_integer(void) const
+bool numeric::is_pos_integer() const
{
- return (this->is_integer() && cln::plusp(cln::the<cln::cl_I>(value)));
+ return (cln::instanceof(value, cln::cl_I_ring) && cln::plusp(cln::the<cln::cl_I>(value)));
}
/** True if object is an exact integer greater or equal zero. */
-bool numeric::is_nonneg_integer(void) const
+bool numeric::is_nonneg_integer() const
{
- return (this->is_integer() && !cln::minusp(cln::the<cln::cl_I>(value)));
+ return (cln::instanceof(value, cln::cl_I_ring) && !cln::minusp(cln::the<cln::cl_I>(value)));
}
/** True if object is an exact even integer. */
-bool numeric::is_even(void) const
+bool numeric::is_even() const
{
- return (this->is_integer() && cln::evenp(cln::the<cln::cl_I>(value)));
+ return (cln::instanceof(value, cln::cl_I_ring) && cln::evenp(cln::the<cln::cl_I>(value)));
}
/** True if object is an exact odd integer. */
-bool numeric::is_odd(void) const
+bool numeric::is_odd() const
{
- return (this->is_integer() && cln::oddp(cln::the<cln::cl_I>(value)));
+ return (cln::instanceof(value, cln::cl_I_ring) && cln::oddp(cln::the<cln::cl_I>(value)));
}
/** Probabilistic primality test.
*
* @return true if object is exact integer and prime. */
-bool numeric::is_prime(void) const
+bool numeric::is_prime() const
{
- return (this->is_integer() && cln::isprobprime(cln::the<cln::cl_I>(value)));
+ return (cln::instanceof(value, cln::cl_I_ring) // integer?
+ && cln::plusp(cln::the<cln::cl_I>(value)) // positive?
+ && cln::isprobprime(cln::the<cln::cl_I>(value)));
}
/** True if object is an exact rational number, may even be complex
* (denominator may be unity). */
-bool numeric::is_rational(void) const
+bool numeric::is_rational() const
{
return cln::instanceof(value, cln::cl_RA_ring);
}
/** True if object is a real integer, rational or float (but not complex). */
-bool numeric::is_real(void) const
+bool numeric::is_real() const
{
return cln::instanceof(value, cln::cl_R_ring);
}
/** True if object is element of the domain of integers extended by I, i.e. is
* of the form a+b*I, where a and b are integers. */
-bool numeric::is_cinteger(void) const
+bool numeric::is_cinteger() const
{
if (cln::instanceof(value, cln::cl_I_ring))
return true;
/** True if object is an exact rational number, may even be complex
* (denominator may be unity). */
-bool numeric::is_crational(void) const
+bool numeric::is_crational() const
{
if (cln::instanceof(value, cln::cl_RA_ring))
return true;
/** Converts numeric types to machine's int. You should check with
* is_integer() if the number is really an integer before calling this method.
* You may also consider checking the range first. */
-int numeric::to_int(void) const
+int numeric::to_int() const
{
GINAC_ASSERT(this->is_integer());
return cln::cl_I_to_int(cln::the<cln::cl_I>(value));
/** Converts numeric types to machine's long. You should check with
* is_integer() if the number is really an integer before calling this method.
* You may also consider checking the range first. */
-long numeric::to_long(void) const
+long numeric::to_long() const
{
GINAC_ASSERT(this->is_integer());
return cln::cl_I_to_long(cln::the<cln::cl_I>(value));
/** Converts numeric types to machine's double. You should check with is_real()
* if the number is really not complex before calling this method. */
-double numeric::to_double(void) const
+double numeric::to_double() const
{
GINAC_ASSERT(this->is_real());
return cln::double_approx(cln::realpart(cln::the<cln::cl_N>(value)));
/** Returns a new CLN object of type cl_N, representing the value of *this.
* This method may be used when mixing GiNaC and CLN in one project.
*/
-cln::cl_N numeric::to_cl_N(void) const
+cln::cl_N numeric::to_cl_N() const
{
return cln::cl_N(cln::the<cln::cl_N>(value));
}
/** Real part of a number. */
-const numeric numeric::real(void) const
+const numeric numeric::real() const
{
return numeric(cln::realpart(cln::the<cln::cl_N>(value)));
}
/** Imaginary part of a number. */
-const numeric numeric::imag(void) const
+const numeric numeric::imag() const
{
return numeric(cln::imagpart(cln::the<cln::cl_N>(value)));
}
* numerator of complex if real and imaginary part are both rational numbers
* (i.e numer(4/3+5/6*I) == 8+5*I), the number carrying the sign in all other
* cases. */
-const numeric numeric::numer(void) const
+const numeric numeric::numer() const
{
- if (this->is_integer())
- return numeric(*this);
+ if (cln::instanceof(value, cln::cl_I_ring))
+ return numeric(*this); // integer case
else if (cln::instanceof(value, cln::cl_RA_ring))
return numeric(cln::numerator(cln::the<cln::cl_RA>(value)));
/** Denominator. Computes the denominator of rational numbers, common integer
* denominator of complex if real and imaginary part are both rational numbers
* (i.e denom(4/3+5/6*I) == 6), one in all other cases. */
-const numeric numeric::denom(void) const
+const numeric numeric::denom() const
{
- if (this->is_integer())
- return _num1;
+ if (cln::instanceof(value, cln::cl_I_ring))
+ return _num1; // integer case
if (cln::instanceof(value, cln::cl_RA_ring))
return numeric(cln::denominator(cln::the<cln::cl_RA>(value)));
*
* @return number of bits (excluding sign) needed to represent that number
* in two's complement if it is an integer, 0 otherwise. */
-int numeric::int_length(void) const
+int numeric::int_length() const
{
- if (this->is_integer())
+ if (cln::instanceof(value, cln::cl_I_ring))
return cln::integer_length(cln::the<cln::cl_I>(value));
else
return 0;
/** Numeric integer remainder.
* Equivalent to Maple's irem(a,b,'q') it obeyes the relation
* irem(a,b,q) == a - q*b. In general, mod(a,b) has the sign of b or is zero,
- * and irem(a,b) has the sign of a or is zero.
+ * and irem(a,b) has the sign of a or is zero.
*
* @return remainder of a/b and quotient stored in q if both are integer,
* 0 otherwise.
/** Floating point evaluation of Archimedes' constant Pi. */
-ex PiEvalf(void)
+ex PiEvalf()
{
return numeric(cln::pi(cln::default_float_format));
}
/** Floating point evaluation of Euler's constant gamma. */
-ex EulerEvalf(void)
+ex EulerEvalf()
{
return numeric(cln::eulerconst(cln::default_float_format));
}
/** Floating point evaluation of Catalan's constant. */
-ex CatalanEvalf(void)
+ex CatalanEvalf()
{
return numeric(cln::catalanconst(cln::default_float_format));
}
#include "basic.h"
#include "ex.h"
+#include <stdexcept>
+
#include <cln/number.h>
// forward decln of cln::cl_N, since cln/complex_class.h is not included:
namespace cln { class cl_N; }
static bool too_late; ///< Already one object present
};
+
+/** Exception class thrown when a singularity is encountered. */
+class pole_error : public std::domain_error {
+public:
+ explicit pole_error(const std::string& what_arg, int degree);
+ int degree() const;
+private:
+ int deg;
+};
+
+
/** This class is a wrapper around CLN-numbers within the GiNaC class
* hierarchy. Objects of this type may directly be created by the user.*/
class numeric : public basic
// member functions
- // other ctors
+ // other constructors
public:
numeric(int i);
numeric(unsigned int i);
// functions overriding virtual functions from base classes
public:
void print(const print_context & c, unsigned level = 0) const;
- unsigned precedence(void) const {return 30;}
+ unsigned precedence() const {return 30;}
bool info(unsigned inf) const;
int degree(const ex & s) const;
int ldegree(const ex & s) const;
bool has(const ex &other) const;
ex eval(int level = 0) const;
ex evalf(int level = 0) const;
+ ex subs(const lst & ls, const lst & lr, unsigned options = 0) const { return subs_one_level(ls, lr, options); } // overwrites basic::subs() for performance reasons
ex normal(lst &sym_lst, lst &repl_lst, int level = 0) const;
ex to_rational(lst &repl_lst) const;
- numeric integer_content(void) const;
+ ex to_polynomial(lst &repl_lst) const;
+ numeric integer_content() const;
ex smod(const numeric &xi) const;
- numeric max_coefficient(void) const;
+ numeric max_coefficient() const;
protected:
/** Implementation of ex::diff for a numeric always returns 0.
* @see ex::diff */
ex derivative(const symbol &s) const { return 0; }
bool is_equal_same_type(const basic &other) const;
- unsigned calchash(void) const;
+ unsigned calchash() const;
// new virtual functions which can be overridden by derived classes
// (none)
const numeric & operator=(unsigned long i);
const numeric & operator=(double d);
const numeric & operator=(const char *s);
- const numeric inverse(void) const;
- int csgn(void) const;
+ const numeric inverse() const;
+ int csgn() const;
int compare(const numeric &other) const;
bool is_equal(const numeric &other) const;
- bool is_zero(void) const;
- bool is_positive(void) const;
- bool is_negative(void) const;
- bool is_integer(void) const;
- bool is_pos_integer(void) const;
- bool is_nonneg_integer(void) const;
- bool is_even(void) const;
- bool is_odd(void) const;
- bool is_prime(void) const;
- bool is_rational(void) const;
- bool is_real(void) const;
- bool is_cinteger(void) const;
- bool is_crational(void) const;
+ bool is_zero() const;
+ bool is_positive() const;
+ bool is_negative() const;
+ bool is_integer() const;
+ bool is_pos_integer() const;
+ bool is_nonneg_integer() const;
+ bool is_even() const;
+ bool is_odd() const;
+ bool is_prime() const;
+ bool is_rational() const;
+ bool is_real() const;
+ bool is_cinteger() const;
+ bool is_crational() const;
bool operator==(const numeric &other) const;
bool operator!=(const numeric &other) const;
bool operator<(const numeric &other) const;
bool operator<=(const numeric &other) const;
bool operator>(const numeric &other) const;
bool operator>=(const numeric &other) const;
- int to_int(void) const;
- long to_long(void) const;
- double to_double(void) const;
- cln::cl_N to_cl_N(void) const;
- const numeric real(void) const;
- const numeric imag(void) const;
- const numeric numer(void) const;
- const numeric denom(void) const;
- int int_length(void) const;
+ int to_int() const;
+ long to_long() const;
+ double to_double() const;
+ cln::cl_N to_cl_N() const;
+ const numeric real() const;
+ const numeric imag() const;
+ const numeric numer() const;
+ const numeric denom() const;
+ int int_length() const;
// converting routines for interfacing with CLN:
numeric(const cln::cl_N &z);
cln::cl_number value;
};
+
// global constants
extern const numeric I;
extern _numeric_digits Digits;
-// deprecated macro, for internal use only
-#define is_a_numeric_hash(x) ((x)&0x80000000U)
-
// global functions
const numeric exp(const numeric &x);
// numeric evaluation functions for class constant objects:
-ex PiEvalf(void);
-ex EulerEvalf(void);
-ex CatalanEvalf(void);
+ex PiEvalf();
+ex EulerEvalf();
+ex CatalanEvalf();
// utility functions
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include <iostream>
+#include <iomanip>
+
#include "operators.h"
#include "numeric.h"
#include "add.h"
return relational(lh,rh,relational::greater_or_equal);
}
-// input/output stream operators
+// input/output stream operators and manipulators
+
+static int my_ios_index()
+{
+ static int i = std::ios_base::xalloc();
+ return i;
+}
+
+// Stream format gets copied or destroyed
+static void my_ios_callback(std::ios_base::event ev, std::ios_base & s, int i)
+{
+ print_context *p = static_cast<print_context *>(s.pword(i));
+ if (ev == std::ios_base::erase_event) {
+ delete p;
+ s.pword(i) = 0;
+ } else if (ev == std::ios_base::copyfmt_event && p != 0)
+ s.pword(i) = p->duplicate();
+}
+
+enum {
+ callback_registered = 1
+};
+
+// Get print_context associated with stream, may return 0 if no context has
+// been associated yet
+static inline print_context *get_print_context(std::ios_base & s)
+{
+ return static_cast<print_context *>(s.pword(my_ios_index()));
+}
+
+// Set print_context associated with stream, retain options
+static void set_print_context(std::ios_base & s, const print_context & c)
+{
+ int i = my_ios_index();
+ long flags = s.iword(i);
+ if (!(flags & callback_registered)) {
+ s.register_callback(my_ios_callback, i);
+ s.iword(i) = flags | callback_registered;
+ }
+ print_context *p = static_cast<print_context *>(s.pword(i));
+ unsigned options = p ? p->options : c.options;
+ delete p;
+ p = c.duplicate();
+ p->options = options;
+ s.pword(i) = p;
+}
+
+// Get options for print_context associated with stream
+static inline unsigned get_print_options(std::ios_base & s)
+{
+ print_context *p = get_print_context(s);
+ return p ? p->options : 0;
+}
+
+// Set options for print_context associated with stream
+static void set_print_options(std::ostream & s, unsigned options)
+{
+ print_context *p = get_print_context(s);
+ if (p == 0)
+ set_print_context(s, print_context(s, options));
+ else
+ p->options = options;
+}
std::ostream & operator<<(std::ostream & os, const ex & e)
{
- e.print(print_context(os));
+ print_context *p = get_print_context(os);
+ if (p == 0)
+ e.print(print_context(os));
+ else
+ e.print(*p);
return os;
}
throw (std::logic_error("expression input from streams not implemented"));
}
+std::ostream & dflt(std::ostream & os)
+{
+ set_print_context(os, print_context(os));
+ set_print_options(os, 0);
+ return os;
+}
+
+std::ostream & latex(std::ostream & os)
+{
+ set_print_context(os, print_latex(os));
+ return os;
+}
+
+std::ostream & python(std::ostream & os)
+{
+ set_print_context(os, print_python(os));
+ return os;
+}
+
+std::ostream & python_repr(std::ostream & os)
+{
+ set_print_context(os, print_python_repr(os));
+ return os;
+}
+
+std::ostream & tree(std::ostream & os)
+{
+ set_print_context(os, print_tree(os));
+ return os;
+}
+
+std::ostream & csrc(std::ostream & os)
+{
+ set_print_context(os, print_csrc_double(os));
+ return os;
+}
+
+std::ostream & csrc_float(std::ostream & os)
+{
+ set_print_context(os, print_csrc_float(os));
+ return os;
+}
+
+std::ostream & csrc_double(std::ostream & os)
+{
+ set_print_context(os, print_csrc_double(os));
+ return os;
+}
+
+std::ostream & csrc_cl_N(std::ostream & os)
+{
+ set_print_context(os, print_csrc_cl_N(os));
+ return os;
+}
+
+std::ostream & index_dimensions(std::ostream & os)
+{
+ set_print_options(os, get_print_options(os) | print_options::print_index_dimensions);
+ return os;
+}
+
+std::ostream & no_index_dimensions(std::ostream & os)
+{
+ set_print_options(os, get_print_options(os) & ~print_options::print_index_dimensions);
+ return os;
+}
+
} // namespace GiNaC
std::ostream & operator<<(std::ostream & os, const ex & e);
std::istream & operator>>(std::istream & is, ex & e);
+// input/output stream manipulators
+std::ostream & dflt(std::ostream & os);
+std::ostream & latex(std::ostream & os);
+std::ostream & python(std::ostream & os);
+std::ostream & python_repr(std::ostream & os);
+std::ostream & tree(std::ostream & os);
+std::ostream & csrc(std::ostream & os); // same as csrc_double
+std::ostream & csrc_float(std::ostream & os);
+std::ostream & csrc_double(std::ostream & os);
+std::ostream & csrc_cl_N(std::ostream & os);
+
+std::ostream & index_dimensions(std::ostream & os);
+std::ostream & no_index_dimensions(std::ostream & os);
+
} // namespace GiNaC
#endif // ndef __GINAC_OPERATORS_H__
#include <vector>
#include <iostream>
#include <stdexcept>
+#include <limits>
#include "power.h"
#include "expairseq.h"
#include "ncmul.h"
#include "numeric.h"
#include "constant.h"
+#include "operators.h"
#include "inifcns.h" // for log() in power::derivative()
#include "matrix.h"
#include "indexed.h"
#include "symbol.h"
+#include "lst.h"
#include "print.h"
#include "archive.h"
#include "utils.h"
typedef std::vector<int> intvector;
//////////
-// default ctor, dtor, copy ctor, assignment operator and helpers
+// default constructor
//////////
power::power() : inherited(TINFO_power) { }
-void power::copy(const power & other)
-{
- inherited::copy(other);
- basis = other.basis;
- exponent = other.exponent;
-}
-
-DEFAULT_DESTROY(power)
-
//////////
-// other ctors
+// other constructors
//////////
// all inlined
// archiving
//////////
-power::power(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
+power::power(const archive_node &n, lst &sym_lst) : inherited(n, sym_lst)
{
n.find_ex("basis", basis, sym_lst);
n.find_ex("exponent", exponent, sym_lst);
return inherited::info(inf);
}
-unsigned power::nops() const
+size_t power::nops() const
{
return 2;
}
-ex & power::let_op(int i)
+ex power::op(size_t i) const
{
- GINAC_ASSERT(i>=0);
GINAC_ASSERT(i<2);
return i==0 ? basis : exponent;
{
if (is_equal(ex_to<basic>(s)))
return 1;
- else if (is_ex_exactly_of_type(exponent, numeric) && ex_to<numeric>(exponent).is_integer()) {
+ else if (is_exactly_a<numeric>(exponent) && ex_to<numeric>(exponent).is_integer()) {
if (basis.is_equal(s))
return ex_to<numeric>(exponent).to_int();
else
{
if (is_equal(ex_to<basic>(s)))
return 1;
- else if (is_ex_exactly_of_type(exponent, numeric) && ex_to<numeric>(exponent).is_integer()) {
+ else if (is_exactly_a<numeric>(exponent) && ex_to<numeric>(exponent).is_integer()) {
if (basis.is_equal(s))
return ex_to<numeric>(exponent).to_int();
else
return _ex0;
} else {
// basis equal to s
- if (is_ex_exactly_of_type(exponent, numeric) && ex_to<numeric>(exponent).is_integer()) {
+ if (is_exactly_a<numeric>(exponent) && ex_to<numeric>(exponent).is_integer()) {
// integer exponent
int int_exp = ex_to<numeric>(exponent).to_int();
if (n == int_exp)
const numeric *num_basis;
const numeric *num_exponent;
- if (is_ex_exactly_of_type(ebasis, numeric)) {
+ if (is_exactly_a<numeric>(ebasis)) {
basis_is_numerical = true;
num_basis = &ex_to<numeric>(ebasis);
}
- if (is_ex_exactly_of_type(eexponent, numeric)) {
+ if (is_exactly_a<numeric>(eexponent)) {
exponent_is_numerical = true;
num_exponent = &ex_to<numeric>(eexponent);
}
// ^(^(x,c1),c2) -> ^(x,c1*c2)
// (c1, c2 numeric(), c2 integer or -1 < c1 <= 1,
// case c1==1 should not happen, see below!)
- if (is_ex_exactly_of_type(ebasis,power)) {
+ if (is_exactly_a<power>(ebasis)) {
const power & sub_power = ex_to<power>(ebasis);
const ex & sub_basis = sub_power.basis;
const ex & sub_exponent = sub_power.exponent;
- if (is_ex_exactly_of_type(sub_exponent,numeric)) {
+ if (is_exactly_a<numeric>(sub_exponent)) {
const numeric & num_sub_exponent = ex_to<numeric>(sub_exponent);
GINAC_ASSERT(num_sub_exponent!=numeric(1));
if (num_exponent->is_integer() || (abs(num_sub_exponent) - _num1).is_negative())
}
// ^(*(x,y,z),c1) -> *(x^c1,y^c1,z^c1) (c1 integer)
- if (num_exponent->is_integer() && is_ex_exactly_of_type(ebasis,mul)) {
+ if (num_exponent->is_integer() && is_exactly_a<mul>(ebasis)) {
return expand_mul(ex_to<mul>(ebasis), *num_exponent);
}
// ^(*(...,x;c1),c2) -> *(^(*(...,x;1),c2),c1^c2) (c1, c2 numeric(), c1>0)
// ^(*(...,x;c1),c2) -> *(^(*(...,x;-1),c2),(-c1)^c2) (c1, c2 numeric(), c1<0)
- if (is_ex_exactly_of_type(ebasis,mul)) {
+ if (is_exactly_a<mul>(ebasis)) {
GINAC_ASSERT(!num_exponent->is_integer()); // should have been handled above
const mul & mulref = ex_to<mul>(ebasis);
if (!mulref.overall_coeff.is_equal(_ex1)) {
// ^(nc,c1) -> ncmul(nc,nc,...) (c1 positive integer, unless nc is a matrix)
if (num_exponent->is_pos_integer() &&
ebasis.return_type() != return_types::commutative &&
- !is_ex_of_type(ebasis,matrix)) {
+ !is_a<matrix>(ebasis)) {
return ncmul(exvector(num_exponent->to_int(), ebasis), true);
}
}
return power(ebasis,eexponent);
}
-ex power::evalm(void) const
+ex power::evalm() const
{
const ex ebasis = basis.evalm();
const ex eexponent = exponent.evalm();
- if (is_ex_of_type(ebasis,matrix)) {
- if (is_ex_of_type(eexponent,numeric)) {
+ if (is_a<matrix>(ebasis)) {
+ if (is_exactly_a<numeric>(eexponent)) {
return (new matrix(ex_to<matrix>(ebasis).pow(eexponent)))->setflag(status_flags::dynallocated);
}
}
return (new power(ebasis, eexponent))->setflag(status_flags::dynallocated);
}
-ex power::subs(const lst & ls, const lst & lr, bool no_pattern) const
-{
- const ex &subsed_basis = basis.subs(ls, lr, no_pattern);
- const ex &subsed_exponent = exponent.subs(ls, lr, no_pattern);
+// from mul.cpp
+extern bool tryfactsubs(const ex &, const ex &, int &, lst &);
- if (are_ex_trivially_equal(basis, subsed_basis)
- && are_ex_trivially_equal(exponent, subsed_exponent))
- return basic::subs(ls, lr, no_pattern);
- else
- return power(subsed_basis, subsed_exponent).basic::subs(ls, lr, no_pattern);
+ex power::subs(const lst & ls, const lst & lr, unsigned options) const
+{
+ const ex &subsed_basis = basis.subs(ls, lr, options);
+ const ex &subsed_exponent = exponent.subs(ls, lr, options);
+
+ if (!are_ex_trivially_equal(basis, subsed_basis)
+ || !are_ex_trivially_equal(exponent, subsed_exponent))
+ return power(subsed_basis, subsed_exponent).subs_one_level(ls, lr, options);
+
+ if (!(options & subs_options::subs_algebraic))
+ return subs_one_level(ls, lr, options);
+
+ lst::const_iterator its, itr;
+ for (its = ls.begin(), itr = lr.begin(); its != ls.end(); ++its, ++itr) {
+ int nummatches = std::numeric_limits<int>::max();
+ lst repls;
+ if (tryfactsubs(*this, *its, nummatches, repls))
+ return (ex_to<basic>((*this) * power(itr->subs(ex(repls), subs_options::subs_no_pattern) / its->subs(ex(repls), subs_options::subs_no_pattern), nummatches))).subs_one_level(ls, lr, options);
+ }
+
+ return subs_one_level(ls, lr, options);
}
-ex power::simplify_ncmul(const exvector & v) const
+ex power::eval_ncmul(const exvector & v) const
{
- return inherited::simplify_ncmul(v);
+ return inherited::eval_ncmul(v);
}
// protected
return exponent.compare(o.exponent);
}
-unsigned power::return_type(void) const
+unsigned power::return_type() const
{
return basis.return_type();
}
-unsigned power::return_type_tinfo(void) const
+unsigned power::return_type_tinfo() const
{
return basis.return_type_tinfo();
}
const ex expanded_exponent = exponent.expand(options);
// x^(a+b) -> x^a * x^b
- if (is_ex_exactly_of_type(expanded_exponent, add)) {
+ if (is_exactly_a<add>(expanded_exponent)) {
const add &a = ex_to<add>(expanded_exponent);
exvector distrseq;
distrseq.reserve(a.seq.size() + 1);
if (ex_to<numeric>(a.overall_coeff).is_integer()) {
const numeric &num_exponent = ex_to<numeric>(a.overall_coeff);
int int_exponent = num_exponent.to_int();
- if (int_exponent > 0 && is_ex_exactly_of_type(expanded_basis, add))
+ if (int_exponent > 0 && is_exactly_a<add>(expanded_basis))
distrseq.push_back(expand_add(ex_to<add>(expanded_basis), int_exponent));
else
distrseq.push_back(power(expanded_basis, a.overall_coeff));
return r.expand();
}
- if (!is_ex_exactly_of_type(expanded_exponent, numeric) ||
+ if (!is_exactly_a<numeric>(expanded_exponent) ||
!ex_to<numeric>(expanded_exponent).is_integer()) {
if (are_ex_trivially_equal(basis,expanded_basis) && are_ex_trivially_equal(exponent,expanded_exponent)) {
return this->hold();
int int_exponent = num_exponent.to_int();
// (x+y)^n, n>0
- if (int_exponent > 0 && is_ex_exactly_of_type(expanded_basis,add))
+ if (int_exponent > 0 && is_exactly_a<add>(expanded_basis))
return expand_add(ex_to<add>(expanded_basis), int_exponent);
// (x*y)^n -> x^n * y^n
- if (is_ex_exactly_of_type(expanded_basis,mul))
+ if (is_exactly_a<mul>(expanded_basis))
return expand_mul(ex_to<mul>(expanded_basis), num_exponent);
// cannot expand further
if (n==2)
return expand_add_2(a);
- const int m = a.nops();
+ const size_t m = a.nops();
exvector result;
// The number of terms will be the number of combinatorial compositions,
// i.e. the number of unordered arrangement of m nonnegative integers
intvector upper_limit(m-1);
int l;
- for (int l=0; l<m-1; ++l) {
+ for (size_t l=0; l<m-1; ++l) {
k[l] = 0;
k_cum[l] = 0;
upper_limit[l] = n;
!is_exactly_a<add>(ex_to<power>(b).basis) ||
!is_exactly_a<mul>(ex_to<power>(b).basis) ||
!is_exactly_a<power>(ex_to<power>(b).basis));
- if (is_ex_exactly_of_type(b,mul))
+ if (is_exactly_a<mul>(b))
term.push_back(expand_mul(ex_to<mul>(b),numeric(k[l])));
else
term.push_back(power(b,k[l]));
!is_exactly_a<add>(ex_to<power>(b).basis) ||
!is_exactly_a<mul>(ex_to<power>(b).basis) ||
!is_exactly_a<power>(ex_to<power>(b).basis));
- if (is_ex_exactly_of_type(b,mul))
+ if (is_exactly_a<mul>(b))
term.push_back(expand_mul(ex_to<mul>(b),numeric(n-k_cum[m-2])));
else
term.push_back(power(b,n-k_cum[m-2]));
// recalc k_cum[] and upper_limit[]
k_cum[l] = (l==0 ? k[0] : k_cum[l-1]+k[l]);
- for (int i=l+1; i<m-1; ++i)
+ for (size_t i=l+1; i<m-1; ++i)
k_cum[i] = k_cum[i-1]+k[i];
- for (int i=l+1; i<m-1; ++i)
+ for (size_t i=l+1; i<m-1; ++i)
upper_limit[i] = n-k_cum[i-1];
}
ex power::expand_add_2(const add & a) const
{
epvector sum;
- unsigned a_nops = a.nops();
+ size_t a_nops = a.nops();
sum.reserve((a_nops*(a_nops+1))/2);
epvector::const_iterator last = a.seq.end();
!is_exactly_a<mul>(ex_to<power>(r).basis) ||
!is_exactly_a<power>(ex_to<power>(r).basis));
- if (are_ex_trivially_equal(c,_ex1)) {
- if (is_ex_exactly_of_type(r,mul)) {
+ if (c.is_equal(_ex1)) {
+ if (is_exactly_a<mul>(r)) {
sum.push_back(expair(expand_mul(ex_to<mul>(r),_num2),
_ex1));
} else {
_ex1));
}
} else {
- if (is_ex_exactly_of_type(r,mul)) {
+ if (is_exactly_a<mul>(r)) {
sum.push_back(a.combine_ex_with_coeff_to_pair(expand_mul(ex_to<mul>(r),_num2),
ex_to<numeric>(c).power_dyn(_num2)));
} else {
ex_to<numeric>(c).power_dyn(_num2)));
}
}
-
+
for (epvector::const_iterator cit1=cit0+1; cit1!=last; ++cit1) {
const ex & r1 = cit1->rest;
const ex & c1 = cit1->coeff;
epvector::const_iterator last = m.seq.end();
epvector::const_iterator cit = m.seq.begin();
while (cit!=last) {
- if (is_ex_exactly_of_type(cit->rest,numeric)) {
+ if (is_exactly_a<numeric>(cit->rest)) {
distrseq.push_back(m.combine_pair_with_coeff_to_pair(*cit, n));
} else {
// it is safe not to call mul::combine_pair_with_coeff_to_pair()
// member functions
- // other ctors
+ // other constructors
public:
power(const ex & lh, const ex & rh) : inherited(TINFO_power), basis(lh), exponent(rh) {}
template<typename T> power(const ex & lh, const T & rh) : inherited(TINFO_power), basis(lh), exponent(rh) {}
// functions overriding virtual functions from base classes
public:
void print(const print_context & c, unsigned level = 0) const;
- unsigned precedence(void) const {return 60;}
+ unsigned precedence() const {return 60;}
bool info(unsigned inf) const;
- unsigned nops() const;
- ex & let_op(int i);
+ size_t nops() const;
+ ex op(size_t i) const;
ex map(map_function & f) const;
int degree(const ex & s) const;
int ldegree(const ex & s) const;
ex coeff(const ex & s, int n = 1) const;
ex eval(int level=0) const;
ex evalf(int level=0) const;
- ex evalm(void) const;
+ ex evalm() const;
ex series(const relational & s, int order, unsigned options = 0) const;
- ex subs(const lst & ls, const lst & lr, bool no_pattern = false) const;
+ ex subs(const lst & ls, const lst & lr, unsigned options = 0) const;
ex normal(lst &sym_lst, lst &repl_lst, int level = 0) const;
ex to_rational(lst &repl_lst) const;
- exvector get_free_indices(void) const;
- ex simplify_ncmul(const exvector & v) const;
+ ex to_polynomial(lst &repl_lst) const;
+ exvector get_free_indices() const;
protected:
ex derivative(const symbol & s) const;
- unsigned return_type(void) const;
- unsigned return_type_tinfo(void) const;
+ ex eval_ncmul(const exvector & v) const;
+ unsigned return_type() const;
+ unsigned return_type_tinfo() const;
ex expand(unsigned options = 0) const;
// new virtual functions which can be overridden by derived classes
namespace GiNaC {
print_context::print_context()
- : s(std::cout) {}
-print_context::print_context(std::ostream & os)
- : s(os) {}
+ : s(std::cout), options(0) {}
+print_context::print_context(std::ostream & os, unsigned opt)
+ : s(os), options(opt) {}
print_latex::print_latex()
: print_context(std::cout) {}
-print_latex::print_latex(std::ostream & os)
- : print_context(os) {}
+print_latex::print_latex(std::ostream & os, unsigned opt)
+ : print_context(os, opt) {}
print_python::print_python()
: print_context(std::cout) {}
-print_python::print_python(std::ostream & os)
- : print_context(os) {}
+print_python::print_python(std::ostream & os, unsigned opt)
+ : print_context(os, opt) {}
print_python_repr::print_python_repr()
: print_context(std::cout) {}
-print_python_repr::print_python_repr(std::ostream & os)
- : print_context(os) {}
+print_python_repr::print_python_repr(std::ostream & os, unsigned opt)
+ : print_context(os, opt) {}
print_tree::print_tree(unsigned d)
: print_context(std::cout), delta_indent(d) {}
-print_tree::print_tree(std::ostream & os, unsigned d)
- : print_context(os), delta_indent(d) {}
+print_tree::print_tree(std::ostream & os, unsigned opt, unsigned d)
+ : print_context(os, opt), delta_indent(d) {}
print_csrc::print_csrc()
: print_context(std::cout) {}
-print_csrc::print_csrc(std::ostream & os)
- : print_context(os) {}
+print_csrc::print_csrc(std::ostream & os, unsigned opt)
+ : print_context(os, opt) {}
print_csrc_float::print_csrc_float()
: print_csrc(std::cout) {}
-print_csrc_float::print_csrc_float(std::ostream & os)
- : print_csrc(os) {}
+print_csrc_float::print_csrc_float(std::ostream & os, unsigned opt)
+ : print_csrc(os, opt) {}
print_csrc_double::print_csrc_double()
: print_csrc(std::cout) {}
-print_csrc_double::print_csrc_double(std::ostream & os)
- : print_csrc(os) {}
+print_csrc_double::print_csrc_double(std::ostream & os, unsigned opt)
+ : print_csrc(os, opt) {}
print_csrc_cl_N::print_csrc_cl_N()
: print_csrc(std::cout) {}
-print_csrc_cl_N::print_csrc_cl_N(std::ostream & os)
- : print_csrc(os) {}
+print_csrc_cl_N::print_csrc_cl_N(std::ostream & os, unsigned opt)
+ : print_csrc(os, opt) {}
} // namespace GiNaC
namespace GiNaC {
+
+/*
+ * The following classes remain publicly visible for compatibility
+ * reasons only. New code should use the iostream manipulators defined
+ * in operators.h instead.
+ */
+
+
+/** Flags to control the behavior of a print_context. */
+class print_options {
+public:
+ enum {
+ print_index_dimensions = 0x0001 ///< print the dimensions of indices
+ };
+};
+
+
/** Context for default (ginsh-parsable) output. */
class print_context
{
public:
print_context();
- print_context(std::ostream &);
+ print_context(std::ostream &, unsigned options = 0);
+ virtual ~print_context() {}
+ virtual print_context * duplicate() const {return new print_context(*this);}
std::ostream & s; /**< stream to output to */
-private:
- // dummy virtual function to make the class polymorphic
- virtual void dummy(void) {}
+ unsigned options; /**< option flags */
};
/** Context for latex-parsable output. */
{
public:
print_latex();
- print_latex(std::ostream &);
+ print_latex(std::ostream &, unsigned options = 0);
+ print_context * duplicate() const {return new print_latex(*this);}
};
/** Context for python pretty-print output. */
{
public:
print_python();
- print_python(std::ostream &);
+ print_python(std::ostream &, unsigned options = 0);
+ print_context * duplicate() const {return new print_python(*this);}
};
/** Context for python-parsable output. */
{
public:
print_python_repr();
- print_python_repr(std::ostream &);
+ print_python_repr(std::ostream &, unsigned options = 0);
+ print_context * duplicate() const {return new print_python_repr(*this);}
};
/** Context for tree-like output for debugging. */
{
public:
print_tree(unsigned d = 4);
- print_tree(std::ostream &, unsigned d = 4);
+ print_tree(std::ostream &, unsigned options = 0, unsigned d = 4);
+ print_context * duplicate() const {return new print_tree(*this);}
+
const unsigned delta_indent; /**< size of indentation step */
};
{
public:
print_csrc();
- print_csrc(std::ostream &);
+ print_csrc(std::ostream &, unsigned options = 0);
+ print_context * duplicate() const {return new print_csrc(*this);}
};
/** Context for C source output using float precision. */
{
public:
print_csrc_float();
- print_csrc_float(std::ostream &);
+ print_csrc_float(std::ostream &, unsigned options = 0);
+ print_context * duplicate() const {return new print_csrc_float(*this);}
};
/** Context for C source output using double precision. */
{
public:
print_csrc_double();
- print_csrc_double(std::ostream &);
+ print_csrc_double(std::ostream &, unsigned options = 0);
+ print_context * duplicate() const {return new print_csrc_double(*this);}
};
/** Context for C source output using CLN numbers. */
{
public:
print_csrc_cl_N();
- print_csrc_cl_N(std::ostream &);
+ print_csrc_cl_N(std::ostream &, unsigned options = 0);
+ print_context * duplicate() const {return new print_csrc_cl_N(*this);}
};
/** Check if obj is a T, including base classes. */
#include "mul.h"
#include "power.h"
#include "relational.h"
+#include "operators.h"
#include "symbol.h"
#include "print.h"
#include "archive.h"
/*
- * Default ctor, dtor, copy ctor, assignment operator and helpers
+ * Default constructor
*/
pseries::pseries() : inherited(TINFO_pseries) { }
-void pseries::copy(const pseries &other)
-{
- inherited::copy(other);
- seq = other.seq;
- var = other.var;
- point = other.point;
-}
-
-DEFAULT_DESTROY(pseries)
-
/*
* Other ctors
* Archiving
*/
-pseries::pseries(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
+pseries::pseries(const archive_node &n, lst &sym_lst) : inherited(n, sym_lst)
{
for (unsigned int i=0; true; ++i) {
ex rest;
<< std::hex << ", hash=0x" << hashvalue << ", flags=0x" << flags << std::dec
<< std::endl;
unsigned delta_indent = static_cast<const print_tree &>(c).delta_indent;
- unsigned num = seq.size();
- for (unsigned i=0; i<num; ++i) {
+ size_t num = seq.size();
+ for (size_t i=0; i<num; ++i) {
seq[i].rest.print(c, level + delta_indent);
seq[i].coeff.print(c, level + delta_indent);
c.s << std::string(level + delta_indent, ' ') << "-----" << std::endl;
c.s << ',';
point.print(c);
c.s << "),[";
- unsigned num = seq.size();
- for (unsigned i=0; i<num; ++i) {
+ size_t num = seq.size();
+ for (size_t i=0; i<num; ++i) {
if (i)
c.s << ',';
c.s << '(';
}
/** Return the number of operands including a possible order term. */
-unsigned pseries::nops(void) const
+size_t pseries::nops() const
{
return seq.size();
}
/** Return the ith term in the series when represented as a sum. */
-ex pseries::op(int i) const
+ex pseries::op(size_t i) const
{
- if (i < 0 || unsigned(i) >= seq.size())
+ if (i >= seq.size())
throw (std::out_of_range("op() out of range"));
- return seq[i].rest * power(var - point, seq[i].coeff);
-}
-ex &pseries::let_op(int i)
-{
- throw (std::logic_error("let_op not defined for pseries"));
+ return seq[i].rest * power(var - point, seq[i].coeff);
}
/** Return degree of highest power of the series. This is usually the exponent
return (new pseries(relational(var,point), new_seq))->setflag(status_flags::dynallocated | status_flags::evaluated);
}
-ex pseries::subs(const lst & ls, const lst & lr, bool no_pattern) const
+ex pseries::subs(const lst & ls, const lst & lr, unsigned options) const
{
// If expansion variable is being substituted, convert the series to a
// polynomial and do the substitution there because the result might
// no longer be a power series
if (ls.has(var))
- return convert_to_poly(true).subs(ls, lr, no_pattern);
+ return convert_to_poly(true).subs(ls, lr, options);
// Otherwise construct a new series with substituted coefficients and
// expansion point
newseq.reserve(seq.size());
epvector::const_iterator it = seq.begin(), itend = seq.end();
while (it != itend) {
- newseq.push_back(expair(it->rest.subs(ls, lr, no_pattern), it->coeff));
+ newseq.push_back(expair(it->rest.subs(ls, lr, options), it->coeff));
++it;
}
- return (new pseries(relational(var,point.subs(ls, lr, no_pattern)), newseq))->setflag(status_flags::dynallocated);
+ return (new pseries(relational(var,point.subs(ls, lr, options)), newseq))->setflag(status_flags::dynallocated);
}
/** Implementation of ex::expand() for a power series. It expands all the
return e;
}
-bool pseries::is_terminating(void) const
+bool pseries::is_terminating() const
{
return seq.empty() || !is_order_function((seq.end()-1)->rest);
}
* @return an expression holding a pseries object */
ex ex::series(const ex & r, int order, unsigned options) const
{
- GINAC_ASSERT(bp!=0);
ex e;
relational rel_;
- if (is_exactly_a<relational>(r))
+ if (is_a<relational>(r))
rel_ = ex_to<relational>(r);
else if (is_a<symbol>(r))
rel_ = relational(r,_ex0);
{
GINAC_DECLARE_REGISTERED_CLASS(pseries, basic)
- // other ctors
+ // other constructors
public:
pseries(const ex &rel_, const epvector &ops_);
// functions overriding virtual functions from base classes
public:
void print(const print_context & c, unsigned level = 0) const;
- unsigned precedence(void) const {return 38;} // for clarity just below add::precedence
- unsigned nops(void) const;
- ex op(int i) const;
- ex &let_op(int i);
+ unsigned precedence() const {return 38;} // for clarity just below add::precedence
+ size_t nops() const;
+ ex op(size_t i) const;
int degree(const ex &s) const;
int ldegree(const ex &s) const;
ex coeff(const ex &s, int n = 1) const;
ex eval(int level=0) const;
ex evalf(int level=0) const;
ex series(const relational & r, int order, unsigned options = 0) const;
- ex subs(const lst & ls, const lst & lr, bool no_pattern = false) const;
+ ex subs(const lst & ls, const lst & lr, unsigned options = 0) const;
ex normal(lst &sym_lst, lst &repl_lst, int level = 0) const;
ex expand(unsigned options = 0) const;
protected:
// non-virtual functions in this class
public:
/** Get the expansion variable. */
- ex get_var(void) const {return var;}
+ ex get_var() const {return var;}
/** Get the expansion point. */
- ex get_point(void) const {return point;}
+ ex get_point() const {return point;}
/** Convert the pseries object to an ordinary polynomial.
*
bool is_compatible_to(const pseries &other) const {return var.is_equal(other.var) && point.is_equal(other.point);}
/** Check whether series has the value zero. */
- bool is_zero(void) const {return seq.size() == 0;}
+ bool is_zero() const {return seq.size() == 0;}
/** Returns true if there is no order term, i.e. the series terminates and
* false otherwise. */
- bool is_terminating(void) const;
+ bool is_terminating() const;
ex add_series(const pseries &other) const;
ex mul_const(const numeric &other) const;
--- /dev/null
+/** @file ptr.h
+ *
+ * Reference-counted pointer template. */
+
+/*
+ * GiNaC Copyright (C) 1999-2003 Johannes Gutenberg University Mainz, Germany
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __GINAC_PTR_H__
+#define __GINAC_PTR_H__
+
+#include <functional>
+#include <iosfwd>
+
+#include "assertion.h"
+
+namespace GiNaC {
+
+/** Class of (intrusively) reference-counted pointers that support
+ * copy-on-write semantics.
+ *
+ * Requirements for T:
+ * T::refcount member that supports ++refcount, --refcount, refcount = 1,
+ * refcount == 0 and refcount > 1
+ * T* T::duplicate() member function (only if makewriteable() is used) */
+template <class T> class ptr {
+ friend class std::less< ptr<T> >;
+
+ // NB: This implementation of reference counting is not thread-safe.
+ // The reference counter needs to be incremented/decremented atomically,
+ // and makewritable() requires locking.
+
+public:
+ // no default ctor: a ptr is never unbound
+
+ /** Bind ptr to newly created object, start reference counting. */
+ ptr(T *t) : p(t) { GINAC_ASSERT(p); p->refcount = 1; }
+
+ /** Bind ptr to existing reference-counted object. */
+ explicit ptr(T &t) : p(&t) { ++p->refcount; }
+
+ ptr(const ptr & other) : p(other.p) { ++p->refcount; }
+
+ ~ptr()
+ {
+ if (--p->refcount == 0)
+ delete p;
+ }
+
+ ptr &operator=(const ptr & other)
+ {
+ // NB: must first increment other.p->refcount, since other might be *this.
+ ++other.p->refcount;
+ if (--p->refcount == 0)
+ delete p;
+ p = other.p;
+ return *this;
+ }
+
+ T &operator*() const { return *p; }
+ T *operator->() const { return p; }
+
+ friend inline T *get_pointer(const ptr & x) { return x.p; }
+
+ /** Announce your intention to modify the object bound to this ptr.
+ * This ensures that the object is not shared by any other ptrs. */
+ void makewritable()
+ {
+ if (p->refcount > 1) {
+ T *p2 = p->duplicate();
+ p2->refcount = 1;
+ --p->refcount;
+ p = p2;
+ }
+ }
+
+ /** Swap the bound object of this ptr with another ptr. */
+ void swap(ptr & other)
+ {
+ T *t = p;
+ p = other.p;
+ other.p = t;
+ }
+
+ // ptr<>s are always supposed to be bound to a valid object, so we don't
+ // provide support for "if (p)", "if (!p)", "if (p==0)" and "if (p!=0)".
+ // We do, however, provide support for comparing ptr<>s with other ptr<>s
+ // to different (probably derived) types and raw pointers.
+
+ template <class U>
+ bool operator==(const ptr<U> & rhs) const { return p == get_pointer(rhs); }
+
+ template <class U>
+ bool operator!=(const ptr<U> & rhs) const { return p != get_pointer(rhs); }
+
+ template <class U>
+ inline friend bool operator==(const ptr & lhs, const U * rhs) { return lhs.p == rhs; }
+
+ template <class U>
+ inline friend bool operator!=(const ptr & lhs, const U * rhs) { return lhs.p != rhs; }
+
+ template <class U>
+ inline friend bool operator==(const U * lhs, const ptr & rhs) { return lhs == rhs.p; }
+
+ template <class U>
+ inline friend bool operator!=(const U * lhs, const ptr & rhs) { return lhs != rhs.p; }
+
+ inline friend std::ostream & operator<<(std::ostream & os, const ptr<T> & rhs)
+ {
+ os << rhs.p;
+ }
+
+private:
+ T *p;
+};
+
+} // namespace GiNaC
+
+namespace std {
+
+/** Specialization of std::less for ptr<T> to enable ordering of ptr<T>
+ * objects (e.g. for the use as std::map keys). */
+template <class T> struct less< GiNaC::ptr<T> >
+ : public binary_function<GiNaC::ptr<T>, GiNaC::ptr<T>, bool> {
+ bool operator()(const GiNaC::ptr<T> &lhs, const GiNaC::ptr<T> &rhs) const
+ {
+ return less<T*>()(lhs.p, rhs.p);
+ }
+};
+
+} // namespace std
+
+#endif // ndef __GINAC_UTILS_H__
*/
#include <string>
+#include <map>
#include <stdexcept>
#include "registrar.h"
registered_class_info *first_registered_class = NULL;
/** Find registered_class_info strucure by class name. */
-static inline registered_class_info *find_registered_class_info(const std::string &class_name)
+static const registered_class_info *find_registered_class_info(const std::string &class_name)
{
- registered_class_info *p = first_registered_class;
- while (p) {
- if (class_name == p->name)
- return p;
- p = p->next;
+ // Use a map for faster lookup. The registered_class_info list doesn't
+ // change at run-time, so it's sufficient to construct the map once
+ // on the first trip through this function.
+ typedef std::map<std::string, const registered_class_info *> name_map_type;
+ static name_map_type name_map;
+ static bool name_map_initialized = false;
+
+ if (!name_map_initialized) {
+ // Construct map
+ const registered_class_info *p = first_registered_class;
+ while (p) {
+ name_map[p->name] = p;
+ p = p->next;
+ }
+ name_map_initialized = true;
}
- throw (std::runtime_error("class '" + class_name + "' not registered"));
+
+ name_map_type::const_iterator it = name_map.find(class_name);
+ if (it == name_map.end())
+ throw (std::runtime_error("class '" + class_name + "' not registered"));
+ else
+ return it->second;
}
unsigned int find_tinfo_key(const std::string &class_name)
{
- registered_class_info *p = find_registered_class_info(class_name);
+ const registered_class_info *p = find_registered_class_info(class_name);
return p->tinfo_key;
}
unarch_func find_unarch_func(const std::string &class_name)
{
- registered_class_info *p = find_registered_class_info(class_name);
+ const registered_class_info *p = find_registered_class_info(class_name);
return p->unarchive;
}
#define __GINAC_REGISTRAR_H__
#include <string>
+#include <list>
namespace GiNaC {
class registered_class_info;
class ex;
class archive_node;
-class lst;
+
+template <template <class> class> class container;
+typedef container<std::list> lst;
/** Unarchiving function (static member function of every GiNaC class). */
-typedef ex (*unarch_func)(const archive_node &n, const lst &sym_lst);
+typedef ex (*unarch_func)(const archive_node &n, lst &sym_lst);
/** Head of list of all registered_class_info structures. */
#define GINAC_DECLARE_REGISTERED_CLASS_NO_CTORS(classname, supername) \
public: \
typedef supername inherited; \
- static registered_class_info reg_info; \
- virtual const char *class_name(void) const; \
- classname(const archive_node &n, const lst &sym_lst); \
- virtual void archive(archive_node &n) const; \
- static ex unarchive(const archive_node &n, const lst &sym_lst);
+ \
+ static GiNaC::registered_class_info reg_info; \
+ virtual const char *class_name() const; \
+ \
+ classname(const GiNaC::archive_node &n, GiNaC::lst &sym_lst); \
+ virtual void archive(GiNaC::archive_node &n) const; \
+ static GiNaC::ex unarchive(const GiNaC::archive_node &n, GiNaC::lst &sym_lst); \
+ \
+ class visitor { \
+ public: \
+ virtual void visit(const classname &) = 0; \
+ };
/** Macro for inclusion in the declaration of each registered class.
* It declares some functions that are common to all classes derived
GINAC_DECLARE_REGISTERED_CLASS_NO_CTORS(classname, supername) \
public: \
classname(); \
- ~classname() { destroy(false); } \
- classname(const classname & other); \
- const classname & operator=(const classname & other); \
- basic * duplicate() const; \
+ classname * duplicate() const { return new classname(*this); } \
+ \
+ void accept(GiNaC::visitor & v) const \
+ { \
+ if (visitor *p = dynamic_cast<visitor *>(&v)) \
+ p->visit(*this); \
+ else \
+ inherited::accept(v); \
+ } \
protected: \
- void copy(const classname & other); \
- void destroy(bool call_parent); \
- int compare_same_type(const basic & other) const; \
+ int compare_same_type(const GiNaC::basic & other) const; \
private:
-/** Primary macro for inclusion in the implementation of each registered class. */
-#define GINAC_IMPLEMENT_REGISTERED_CLASS_NO_CTORS(classname, supername) \
- registered_class_info classname::reg_info(#classname, #supername, TINFO_##classname, &classname::unarchive); \
- const char *classname::class_name(void) const {return reg_info.name;}
-
/** Macro for inclusion in the implementation of each registered class.
- * It implements some functions that are the same in all classes derived
- * from 'basic' (such as the assignment operator). */
+ * It defines some members that are the same in all classes derived from
+ * 'basic'. */
#define GINAC_IMPLEMENT_REGISTERED_CLASS(classname, supername) \
- GINAC_IMPLEMENT_REGISTERED_CLASS_NO_CTORS(classname, supername) \
-classname::classname(const classname & other) { copy(other); } \
-const classname & classname::operator=(const classname & other) \
-{ \
- if (this != &other) { \
- destroy(true); \
- copy(other); \
- } \
- return *this; \
-} \
-basic * classname::duplicate() const { \
- return new classname(*this); \
-}
+ GiNaC::registered_class_info classname::reg_info(#classname, #supername, TINFO_##classname, &classname::unarchive); \
+ const char *classname::class_name() const {return reg_info.name;}
/** Find TINFO_* key by class name. */
#include <stdexcept>
#include "relational.h"
+#include "operators.h"
#include "numeric.h"
#include "print.h"
#include "archive.h"
GINAC_IMPLEMENT_REGISTERED_CLASS(relational, basic)
//////////
-// default ctor, dtor, copy ctor, assignment operator and helpers
+// default constructor
//////////
relational::relational() : basic(TINFO_relational) {}
-void relational::copy(const relational & other)
-{
- basic::copy(other);
- lh=other.lh;
- rh=other.rh;
- o=other.o;
-}
-
-DEFAULT_DESTROY(relational)
-
//////////
-// other ctors
+// other constructors
//////////
// public
// archiving
//////////
-relational::relational(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
+relational::relational(const archive_node &n, lst &sym_lst) : inherited(n, sym_lst)
{
unsigned int opi;
if (!(n.find_unsigned("op", opi)))
return 0;
}
-unsigned relational::nops() const
+size_t relational::nops() const
{
return 2;
}
-ex & relational::let_op(int i)
+ex relational::op(size_t i) const
{
- GINAC_ASSERT(i>=0);
GINAC_ASSERT(i<2);
return i==0 ? lh : rh;
}
+ex relational::map(map_function & f) const
+{
+ return (new relational(f(lh), f(rh), o))->setflag(status_flags::dynallocated);
+}
+
ex relational::eval(int level) const
{
if (level==1)
return (new relational(lh.eval(level-1),rh.eval(level-1),o))->setflag(status_flags::dynallocated | status_flags::evaluated);
}
-ex relational::subs(const lst & ls, const lst & lr, bool no_pattern) const
+ex relational::subs(const lst & ls, const lst & lr, unsigned options) const
{
- const ex & subsed_lh = lh.subs(ls, lr, no_pattern);
- const ex & subsed_rh = rh.subs(ls, lr, no_pattern);
+ const ex & subsed_lh = lh.subs(ls, lr, options);
+ const ex & subsed_rh = rh.subs(ls, lr, options);
if (!are_ex_trivially_equal(lh, subsed_lh) || !are_ex_trivially_equal(rh, subsed_rh))
- return relational(subsed_lh, subsed_rh, o).basic::subs(ls, lr, no_pattern);
+ return relational(subsed_lh, subsed_rh, o).subs_one_level(ls, lr, options);
else
- return basic::subs(ls, lr, no_pattern);
+ return subs_one_level(ls, lr, options);
}
-ex relational::simplify_ncmul(const exvector & v) const
+ex relational::eval_ncmul(const exvector & v) const
{
- return lh.simplify_ncmul(v);
+ return lh.eval_ncmul(v);
}
// protected
return o == oth.o;
}
-unsigned relational::return_type(void) const
+unsigned relational::return_type() const
{
GINAC_ASSERT(lh.return_type()==rh.return_type());
return lh.return_type();
}
-unsigned relational::return_type_tinfo(void) const
+unsigned relational::return_type_tinfo() const
{
GINAC_ASSERT(lh.return_type_tinfo()==rh.return_type_tinfo());
return lh.return_type_tinfo();
}
-unsigned relational::calchash(void) const
+unsigned relational::calchash() const
{
unsigned v = golden_ratio_hash(tinfo());
unsigned lhash = lh.gethash();
unsigned rhash = rh.gethash();
- v = rotate_left_31(v);
+ v = rotate_left(v);
switch(o) {
case equal:
case not_equal:
lhash = rhash;
break;
}
- v = rotate_left_31(v);
+ v = rotate_left(v);
v ^= lhash;
- // mask out numeric hashes:
- v &= 0x7FFFFFFFU;
-
// store calculated hash value only if object is already evaluated
if (flags & status_flags::evaluated) {
setflag(status_flags::hash_calculated);
//////////
/** Left hand side of relational. */
-ex relational::lhs(void) const
+ex relational::lhs() const
{
return lh;
}
/** Right hand side of relational. */
-ex relational::rhs(void) const
+ex relational::rhs() const
{
return rh;
}
// non-virtual functions in this class
//////////
-/** Cast the relational into a boolean, mainly for evaluation within an
+relational::safe_bool relational::make_safe_bool(bool cond) const
+{
+ return cond? &safe_bool_helper::nonnull : 0;
+}
+
+/** Cast the relational into a boolean, mainly for evaluation within an
* if-statement. Note that (a<b) == false does not imply (a>=b) == true in
* the general symbolic case. A false result means the comparison is either
* false or undecidable (except of course for !=, where true means either
* unequal or undecidable). */
-relational::operator bool() const
+relational::operator relational::safe_bool() const
{
const ex df = lh-rh;
- if (!is_ex_exactly_of_type(df,numeric))
+ if (!is_exactly_a<numeric>(df))
// cannot decide on non-numerical results
- return o==not_equal ? true : false;
-
+ return o==not_equal ? make_safe_bool(true) : make_safe_bool(false);
+
switch (o) {
case equal:
- return ex_to<numeric>(df).is_zero();
+ return make_safe_bool(ex_to<numeric>(df).is_zero());
case not_equal:
- return !ex_to<numeric>(df).is_zero();
+ return make_safe_bool(!ex_to<numeric>(df).is_zero());
case less:
- return ex_to<numeric>(df)<_num0;
+ return make_safe_bool(ex_to<numeric>(df)<_num0);
case less_or_equal:
- return ex_to<numeric>(df)<=_num0;
+ return make_safe_bool(ex_to<numeric>(df)<=_num0);
case greater:
- return ex_to<numeric>(df)>_num0;
+ return make_safe_bool(ex_to<numeric>(df)>_num0);
case greater_or_equal:
- return ex_to<numeric>(df)>=_num0;
+ return make_safe_bool(ex_to<numeric>(df)>=_num0);
default:
throw(std::logic_error("invalid relational operator"));
}
greater_or_equal
};
- // other ctors
+ // other constructors
public:
relational(const ex & lhs, const ex & rhs, operators oper=equal);
// functions overriding virtual functions from base classes
public:
void print(const print_context & c, unsigned level = 0) const;
- unsigned precedence(void) const {return 20;}
+ unsigned precedence() const {return 20;}
bool info(unsigned inf) const;
- unsigned nops() const;
- ex & let_op(int i);
+ size_t nops() const;
+ ex op(size_t i) const;
+ ex map(map_function & f) const;
+ ex subs(const lst & ls, const lst & lr, unsigned options = 0) const;
ex eval(int level=0) const;
- ex subs(const lst & ls, const lst & lr, bool no_pattern = false) const;
- ex simplify_ncmul(const exvector & v) const;
protected:
+ ex eval_ncmul(const exvector & v) const;
bool match_same_type(const basic & other) const;
- unsigned return_type(void) const;
- unsigned return_type_tinfo(void) const;
- unsigned calchash(void) const;
+ unsigned return_type() const;
+ unsigned return_type_tinfo() const;
+ unsigned calchash() const;
// new virtual functions which can be overridden by derived classes
public:
- virtual ex lhs(void) const;
- virtual ex rhs(void) const;
+ virtual ex lhs() const;
+ virtual ex rhs() const;
// non-virtual functions in this class
-public:
- operator bool(void) const;
+private:
+ // For conversions to boolean, as would be used in an if conditional,
+ // implicit conversions from bool to int have a large number of
+ // undesirable side effects. The following safe_bool type enables
+ // use of relational objects in conditionals without those side effects
+ struct safe_bool_helper {
+ void nonnull() {};
+ };
+
+ typedef void (safe_bool_helper::*safe_bool)();
+ safe_bool make_safe_bool(bool) const;
+
+public:
+ operator safe_bool() const;
+ safe_bool operator!() const;
+
// member variables
protected:
return obj.tinfo()==TINFO_relational;
}
+// inlined functions for efficiency
+inline relational::safe_bool relational::operator!() const
+{
+ return make_safe_bool(!static_cast<bool>(*this));
+}
+
} // namespace GiNaC
#endif // ndef __GINAC_RELATIONAL_H__
{
GINAC_ASSERT(f.seq.size()==seq.size());
if (f.gethash()!=hashvalue) return false;
- unsigned num = seq.size();
- for (unsigned i=0; i<num; ++i)
+ size_t num = seq.size();
+ for (size_t i=0; i<num; ++i)
if (!seq[i].is_equal(f.seq[i])) return false;
++last_access = access_counter;
++successful_hits;
operator[](entry).add_entry(f,result);
}
-void remember_table::clear_all_entries(void)
+void remember_table::clear_all_entries()
{
clear();
init_table();
}
-void remember_table::init_table(void)
+void remember_table::init_table()
{
reserve(table_size);
for (unsigned i=0; i<table_size; ++i)
push_back(remember_table_list(max_assoc_size,remember_strategy));
}
-std::vector<remember_table> & remember_table::remember_tables(void)
+std::vector<remember_table> & remember_table::remember_tables()
{
static std::vector<remember_table> * rt = new std::vector<remember_table>;
return *rt;
public:
remember_table_entry(function const & f, ex const & r);
bool is_equal(function const & f) const;
- ex get_result(void) const { return result; }
- unsigned long get_last_access(void) const { return last_access; }
- unsigned long get_successful_hits(void) const { return successful_hits; };
+ ex get_result() const { return result; }
+ unsigned long get_last_access() const { return last_access; }
+ unsigned long get_successful_hits() const { return successful_hits; };
protected:
unsigned hashvalue;
remember_table(unsigned s, unsigned as, unsigned strat);
bool lookup_entry(function const & f, ex & result) const;
void add_entry(function const & f, ex const & result);
- void clear_all_entries(void);
+ void clear_all_entries();
void show_statistics(std::ostream & os, unsigned level) const;
- static std::vector<remember_table> & remember_tables(void);
+ static std::vector<remember_table> & remember_tables();
protected:
- void init_table(void);
+ void init_table();
unsigned table_size;
unsigned max_assoc_size;
unsigned remember_strategy;
/** @file structure.cpp
*
- * Implementation of 'abstract' class structure. */
+ * Wrapper template for making GiNaC classes out of C++ structures. */
/*
* GiNaC Copyright (C) 1999-2003 Johannes Gutenberg University Mainz, Germany
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <iostream>
-#include <string>
-
#include "structure.h"
-#include "archive.h"
-#include "utils.h"
-#include "print.h"
namespace GiNaC {
-GINAC_IMPLEMENT_REGISTERED_CLASS(structure, basic)
-
-//////////
-// default ctor, dtor, copy ctor, assignment operator and helpers
-//////////
-
-DEFAULT_CTORS(structure)
-
-//////////
-// archiving
-//////////
-
-DEFAULT_ARCHIVING(structure)
-
-//////////
-// functions overriding virtual functions from base classes
-//////////
-
-void structure::print(const print_context & c, unsigned level) const
-{
- if (is_a<print_tree>(c)) {
-
- c.s << std::string(level, ' ') << class_name()
- << std::hex << ", hash=0x" << hashvalue << ", flags=0x" << flags << std::dec
- << std::endl;
-
- } else
- c.s << class_name() << "()";
-}
-
-// protected
-
-DEFAULT_COMPARE(structure)
-
-bool structure::is_equal_same_type(const basic & other) const
-{
- GINAC_ASSERT(is_a<structure>(other));
- return true; // all structures are the same
-}
-
-//////////
-// non-virtual functions in this class
-//////////
-
-// protected
-
-std::vector<registered_structure_info> & structure::registered_structures(void)
-{
- static std::vector<registered_structure_info> * rs = new std::vector<registered_structure_info>;
- return *rs;
-}
-
-// public
-
-unsigned structure::register_new(const char * nm)
-{
- registered_structure_info rsi={nm};
- registered_structures().push_back(rsi);
- return registered_structures().size()-1;
-}
+// Next free tinfo_key for structure types
+unsigned next_structure_tinfo_key = TINFO_structure;
} // namespace GiNaC
/** @file structure.h
*
- * Interface to 'abstract' class structure. */
+ * Wrapper template for making GiNaC classes out of C++ structures. */
/*
* GiNaC Copyright (C) 1999-2003 Johannes Gutenberg University Mainz, Germany
#ifndef __GINAC_STRUCTURE_H__
#define __GINAC_STRUCTURE_H__
-#include "basic.h"
+#include <functional>
+
+#include "ex.h"
+#include "print.h"
namespace GiNaC {
-struct registered_structure_info {
- const char * name;
+extern unsigned next_structure_tinfo_key;
+
+
+/** Comparison policy: all structures of one type are equal */
+template <class T>
+class compare_all_equal {
+protected:
+ static bool struct_is_equal(const T * t1, const T * t2) { return true; }
+ static int struct_compare(const T * t1, const T * t2) { return 0; }
+
+ // disallow destruction of structure through a compare_all_equal*
+protected:
+ ~compare_all_equal() {}
};
-/** The class structure is used to implement user defined classes
- with named members which behave similar to ordinary C structs.
- structure is an 'abstract' base class (it is possible but not
- meaningful to make instances), the user defined structures
- will be create by the perl script structure.pl */
-class structure : public basic
-{
+/** Comparison policy: use std::equal_to/std::less (defaults to operators
+ * == and <) to compare structures. */
+template <class T>
+class compare_std_less {
+protected:
+ static bool struct_is_equal(const T * t1, const T * t2)
+ {
+ return std::equal_to<T>()(*t1, *t2);
+ }
+
+ static int struct_compare(const T * t1, const T * t2)
+ {
+ if (std::less<T>()(*t1, *t2))
+ return -1;
+ else if (std::less<T>()(*t2, *t1))
+ return 1;
+ else
+ return 0;
+ }
+
+ // disallow destruction of structure through a compare_std_less*
+protected:
+ ~compare_std_less() {}
+};
+
+
+/** Comparison policy: use bit-wise comparison to compare structures. */
+template <class T>
+class compare_bitwise {
+protected:
+ static bool struct_is_equal(const T * t1, const T * t2)
+ {
+ const char * cp1 = reinterpret_cast<const char *>(t1);
+ const char * cp2 = reinterpret_cast<const char *>(t2);
+
+ return std::equal(cp1, cp1 + sizeof(T), cp2);
+ }
+
+ static int struct_compare(const T * t1, const T * t2)
+ {
+ const unsigned char * cp1 = reinterpret_cast<const unsigned char *>(t1);
+ const unsigned char * cp2 = reinterpret_cast<const unsigned char *>(t2);
+ typedef std::pair<const unsigned char *, const unsigned char *> cppair;
+
+ cppair res = std::mismatch(cp1, cp1 + sizeof(T), cp2);
+
+ if (res.first == cp1 + sizeof(T))
+ return 0;
+ else if (*res.first < *res.second)
+ return -1;
+ else
+ return 1;
+ }
+
+ // disallow destruction of structure through a compare_bitwise*
+protected:
+ ~compare_bitwise() {}
+};
+
+
+// Select default comparison policy
+template <class T, template <class> class ComparisonPolicy = compare_all_equal> class structure;
+
+
+/** Wrapper template for making GiNaC classes out of C++ structures. */
+template <class T, template <class> class ComparisonPolicy>
+class structure : public basic, public ComparisonPolicy<T> {
GINAC_DECLARE_REGISTERED_CLASS(structure, basic)
-
+
+ // helpers
+ static unsigned get_tinfo() { return reg_info.tinfo_key; }
+ static const char *get_class_name() { return "structure"; }
+
+ // constructors
+public:
+ /** Construct structure as a copy of a given C++ structure. */
+ structure(const T & t) : inherited(get_tinfo()), obj(t) { }
+
// functions overriding virtual functions from base classes
+ // All these are just defaults that can be specialized by the user
public:
- void print(const print_context & c, unsigned level=0) const;
+ // evaluation
+ ex eval(int level = 0) const { return hold(); }
+ ex evalf(int level = 0) const { return inherited::evalf(level); }
+ ex evalm() const { return inherited::evalm(); }
protected:
- bool is_equal_same_type(const basic & other) const;
-
- // non-virtual functions in this class
+ ex eval_ncmul(const exvector & v) const { return hold_ncmul(v); }
+public:
+ ex eval_indexed(const basic & i) const { return i.hold(); }
+
+ // printing
+ void print(const print_context & c, unsigned level = 0) const { inherited::print(c, level); }
+ unsigned precedence() const { return 70; }
+
+ // info
+ bool info(unsigned inf) const { return false; }
+
+ // operand access
+ size_t nops() const { return 0; }
+ ex op(size_t i) const { return inherited::op(i); }
+ ex operator[](const ex & index) const { return inherited::operator[](index); }
+ ex operator[](size_t i) const { return inherited::operator[](i); }
+ ex & let_op(size_t i) { return inherited::let_op(i); }
+ ex & operator[](const ex & index) { return inherited::operator[](index); }
+ ex & operator[](size_t i) { return inherited::operator[](i); }
+
+ // pattern matching
+ bool has(const ex & other) const { return inherited::has(other); }
+ bool match(const ex & pattern, lst & repl_lst) const { return inherited::match(pattern, repl_lst); }
+protected:
+ bool match_same_type(const basic & other) const { return true; }
+public:
+
+ // substitutions
+ ex subs(const lst & ls, const lst & lr, unsigned options = 0) const { return inherited::subs(ls, lr, options); }
+
+ // function mapping
+ ex map(map_function & f) const { return inherited::map(f); }
+
+ // degree/coeff
+ int degree(const ex & s) const { return inherited::degree(s); }
+ int ldegree(const ex & s) const { return inherited::ldegree(s); }
+ ex coeff(const ex & s, int n = 1) const { return inherited::coeff(s, n); }
+
+ // expand/collect
+ ex expand(unsigned options = 0) const { return inherited::expand(options); }
+ ex collect(const ex & s, bool distributed = false) const { return inherited::collect(s, distributed); }
+
+ // differentiation and series expansion
protected:
- static std::vector<registered_structure_info> & registered_structures(void);
+ ex derivative(const symbol & s) const { return inherited::derivative(s); }
+public:
+ ex series(const relational & r, int order, unsigned options = 0) const { return inherited::series(r, order, options); }
+
+ // rational functions
+ ex normal(lst & sym_lst, lst & repl_lst, int level = 0) const { return inherited::normal(sym_lst, repl_lst, level); }
+ ex to_rational(lst & repl_lst) const { return inherited::to_rational(repl_lst); }
+ ex to_polynomial(lst & repl_lst) const { return inherited::to_polynomial(repl_lst); }
+
+ // polynomial algorithms
+ numeric integer_content() const { return 1; }
+ ex smod(const numeric & xi) const { return *this; }
+ numeric max_coefficient() const { return 1; }
+
+ // indexed objects
+ exvector get_free_indices() const { return exvector(); }
+ ex add_indexed(const ex & self, const ex & other) const { return self + other; }
+ ex scalar_mul_indexed(const ex & self, const numeric & other) const { return self * other; }
+ bool contract_with(exvector::iterator self, exvector::iterator other, exvector & v) const { return false; }
+
+ // noncommutativity
+ unsigned return_type() const { return return_types::commutative; }
+ unsigned return_type_tinfo() const { return tinfo(); }
+
+protected:
+ bool is_equal_same_type(const basic & other) const
+ {
+ GINAC_ASSERT(is_a<structure>(other));
+ const structure & o = static_cast<const structure &>(other);
+
+ return struct_is_equal(&obj, &o.obj);
+ }
+
+ unsigned calchash() const { return inherited::calchash(); }
+
+ // non-virtual functions in this class
public:
- static unsigned register_new(const char * nm);
+ // access to embedded structure
+ const T *operator->() const { return &obj; }
+ T &get_struct() { return obj; }
+ const T &get_struct() const { return obj; }
+
+private:
+ T obj;
};
+
+/** Default constructor */
+template <class T, template <class> class CP>
+structure<T, CP>::structure() : inherited(get_tinfo()) { }
+
+/** Construct object from archive_node. */
+template <class T, template <class> class CP>
+structure<T, CP>::structure(const archive_node &n, lst &sym_lst) : inherited(n, sym_lst) {}
+
+/** Unarchive the object. */
+template <class T, template <class> class CP>
+ex structure<T, CP>::unarchive(const archive_node &n, lst &sym_lst)
+{
+ return (new structure(n, sym_lst))->setflag(status_flags::dynallocated);
+}
+
+/** Archive the object. */
+template <class T, template <class> class CP>
+void structure<T, CP>::archive(archive_node &n) const
+{
+ inherited::archive(n);
+}
+
+/** Compare two structures of the same type. */
+template <class T, template <class> class CP>
+int structure<T, CP>::compare_same_type(const basic & other) const
+{
+ GINAC_ASSERT(is_a<structure>(other));
+ const structure & o = static_cast<const structure &>(other);
+
+ return struct_compare(&obj, &o.obj);
+}
+
+template <class T, template <class> class CP>
+registered_class_info structure<T, CP>::reg_info(structure::get_class_name(), "basic", next_structure_tinfo_key++, &structure::unarchive);
+
+template <class T, template <class> class CP>
+const char *structure<T, CP>::class_name() const { return reg_info.name; }
+
+
} // namespace GiNaC
#endif // ndef __GINAC_STRUCTURE_H__
+++ /dev/null
-#!/usr/bin/perl -w
-
-$input_structure='';
-$original_input_structure='';
-while (<>) {
- $input_structure .= '// '.$_;
- $original_input_structure .= $_;
-}
-
-$original_input_structure =~ tr/ \t\n\r\f/ /;
-$original_input_structure =~ tr/ //s;
-
-if ($original_input_structure =~ /^struct (\w+) ?\{ ?(.*)\}\;? ?$/) {
- $STRUCTURE=$1;
- $decl=$2;
-} else {
- die "illegal struct, must match 'struct name { type var; /*comment*/ ...};': $original_input_structure";
-}
-
-# split off a part 'type var[,var...];' with a possible C-comment '/* ... */'
-while ($decl =~ /^ ?(\w+) ([\w \,]+)\; ?((\/\*.*?\*\/)?)(.*)$/) {
- $type=$1;
- $member=$2;
- $comment=$3;
- $decl=$5;
- while ($member =~ /^(\w+) ?\, ?(.*)$/) {
- push @TYPES,$type;
- push @MEMBERS,$1;
- push @COMMENTS,$comment;
- if ($comment ne '') {
- $comment='/* see above */';
- }
- $member=$2;
- }
- if ($member !~ /^\w+$/) {
- die "illegal struct, must match 'struct name { type var; /*comment*/ ...};': $input_structure";
- }
- push @TYPES,$type;
- push @MEMBERS,$member;
- push @COMMENTS,$comment;
-}
-
-if ($decl !~ /^ ?$/) {
- die "illegal struct, must match 'struct name { type var; /*comment*/ ...};': $input_structure";
-}
-
-#$STRUCTURE='teststruct';
-$STRUCTURE_UC=uc(${STRUCTURE});
-#@TYPES=('ex','ex','ex');
-#@MEMBERS=('q10','q20','q21');
-
-sub generate {
- my ($template,$conj)=@_;
- my ($res,$N);
-
- $res='';
- for ($N=1; $N<=$#MEMBERS+1; $N++) {
- $TYPE=$TYPES[$N-1];
- $MEMBER=$MEMBERS[$N-1];
- $COMMENT=$COMMENTS[$N-1];
- $res .= eval('"' . $template . '"');
- $TYPE=''; # to avoid main::TYPE used only once warning
- $MEMBER=''; # same as above
- $COMMENT=''; # same as above
- if ($N!=$#MEMBERS+1) {
- $res .= $conj;
- }
- }
- return $res;
-}
-
-$number_of_members=$#MEMBERS+1;
-$constructor_arglist=generate('ex tmp_${MEMBER}',', ');
-$member_access_functions=generate(' const ex & ${MEMBER}(void) { return m_${MEMBER}; }',"\n");
-$op_access_indices_decl=generate(' static unsigned op_${MEMBER};',"\n");
-$op_access_indices_def=generate('unsigned ${STRUCTURE}::op_${MEMBER}=${N}-1;',"\n");
-$members=generate(' ex m_${MEMBER}; ${COMMENT}',"\n");
-$copy_statements=generate(' m_${MEMBER}=other.m_${MEMBER};',"\n");
-$constructor_statements=generate('m_${MEMBER}(tmp_${MEMBER})',', ');
-$let_op_statements=generate(
-' case ${N}-1:'."\n".
-' return m_${MEMBER};'."\n".
-' break;',
-"\n");
-$temporary_arglist=generate('tmp_${MEMBER}',', ');
-$expand_statements=generate(' ex tmp_${MEMBER}=m_${MEMBER}.expand(options);',"\n");
-$has_statements=generate(' if (m_${MEMBER}.has(other)) return true;',"\n");
-$eval_statements=generate(
-' ex tmp_${MEMBER}=m_${MEMBER}.eval(level-1);'."\n".
-' all_are_trivially_equal = all_are_trivially_equal &&'."\n".
-' are_ex_trivially_equal(tmp_${MEMBER},m_${MEMBER});',
-"\n");
-$evalf_statements=generate(
-' ex tmp_${MEMBER}=m_${MEMBER}.evalf(level-1);'."\n".
-' all_are_trivially_equal = all_are_trivially_equal &&'."\n".
-' are_ex_trivially_equal(tmp_${MEMBER},m_${MEMBER});',
-"\n");
-$normal_statements=generate(
-' ex tmp_${MEMBER}=m_${MEMBER}.normal(level-1);'."\n".
-' all_are_trivially_equal = all_are_trivially_equal &&'."\n".
-' are_ex_trivially_equal(tmp_${MEMBER},m_${MEMBER});',
-"\n");
-$diff_statements=generate(' ex tmp_${MEMBER}=m_${MEMBER}.diff(s);',"\n");
-$subs_statements=generate(
-' ex tmp_${MEMBER}=m_${MEMBER}.subs(ls,lr);'."\n".
-' all_are_trivially_equal = all_are_trivially_equal &&'."\n".
-' are_ex_trivially_equal(tmp_${MEMBER},m_${MEMBER});',
-"\n");
-$compare_statements=generate(
-' cmpval=m_${MEMBER}.compare(o.m_${MEMBER});'."\n".
-' if (cmpval!=0) return cmpval;',
-"\n");
-$is_equal_statements=generate(' if (!m_${MEMBER}.is_equal(o.m_${MEMBER})) return false;',"\n");
-$types_ok_statements=generate(
-'#ifndef SKIP_TYPE_CHECK_FOR_${TYPE}'."\n".
-' if (!is_ex_exactly_of_type(m_${MEMBER},${TYPE})) return false;'."\n".
-'#endif // ndef SKIP_TYPE_CHECK_FOR_${TYPE}',"\n");
-
-$interface=<<END_OF_INTERFACE;
-/** \@file ${STRUCTURE}.h
- *
- * Definition of GiNaC's user defined structure ${STRUCTURE}. */
-
-/*
- * This file was generated automatically by structure.pl.
- * Please do not modify it directly, edit the perl script instead!
- *
- * GiNaC Copyright (C) 1999-2003 Johannes Gutenberg University Mainz, Germany
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-// structure.pl input:
-${input_structure}
-
-#ifndef __GINAC_${STRUCTURE_UC}_H__
-#define __GINAC_${STRUCTURE_UC}_H__
-
-#include "structure.h"
-
-namespace GiNaC {
-
-class ${STRUCTURE} : public structure
-{
-// member functions
-
- // default ctor, dtor, copy ctor, assignment operator and helpers
-public:
- ${STRUCTURE}();
- ~${STRUCTURE}();
- ${STRUCTURE}(${STRUCTURE} const & other);
- ${STRUCTURE} const & operator=(${STRUCTURE} const & other);
-protected:
- void copy(${STRUCTURE} const & other);
- void destroy(bool call_parent);
-
- // other ctors
-public:
- ${STRUCTURE}(${constructor_arglist});
-
- // functions overriding virtual functions from base classes
-public:
- basic * duplicate() const;
- void print(const print_context & c, unsigned level = 0) const;
- int nops() const;
- ex & let_op(int i);
- ex expand(unsigned options=0) const;
- bool has(const ex & other) const;
- ex eval(int level=0) const;
- ex evalf(int level=0) const;
- ex normal(lst &sym_lst, lst &repl_lst, int level=0) const;
- ex diff(const symbol & s) const;
- ex subs(const lst & ls, const lst & lr) const;
-protected:
- int compare_same_type(const basic & other) const;
- bool is_equal_same_type(const basic & other) const;
- unsigned return_type(void) const;
-
- // new virtual functions which can be overridden by derived classes
- // none
-
- // non-virtual functions in this class
-public:
-${member_access_functions}
- bool types_ok(void) const;
-
-// member variables
-protected:
-${members}
-public:
-${op_access_indices_decl}
-};
-
-// global constants
-
-extern const ${STRUCTURE} some_${STRUCTURE};
-extern const type_info & typeid_${STRUCTURE};
-extern const unsigned tinfo_${STRUCTURE};
-
-} // namespace GiNaC
-
-#endif // ndef _${STRUCTURE_UC}_H_
-
-END_OF_INTERFACE
-
-$implementation=<<END_OF_IMPLEMENTATION;
-/** \@file ${STRUCTURE}.cpp
- *
- * Implementation of GiNaC's user defined structure ${STRUCTURE}. */
-
-/*
- * This file was generated automatically by STRUCTURE.pl.
- * Please do not modify it directly, edit the perl script instead!
- *
- * GiNaC Copyright (C) 1999-2003 Johannes Gutenberg University Mainz, Germany
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-// structure.pl input:
-${input_structure}
-
-#include <iostream>
-#include <stdexcept>
-
-#include "${STRUCTURE}.h"
-#include "print.h"
-
-namespace GiNaC {
-
-//////////
-// default ctor, destructor, copy ctor assignment operator and helpers
-//////////
-
-// public
-
-${STRUCTURE}::${STRUCTURE}()
-{
- tinfo_key=tinfo_${STRUCTURE};
-}
-
-${STRUCTURE}::~${STRUCTURE}()
-{
- destroy(false);
-}
-
-${STRUCTURE}::${STRUCTURE}(${STRUCTURE} const & other)
-{
- copy(other);
-}
-
-${STRUCTURE} const & ${STRUCTURE}::operator=(${STRUCTURE} const & other)
-{
- if (this != &other) {
- destroy(true);
- copy(other);
- }
- return *this;
-}
-
-// protected
-
-void ${STRUCTURE}::copy(${STRUCTURE} const & other)
-{
- structure::copy(other);
-${copy_statements}
-}
-
-void ${STRUCTURE}::destroy(bool call_parent)
-{
- if (call_parent) structure::destroy(call_parent);
-}
-
-//////////
-// other ctors
-//////////
-
-// public
-
-${STRUCTURE}::${STRUCTURE}(${constructor_arglist})
- : ${constructor_statements}
-{
- tinfo_key=tinfo_${STRUCTURE};
-}
-
-//////////
-// functions overriding virtual functions from base classes
-//////////
-
-// public
-
-basic * ${STRUCTURE}::duplicate() const
-{
- return new ${STRUCTURE}(*this);
-}
-
-void ${STRUCTURE}::print(const print_context & c, unsigned level) const
-{
- c.s << class_name() << "()";
-}
-
-int ${STRUCTURE}::nops() const
-{
- return ${number_of_members};
-}
-
-ex & ${STRUCTURE}::let_op(int i)
-{
- GINAC_ASSERT(i>=0);
- GINAC_ASSERT(i<nops());
-
- switch (i) {
-${let_op_statements}
- }
- throw(std::runtime_error("${STRUCTURE}::let_op(): should not have reached this point"));
-}
-
-ex ${STRUCTURE}::expand(unsigned options) const
-{
- bool all_are_trivially_equal=true;
-${expand_statements}
- if (all_are_trivially_equal) {
- return *this;
- }
- return ${STRUCTURE}(${temporary_arglist});
-}
-
-// a ${STRUCTURE} 'has' an expression if it is this expression itself or a child 'has' it
-
-bool ${STRUCTURE}::has(const ex & other) const
-{
- GINAC_ASSERT(other.bp!=0);
- if (is_equal(*other.bp)) return true;
-${has_statements}
- return false;
-}
-
-ex ${STRUCTURE}::eval(int level) const
-{
- if (level==1) {
- return this->hold();
- }
- bool all_are_trivially_equal=true;
-${eval_statements}
- if (all_are_trivially_equal) {
- return this->hold();
- }
- return ${STRUCTURE}(${temporary_arglist});
-}
-
-ex ${STRUCTURE}::evalf(int level) const
-{
- if (level==1) {
- return *this;
- }
- bool all_are_trivially_equal=true;
-${evalf_statements}
- if (all_are_trivially_equal) {
- return *this;
- }
- return ${STRUCTURE}(${temporary_arglist});
-}
-
-/** Implementation of ex::normal() for ${STRUCTURE}s. It normalizes the arguments
- * and replaces the ${STRUCTURE} by a temporary symbol.
- * \@see ex::normal */
-ex ${STRUCTURE}::normal(lst &sym_lst, lst &repl_lst, int level) const
-{
- if (level==1) {
- return basic::normal(sym_lst,repl_lst,level);
- }
- bool all_are_trivially_equal=true;
-${normal_statements}
- if (all_are_trivially_equal) {
- return basic::normal(sym_lst,repl_lst,level);
- }
- ex n=${STRUCTURE}(${temporary_arglist});
- return n.bp->basic::normal(sym_lst,repl_lst,level);
-}
-
-/** ${STRUCTURE}::diff() differentiates the children.
- there is no need to check for triavially equal, since diff usually
- does not return itself unevaluated. */
-ex ${STRUCTURE}::diff(const symbol & s) const
-{
-${diff_statements}
- return ${STRUCTURE}(${temporary_arglist});
-}
-
-ex ${STRUCTURE}::subs(const lst & ls, const lst & lr) const
-{
- bool all_are_trivially_equal=true;
-${subs_statements}
- if (all_are_trivially_equal) {
- return *this;
- }
- return ${STRUCTURE}(${temporary_arglist});
-}
-
-// protected
-
-int ${STRUCTURE}::compare_same_type(const basic & other) const
-{
- GINAC_ASSERT(is_of_type(other,${STRUCTURE}));
- ${STRUCTURE} const &o = static_cast<const ${STRUCTURE} &>(other);
- int cmpval;
-${compare_statements}
- return 0;
-}
-
-bool ${STRUCTURE}::is_equal_same_type(const basic & other) const
-{
- GINAC_ASSERT(is_of_type(other,${STRUCTURE}));
- ${STRUCTURE} const &o = static_cast<const ${STRUCTURE} &>(other);
-${is_equal_statements}
- return true;
-}
-
-unsigned ${STRUCTURE}::return_type(void) const
-{
- return return_types::noncommutative_composite;
-}
-
-//////////
-// new virtual functions which can be overridden by derived classes
-//////////
-
-// none
-
-//////////
-// non-virtual functions in this class
-//////////
-
-// public
-
-#define SKIP_TYPE_CHECK_FOR_ex
-// this is a hack since there is no meaningful
-// is_ex_exactly_of_type(...,ex) macro definition
-
-bool ${STRUCTURE}::types_ok(void) const
-{
-${types_ok_statements}
- return true;
-}
-
-//////////
-// static member variables
-//////////
-
-${op_access_indices_def}
-
-//////////
-// global constants
-//////////
-
-const ${STRUCTURE} some_${STRUCTURE};
-const type_info & typeid_${STRUCTURE}=typeid(some_${STRUCTURE});
-const unsigned tinfo_${STRUCTURE}=structure::register_new("${STRUCTURE}");
-
-} // namespace GiNaC
-
-END_OF_IMPLEMENTATION
-
-print "Creating interface file ${STRUCTURE}.h...";
-open OUT,">${STRUCTURE}.h" or die "cannot open ${STRUCTURE}.h";
-print OUT $interface;
-close OUT;
-print "ok.\n";
-
-print "Creating implementation file ${STRUCTURE}.cpp...";
-open OUT,">${STRUCTURE}.cpp" or die "cannot open ${STRUCTURE}.cpp";
-print OUT $implementation;
-close OUT;
-print "ok.\n";
-
-print "done.\n";
GINAC_IMPLEMENT_REGISTERED_CLASS(symbol, basic)
//////////
-// default ctor, dtor, copy ctor, assignment operator and helpers
+// default constructor
//////////
-symbol::symbol() : inherited(TINFO_symbol), serial(next_serial++)
+symbol::symbol()
+ : inherited(TINFO_symbol), asexinfop(new assigned_ex_info), serial(next_serial++), name(autoname_prefix() + ToString(serial)), TeX_name(name)
{
- name = TeX_name = autoname_prefix()+ToString(serial);
- asexinfop = new assigned_ex_info;
setflag(status_flags::evaluated | status_flags::expanded);
}
-/** For use by copy ctor and assignment operator. */
-void symbol::copy(const symbol & other)
-{
- inherited::copy(other);
- name = other.name;
- TeX_name = other.TeX_name;
- serial = other.serial;
- asexinfop = other.asexinfop;
- ++(asexinfop->refcount);
-}
-
-void symbol::destroy(bool call_parent)
-{
- if (--asexinfop->refcount == 0)
- delete asexinfop;
- if (call_parent)
- inherited::destroy(call_parent);
-}
-
//////////
-// other ctors
+// other constructors
//////////
// public
-symbol::symbol(const std::string & initname) : inherited(TINFO_symbol)
+symbol::symbol(const std::string & initname)
+ : inherited(TINFO_symbol), asexinfop(new assigned_ex_info), serial(next_serial++), name(initname), TeX_name(default_TeX_name())
{
- name = initname;
- TeX_name = default_TeX_name();
- serial = next_serial++;
- asexinfop = new assigned_ex_info;
setflag(status_flags::evaluated | status_flags::expanded);
}
-symbol::symbol(const std::string & initname, const std::string & texname) : inherited(TINFO_symbol)
+symbol::symbol(const std::string & initname, const std::string & texname)
+ : inherited(TINFO_symbol), asexinfop(new assigned_ex_info), serial(next_serial++), name(initname), TeX_name(texname)
{
- name = initname;
- TeX_name = texname;
- serial = next_serial++;
- asexinfop = new assigned_ex_info;
setflag(status_flags::evaluated | status_flags::expanded);
}
//////////
/** Construct object from archive_node. */
-symbol::symbol(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
+symbol::symbol(const archive_node &n, lst &sym_lst)
+ : inherited(n, sym_lst), asexinfop(new assigned_ex_info), serial(next_serial++)
{
- serial = next_serial++;
if (!(n.find_string("name", name)))
name = autoname_prefix() + ToString(serial);
if (!(n.find_string("TeXname", TeX_name)))
TeX_name = default_TeX_name();
- asexinfop = new assigned_ex_info;
setflag(status_flags::evaluated);
}
/** Unarchive the object. */
-ex symbol::unarchive(const archive_node &n, const lst &sym_lst)
+ex symbol::unarchive(const archive_node &n, lst &sym_lst)
{
ex s = (new symbol(n, sym_lst))->setflag(status_flags::dynallocated);
-
+
// If symbol is in sym_lst, return the existing symbol
- for (unsigned i=0; i<sym_lst.nops(); i++) {
- if (is_ex_of_type(sym_lst.op(i), symbol) && (ex_to<symbol>(sym_lst.op(i)).name == ex_to<symbol>(s).name))
- return sym_lst.op(i);
+ for (lst::const_iterator it = sym_lst.begin(); it != sym_lst.end(); ++it) {
+ if (is_a<symbol>(*it) && (ex_to<symbol>(*it).name == ex_to<symbol>(s).name))
+ return *it;
}
+
+ // Otherwise add new symbol to list and return it
+ sym_lst.append(s);
return s;
}
return serial==o->serial;
}
-unsigned symbol::calchash(void) const
+unsigned symbol::calchash() const
{
- // this is where the schoolbook method
- // (golden_ratio_hash(tinfo()) ^ serial)
- // is not good enough yet...
- hashvalue = golden_ratio_hash(golden_ratio_hash(tinfo()) ^ serial);
+ hashvalue = golden_ratio_hash(tinfo() ^ serial);
setflag(status_flags::hash_calculated);
return hashvalue;
}
void symbol::assign(const ex & value)
{
- asexinfop->is_assigned = 1;
+ asexinfop->is_assigned = true;
asexinfop->assigned_expression = value;
clearflag(status_flags::evaluated | status_flags::expanded);
}
-void symbol::unassign(void)
+void symbol::unassign()
{
if (asexinfop->is_assigned) {
- asexinfop->is_assigned = 0;
+ asexinfop->is_assigned = false;
asexinfop->assigned_expression = _ex0;
}
setflag(status_flags::evaluated | status_flags::expanded);
/** Symbols not constructed with a string get one assigned using this
* prefix and a number. */
-std::string & symbol::autoname_prefix(void)
+std::string & symbol::autoname_prefix()
{
static std::string *s = new std::string("symbol");
return *s;
}
/** Return default TeX name for symbol. This recognizes some greek letters. */
-std::string symbol::default_TeX_name(void) const
+std::string symbol::default_TeX_name() const
{
if (name=="alpha" || name=="beta" || name=="gamma"
|| name=="delta" || name=="epsilon" || name=="varepsilon"
//////////
/** Default ctor. Defaults to unassigned. */
-symbol::assigned_ex_info::assigned_ex_info(void) : is_assigned(0), refcount(1)
+symbol::assigned_ex_info::assigned_ex_info() : is_assigned(false)
{
}
#include <string>
#include "basic.h"
#include "ex.h"
+#include "ptr.h"
namespace GiNaC {
class symbol : public basic
{
GINAC_DECLARE_REGISTERED_CLASS(symbol, basic)
-
+
// types
- /** Symbols as keys to expressions - this is deprecated. */
+ /** Symbols as keys to expressions - only for ginsh. */
class assigned_ex_info {
+ friend class ptr<assigned_ex_info>;
public:
assigned_ex_info(); ///< Default ctor
bool is_assigned; ///< True if there is an expression assigned
ex assigned_expression; ///< The actual expression
- unsigned refcount; ///< Reference counter
+ private:
+ size_t refcount; ///< Reference counter, managed by ptr<assigned_ex_info>
};
-
+
// member functions
- // other ctors
+ // other constructors
public:
explicit symbol(const std::string & initname);
explicit symbol(const std::string & initname, const std::string & texname);
ex eval(int level = 0) const;
ex evalf(int level = 0) const { return *this; } // overwrites basic::evalf() for performance reasons
ex series(const relational & s, int order, unsigned options = 0) const;
+ ex subs(const lst & ls, const lst & lr, unsigned options = 0) const { return subs_one_level(ls, lr, options); } // overwrites basic::subs() for performance reasons
ex normal(lst &sym_lst, lst &repl_lst, int level = 0) const;
ex to_rational(lst &repl_lst) const;
+ ex to_polynomial(lst &repl_lst) const;
protected:
ex derivative(const symbol & s) const;
bool is_equal_same_type(const basic & other) const;
- unsigned calchash(void) const;
+ unsigned calchash() const;
// non-virtual functions in this class
public:
void assign(const ex & value);
- void unassign(void);
+ void unassign();
void set_name(const std::string & n) { name = n; }
- std::string get_name(void) const { return name; }
+ std::string get_name() const { return name; }
private:
- std::string & autoname_prefix(void);
- std::string default_TeX_name(void) const;
+ std::string & autoname_prefix();
+ std::string default_TeX_name() const;
// member variables
protected:
- assigned_ex_info * asexinfop; ///< ptr to assigned expression, deprecated
- unsigned serial; ///< unique serial number for comparison
- std::string name; ///< printname of this symbol
- std::string TeX_name; ///< LaTeX name of this symbol
+ ptr<assigned_ex_info> asexinfop; ///< assigned expression, only for private use by ginsh
+ unsigned serial; ///< unique serial number for comparison
+ std::string name; ///< printname of this symbol
+ std::string TeX_name; ///< LaTeX name of this symbol
private:
static unsigned next_serial;
};
#include "symmetry.h"
#include "lst.h"
#include "numeric.h" // for factorial()
+#include "operators.h"
#include "print.h"
#include "archive.h"
#include "utils.h"
*/
//////////
-// default ctor, dtor, copy ctor, assignment operator and helpers
+// default constructor
//////////
symmetry::symmetry() : type(none)
tinfo_key = TINFO_symmetry;
}
-void symmetry::copy(const symmetry & other)
-{
- inherited::copy(other);
- type = other.type;
- indices = other.indices;
- children = other.children;
-}
-
-DEFAULT_DESTROY(symmetry)
-
//////////
// other constructors
//////////
//////////
/** Construct object from archive_node. */
-symmetry::symmetry(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
+symmetry::symmetry(const archive_node &n, lst &sym_lst) : inherited(n, sym_lst)
{
unsigned t;
if (!(n.find_unsigned("type", t)))
default: c.s << '?'; break;
}
c.s << '(';
- unsigned num = children.size();
- for (unsigned i=0; i<num; i++) {
+ size_t num = children.size();
+ for (size_t i=0; i<num; i++) {
children[i].print(c);
if (i != num - 1)
c.s << ",";
if (num < 2)
return e;
- // Transform object vector to a list
- exlist iv_lst;
- iv_lst.insert(iv_lst.begin(), first, last);
- lst orig_lst(iv_lst, true);
+ // Transform object vector to a lst (for subs())
+ lst orig_lst(first, last);
// Create index vectors for permutation
unsigned *iv = new unsigned[num], *iv2;
if (num < 2)
return e;
- // Transform object vector to a list
- exlist iv_lst;
- iv_lst.insert(iv_lst.begin(), first, last);
- lst orig_lst(iv_lst, true);
+ // Transform object vector to a lst (for subs())
+ lst orig_lst(first, last);
lst new_lst = orig_lst;
// Loop over all cyclic permutations (the first permutation, which is
/** Symmetrize expression over a list of objects (symbols, indices). */
ex ex::symmetrize(const lst & l) const
{
- exvector v;
- v.reserve(l.nops());
- for (unsigned i=0; i<l.nops(); i++)
- v.push_back(l.op(i));
+ exvector v(l.begin(), l.end());
return symm(*this, v.begin(), v.end(), false);
}
/** Antisymmetrize expression over a list of objects (symbols, indices). */
ex ex::antisymmetrize(const lst & l) const
{
- exvector v;
- v.reserve(l.nops());
- for (unsigned i=0; i<l.nops(); i++)
- v.push_back(l.op(i));
+ exvector v(l.begin(), l.end());
return symm(*this, v.begin(), v.end(), true);
}
* (symbols, indices). */
ex ex::symmetrize_cyclic(const lst & l) const
{
- exvector v;
- v.reserve(l.nops());
- for (unsigned i=0; i<l.nops(); i++)
- v.push_back(l.op(i));
+ exvector v(l.begin(), l.end());
return GiNaC::symmetrize_cyclic(*this, v.begin(), v.end());
}
void validate(unsigned n);
/** Check whether this node actually represents any kind of symmetry. */
- bool has_symmetry(void) const {return type != none || !children.empty(); }
+ bool has_symmetry() const {return type != none || !children.empty(); }
// member variables
private:
// global functions
-inline symmetry sy_none(void) { return symmetry(); }
+inline symmetry sy_none() { return symmetry(); }
inline symmetry sy_none(const symmetry &c1, const symmetry &c2) { return symmetry(symmetry::none, c1, c2); }
inline symmetry sy_none(const symmetry &c1, const symmetry &c2, const symmetry &c3) { return symmetry(symmetry::none, c1, c2).add(c3); }
inline symmetry sy_none(const symmetry &c1, const symmetry &c2, const symmetry &c3, const symmetry &c4) { return symmetry(symmetry::none, c1, c2).add(c3).add(c4); }
-inline symmetry sy_symm(void) { symmetry s; s.set_type(symmetry::symmetric); return s; }
+inline symmetry sy_symm() { symmetry s; s.set_type(symmetry::symmetric); return s; }
inline symmetry sy_symm(const symmetry &c1, const symmetry &c2) { return symmetry(symmetry::symmetric, c1, c2); }
inline symmetry sy_symm(const symmetry &c1, const symmetry &c2, const symmetry &c3) { return symmetry(symmetry::symmetric, c1, c2).add(c3); }
inline symmetry sy_symm(const symmetry &c1, const symmetry &c2, const symmetry &c3, const symmetry &c4) { return symmetry(symmetry::symmetric, c1, c2).add(c3).add(c4); }
-inline symmetry sy_anti(void) { symmetry s; s.set_type(symmetry::antisymmetric); return s; }
+inline symmetry sy_anti() { symmetry s; s.set_type(symmetry::antisymmetric); return s; }
inline symmetry sy_anti(const symmetry &c1, const symmetry &c2) { return symmetry(symmetry::antisymmetric, c1, c2); }
inline symmetry sy_anti(const symmetry &c1, const symmetry &c2, const symmetry &c3) { return symmetry(symmetry::antisymmetric, c1, c2).add(c3); }
inline symmetry sy_anti(const symmetry &c1, const symmetry &c2, const symmetry &c3, const symmetry &c4) { return symmetry(symmetry::antisymmetric, c1, c2).add(c3).add(c4); }
-inline symmetry sy_cycl(void) { symmetry s; s.set_type(symmetry::cyclic); return s; }
+inline symmetry sy_cycl() { symmetry s; s.set_type(symmetry::cyclic); return s; }
inline symmetry sy_cycl(const symmetry &c1, const symmetry &c2) { return symmetry(symmetry::cyclic, c1, c2); }
inline symmetry sy_cycl(const symmetry &c1, const symmetry &c2, const symmetry &c3) { return symmetry(symmetry::cyclic, c1, c2).add(c3); }
inline symmetry sy_cycl(const symmetry &c1, const symmetry &c2, const symmetry &c3, const symmetry &c4) { return symmetry(symmetry::cyclic, c1, c2).add(c3).add(c4); }
#include "indexed.h"
#include "symmetry.h"
#include "relational.h"
+#include "operators.h"
#include "lst.h"
#include "numeric.h"
#include "matrix.h"
GINAC_IMPLEMENT_REGISTERED_CLASS(tensepsilon, tensor)
//////////
-// default ctor, dtor, copy ctor, assignment operator and helpers
+// constructors
//////////
-DEFAULT_CTORS(tensor)
-DEFAULT_CTORS(tensdelta)
-DEFAULT_CTORS(tensmetric)
-DEFAULT_COPY(spinmetric)
-DEFAULT_DESTROY(spinmetric)
-DEFAULT_DESTROY(minkmetric)
-DEFAULT_DESTROY(tensepsilon)
+tensor::tensor() : inherited(TINFO_tensor)
+{
+ setflag(status_flags::evaluated | status_flags::expanded);
+}
+
+DEFAULT_CTOR(tensdelta)
+DEFAULT_CTOR(tensmetric)
minkmetric::minkmetric() : pos_sig(false)
{
tinfo_key = TINFO_minkmetric;
}
-void minkmetric::copy(const minkmetric & other)
-{
- inherited::copy(other);
- pos_sig = other.pos_sig;
-}
-
tensepsilon::tensepsilon() : minkowski(false), pos_sig(false)
{
tinfo_key = TINFO_tensepsilon;
tinfo_key = TINFO_tensepsilon;
}
-void tensepsilon::copy(const tensepsilon & other)
-{
- inherited::copy(other);
- minkowski = other.minkowski;
- pos_sig = other.pos_sig;
-}
-
//////////
// archiving
//////////
DEFAULT_UNARCHIVE(minkmetric)
DEFAULT_UNARCHIVE(tensepsilon)
-minkmetric::minkmetric(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
+minkmetric::minkmetric(const archive_node &n, lst &sym_lst) : inherited(n, sym_lst)
{
n.find_bool("pos_sig", pos_sig);
}
n.add_bool("pos_sig", pos_sig);
}
-tensepsilon::tensepsilon(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
+tensepsilon::tensepsilon(const archive_node &n, lst &sym_lst) : inherited(n, sym_lst)
{
n.find_bool("minkowski", minkowski);
n.find_bool("pos_sig", pos_sig);
// a canonic order but we can't assume what exactly that order is)
std::vector<int> v;
v.reserve(i.nops() - 1);
- for (unsigned j=1; j<i.nops(); j++)
+ for (size_t j=1; j<i.nops(); j++)
v.push_back(ex_to<numeric>(ex_to<idx>(i.op(j)).get_value()).to_int());
int sign = permutation_sign(v.begin(), v.end());
// In a Minkowski space, check for covariant indices
if (minkowski) {
- for (unsigned j=1; j<i.nops(); j++) {
+ for (size_t j=1; j<i.nops(); j++) {
const ex & x = i.op(j);
- if (!is_ex_of_type(x, varidx))
+ if (!is_a<varidx>(x))
throw(std::runtime_error("indices of epsilon tensor in Minkowski space must be of type varidx"));
if (ex_to<varidx>(x).is_covariant())
if (ex_to<idx>(x).get_value().is_zero())
again:
if (self_idx->is_symbolic()) {
- for (unsigned i=1; i<other->nops(); i++) {
+ for (size_t i=1; i<other->nops(); i++) {
const idx &other_idx = ex_to<idx>(other->op(i));
if (is_dummy_pair(*self_idx, other_idx)) {
// If contracting with the delta tensor, let the delta do it
// (don't raise/lower delta indices)
- if (is_ex_of_type(other->op(0), tensdelta))
+ if (is_a<tensdelta>(other->op(0)))
return false;
// Replace the dummy index with this tensor's other index and remove
- // the tensor (this is valid for contractions with all other tensors)
+ // the tensor
return replace_contr_index(self, other);
}
GINAC_ASSERT(is_a<spinmetric>(self->op(0)));
// Contractions between spinor metrics
- if (is_ex_of_type(other->op(0), spinmetric)) {
+ if (is_a<spinmetric>(other->op(0))) {
const idx &self_i1 = ex_to<idx>(self->op(1));
const idx &self_i2 = ex_to<idx>(self->op(2));
const idx &other_i1 = ex_to<idx>(other->op(1));
// If contracting with the delta tensor, let the delta do it
// (don't raise/lower delta indices)
- if (is_ex_of_type(other->op(0), tensdelta))
+ if (is_a<tensdelta>(other->op(0)))
return false;
// Try to contract first index
again:
if (self_idx->is_symbolic()) {
- for (unsigned i=1; i<other->nops(); i++) {
+ for (size_t i=1; i<other->nops(); i++) {
const idx &other_idx = ex_to<idx>(other->op(i));
if (is_dummy_pair(*self_idx, other_idx)) {
GINAC_ASSERT(is_a<indexed>(*self));
GINAC_ASSERT(is_a<indexed>(*other));
GINAC_ASSERT(is_a<tensepsilon>(self->op(0)));
- unsigned num = self->nops() - 1;
+ size_t num = self->nops() - 1;
- if (is_ex_exactly_of_type(other->op(0), tensepsilon) && num+1 == other->nops()) {
+ if (is_exactly_a<tensepsilon>(other->op(0)) && num+1 == other->nops()) {
// Contraction of two epsilon tensors is a determinant
bool variance = is_a<varidx>(self->op(1));
matrix M(num, num);
- for (unsigned i=0; i<num; i++) {
- for (unsigned j=0; j<num; j++) {
+ for (size_t i=0; i<num; i++) {
+ for (size_t j=0; j<num; j++) {
if (minkowski)
M(i, j) = lorentz_g(self->op(i+1), other->op(j+1), pos_sig);
else if (variance)
ex delta_tensor(const ex & i1, const ex & i2)
{
- if (!is_ex_of_type(i1, idx) || !is_ex_of_type(i2, idx))
+ if (!is_a<idx>(i1) || !is_a<idx>(i2))
throw(std::invalid_argument("indices of delta tensor must be of type idx"));
return indexed(tensdelta(), sy_symm(), i1, i2);
ex metric_tensor(const ex & i1, const ex & i2)
{
- if (!is_ex_of_type(i1, varidx) || !is_ex_of_type(i2, varidx))
+ if (!is_a<varidx>(i1) || !is_a<varidx>(i2))
throw(std::invalid_argument("indices of metric tensor must be of type varidx"));
return indexed(tensmetric(), sy_symm(), i1, i2);
ex lorentz_g(const ex & i1, const ex & i2, bool pos_sig)
{
- if (!is_ex_of_type(i1, varidx) || !is_ex_of_type(i2, varidx))
+ if (!is_a<varidx>(i1) || !is_a<varidx>(i2))
throw(std::invalid_argument("indices of metric tensor must be of type varidx"));
return indexed(minkmetric(pos_sig), sy_symm(), i1, i2);
ex spinor_metric(const ex & i1, const ex & i2)
{
- if (!is_ex_of_type(i1, spinidx) || !is_ex_of_type(i2, spinidx))
+ if (!is_a<spinidx>(i1) || !is_a<spinidx>(i2))
throw(std::invalid_argument("indices of spinor metric must be of type spinidx"));
if (!ex_to<idx>(i1).get_dim().is_equal(2) || !ex_to<idx>(i2).get_dim().is_equal(2))
throw(std::runtime_error("index dimension for spinor metric must be 2"));
ex epsilon_tensor(const ex & i1, const ex & i2)
{
- if (!is_ex_of_type(i1, idx) || !is_ex_of_type(i2, idx))
+ if (!is_a<idx>(i1) || !is_a<idx>(i2))
throw(std::invalid_argument("indices of epsilon tensor must be of type idx"));
ex dim = ex_to<idx>(i1).get_dim();
ex epsilon_tensor(const ex & i1, const ex & i2, const ex & i3)
{
- if (!is_ex_of_type(i1, idx) || !is_ex_of_type(i2, idx) || !is_ex_of_type(i3, idx))
+ if (!is_a<idx>(i1) || !is_a<idx>(i2) || !is_a<idx>(i3))
throw(std::invalid_argument("indices of epsilon tensor must be of type idx"));
ex dim = ex_to<idx>(i1).get_dim();
ex lorentz_eps(const ex & i1, const ex & i2, const ex & i3, const ex & i4, bool pos_sig)
{
- if (!is_ex_of_type(i1, varidx) || !is_ex_of_type(i2, varidx) || !is_ex_of_type(i3, varidx) || !is_ex_of_type(i4, varidx))
+ if (!is_a<varidx>(i1) || !is_a<varidx>(i2) || !is_a<varidx>(i3) || !is_a<varidx>(i4))
throw(std::invalid_argument("indices of Lorentz epsilon tensor must be of type varidx"));
ex dim = ex_to<idx>(i1).get_dim();
// functions overriding virtual functions from base classes
protected:
- unsigned return_type(void) const { return return_types::noncommutative_composite; }
+ unsigned return_type() const { return return_types::noncommutative_composite; }
// non-virtual functions in this class
public:
// member variables
private:
bool minkowski; /**< If true, tensor is in Minkowski-type space. Otherwise it is in a Euclidean space. */
- bool pos_sig; /**< If true, the metric is assumed to be diag(-1,1,1...). Otherwise it is diag(1,-1,-1,...). This is only relevant if minkowski = true. */
+ bool pos_sig; /**< If true, the metric is assumed to be diag(-1,1,1...). Otherwise it is diag(1,-1,-1,...). This is only relevant if minkowski = true. */
};
: domain_error(what_arg), deg(degree) { }
/** Return the degree of the pole_error exception class. */
-int pole_error::degree(void) const
+int pole_error::degree() const
{
return deg;
}
// static numeric 0
const numeric *_num0_p;
+const basic *_num0_bp;
const numeric &_num0 = *_num0_p;
const ex _ex0 = _num0;
_num_1_3_p= reinterpret_cast<const numeric*>(&((new numeric(-1,3))->setflag(status_flags::dynallocated)));
_num_1_4_p= reinterpret_cast<const numeric*>(&((new numeric(-1,4))->setflag(status_flags::dynallocated)));
_num0_p = reinterpret_cast<const numeric*>(&((new numeric(0))->setflag(status_flags::dynallocated)));
+ _num0_bp = _num0_p;
_num1_4_p = reinterpret_cast<const numeric*>(&((new numeric(1,4))->setflag(status_flags::dynallocated)));
_num1_3_p = reinterpret_cast<const numeric*>(&((new numeric(1,3))->setflag(status_flags::dynallocated)));
_num1_2_p = reinterpret_cast<const numeric*>(&((new numeric(1,2))->setflag(status_flags::dynallocated)));
// member functions
- // default ctor, dtor, copy ctor, assignment operator and helpers
+ // default constructor, destructor, copy constructor and assignment operator
// none
- // other ctors
+ // other constructors
// none
// functions overriding virtual functions from base classes
//////////
-// default ctor, dtor, copy ctor, assignment operator and helpers
+// default constructor, destructor, copy constructor and assignment operator
//////////
// public
// protected
//////////
-// other ctors
+// other constructors
//////////
// public
#include "config.h"
#include <string>
-#include <stdexcept>
+#include <functional>
+
#include "assertion.h"
namespace GiNaC {
-/** Exception class thrown by classes which provide their own series expansion
- * to signal that ordinary Taylor expansion is safe. */
-class do_taylor {};
-
/** Exception class thrown by functions to signal unimplemented functionality
* so the expression may just be .hold() */
class dunno {};
-/** Exception class thrown when a singularity is encountered. */
-class pole_error : public std::domain_error {
-public:
- explicit pole_error(const std::string& what_arg, int degree);
- int degree(void) const;
-private:
- int deg;
-};
-
// some compilers (e.g. cygwin) define a macro log2, causing confusion
#ifndef log2
unsigned log2(unsigned n);
/** Compare two pointers (just to establish some sort of canonical order).
* @return -1, 0, or 1 */
-inline int compare_pointers(const void * a, const void * b)
+template <class T>
+inline int compare_pointers(const T * a, const T * b)
{
- if (a<b)
+ // '<' is not defined for pointers that don't point to the same array,
+ // but std::less is.
+ if (std::less<const T *>()(a, b))
return -1;
- else if (a>b)
+ else if (std::less<const T *>()(b, a))
return 1;
return 0;
}
-/** Rotate lower 31 bits of unsigned value by one bit to the left
- * (upper bit gets cleared). */
-inline unsigned rotate_left_31(unsigned n)
+/** Rotate bits of unsigned value by one bit to the left. */
+inline unsigned rotate_left(unsigned n)
{
- // clear highest bit and shift 1 bit to the left
- n = (n & 0x7FFFFFFFU) << 1;
-
- // overflow? clear highest bit and set lowest bit
- if (n & 0x80000000U)
- n = (n & 0x7FFFFFFFU) | 0x00000001U;
-
- GINAC_ASSERT(n<0x80000000U);
-
- return n;
+ return (n & 0x80000000U) ? (n << 1 | 0x00000001U) : (n << 1);
}
-/** Golden ratio hash function for the 31 least significant bits. */
+/** Truncated multiplication with golden ratio, for computing hash values. */
inline unsigned golden_ratio_hash(unsigned n)
{
- // This function requires arithmetic with at least 64 significant bits
+ // This function works much better when fast arithmetic with at
+ // least 64 significant bits is available.
#if SIZEOF_LONG >= 8
// So 'long' has 64 bits. Excellent! We prefer it because it might be
// more efficient than 'long long'.
- unsigned long l = n * 0x4f1bbcddL;
- return (l & 0x7fffffffU) ^ (l >> 32);
+ unsigned long l = n * 0x4f1bbcddUL;
+ return (unsigned)l;
#elif SIZEOF_LONG_LONG >= 8
// This requires 'long long' (or an equivalent 64 bit type)---which is,
// unfortunately, not ANSI-C++-compliant.
// (Yet C99 demands it, which is reason for hope.)
- unsigned long long l = n * 0x4f1bbcddL;
- return (l & 0x7fffffffU) ^ (l >> 32);
-#elif SIZEOF_LONG_DOUBLE > 8
- // If 'long double' is bigger than 64 bits, we assume that the mantissa
- // has at least 64 bits. This is not guaranteed but it's a good guess.
- // Unfortunately, it may lead to horribly slow code.
- const static long double golden_ratio = .618033988749894848204586834370;
- long double m = golden_ratio * n;
- return unsigned((m - int(m)) * 0x80000000);
+ unsigned long long l = n * 0x4f1bbcddULL;
+ return (unsigned)l;
#else
-#error "No 64 bit data type. You lose."
+ // Without a type with 64 significant bits do the multiplication manually
+ // by splitting n up into the lower and upper two bytes.
+ const unsigned n0 = (n & 0x0000ffffU);
+ const unsigned n1 = (n & 0xffff0000U) >> 16;
+ return (n0 * 0x0000bcddU) + ((n1 * 0x0000bcddU + n0 * 0x00004f1bU) << 16);
#endif
}
// the library but should not be used outside it since it is
// potentially confusing.
-class numeric;
class ex;
extern const numeric *_num_120_p;
extern const numeric &_num_1_4;
extern const ex _ex_1_4;
extern const numeric *_num0_p;
+extern const basic *_num0_bp;
extern const numeric &_num0;
extern const ex _ex0;
extern const numeric *_num1_4_p;
// Helper macros for class implementations (mostly useful for trivial classes)
-#define DEFAULT_COPY(classname) \
-void classname::copy(const classname & other) \
-{ \
- inherited::copy(other); \
-}
-
-#define DEFAULT_DESTROY(classname) \
-void classname::destroy(bool call_parent) \
-{ \
- if (call_parent) \
- inherited::destroy(call_parent); \
-}
-
-#define DEFAULT_CTORS(classname) \
-classname::classname() : inherited(TINFO_##classname) {} \
-DEFAULT_COPY(classname) \
-DEFAULT_DESTROY(classname)
+#define DEFAULT_CTOR(classname) \
+classname::classname() : inherited(TINFO_##classname) {}
#define DEFAULT_UNARCHIVE(classname) \
-ex classname::unarchive(const archive_node &n, const lst &sym_lst) \
+ex classname::unarchive(const archive_node &n, lst &sym_lst) \
{ \
return (new classname(n, sym_lst))->setflag(status_flags::dynallocated); \
}
#define DEFAULT_ARCHIVING(classname) \
-classname::classname(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst) {} \
+classname::classname(const archive_node &n, lst &sym_lst) : inherited(n, sym_lst) {} \
DEFAULT_UNARCHIVE(classname) \
void classname::archive(archive_node &n) const \
{ \
c.s << text; \
}
-// Obsolete convenience macros. TO BE PHASED OUT SOON!
-// Use the inlined template functions in basic.h instead. (FIXME: remove them)
-
-#define is_of_type(OBJ,TYPE) \
- (dynamic_cast<const TYPE *>(&OBJ)!=0)
-
-#define is_exactly_of_type(OBJ,TYPE) \
- ((OBJ).tinfo()==GiNaC::TINFO_##TYPE)
-
-#define is_ex_of_type(OBJ,TYPE) \
- (dynamic_cast<const TYPE *>((OBJ).bp)!=0)
-
-#define is_ex_exactly_of_type(OBJ,TYPE) \
- ((*(OBJ).bp).tinfo()==GiNaC::TINFO_##TYPE)
-
} // namespace GiNaC
GINAC_IMPLEMENT_REGISTERED_CLASS(wildcard, basic)
//////////
-// default ctor, dtor, copy ctor, assignment operator and helpers
+// default constructor
//////////
-wildcard::wildcard() : label(0)
+wildcard::wildcard() : inherited(TINFO_wildcard), label(0)
{
- tinfo_key = TINFO_wildcard;
+ setflag(status_flags::evaluated | status_flags::expanded);
}
-void wildcard::copy(const wildcard & other)
-{
- inherited::copy(other);
- label = other.label;
-}
-
-DEFAULT_DESTROY(wildcard)
-
//////////
// other constructors
//////////
-wildcard::wildcard(unsigned l) : label(l)
+wildcard::wildcard(unsigned l) : inherited(TINFO_wildcard), label(l)
{
- tinfo_key = TINFO_wildcard;
+ setflag(status_flags::evaluated | status_flags::expanded);
}
//////////
// archiving
//////////
-wildcard::wildcard(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
+wildcard::wildcard(const archive_node &n, lst &sym_lst) : inherited(n, sym_lst)
{
n.find_unsigned("label", label);
+ setflag(status_flags::evaluated | status_flags::expanded);
}
void wildcard::archive(archive_node &n) const
c.s << "$" << label;
}
-unsigned wildcard::calchash(void) const
+unsigned wildcard::calchash() const
{
// this is where the schoolbook method
// (golden_ratio_hash(tinfo()) ^ label)
bool match(const ex & pattern, lst & repl_lst) const;
protected:
- unsigned calchash(void) const;
+ unsigned calchash() const;
// non-virtual functions in this class
public:
- unsigned get_label(void) const {return label;}
+ unsigned get_label() const {return label;}
// member variables
private:
">=" return T_GREATEREQ;
/* last 1..3 expressions */
-\" return T_QUOTE;
-\"\" return T_QUOTE2;
-\"\"\" return T_QUOTE3;
\% return T_QUOTE;
\%\% return T_QUOTE2;
\%\%\% return T_QUOTE3;
static const char *orig_basic_word_break_characters;
#endif
-// Expression stack for ", "" and """
+// Expression stack for %, %% and %%%
static void push(const ex &e);
static ex exstack[3];
static ex f_diag(const exprseq &e)
{
- unsigned dim = e.nops();
+ size_t dim = e.nops();
matrix &m = *new matrix(dim, dim);
- for (unsigned i=0; i<dim; i++)
+ for (size_t i=0; i<dim; i++)
m.set(i, i, e.op(i));
return m;
}